1ffe3c632Sopenharmony_ci#region Copyright notice and license
2ffe3c632Sopenharmony_ci// Protocol Buffers - Google's data interchange format
3ffe3c632Sopenharmony_ci// Copyright 2019 Google Inc.  All rights reserved.
4ffe3c632Sopenharmony_ci// https://github.com/protocolbuffers/protobuf
5ffe3c632Sopenharmony_ci//
6ffe3c632Sopenharmony_ci// Redistribution and use in source and binary forms, with or without
7ffe3c632Sopenharmony_ci// modification, are permitted provided that the following conditions are
8ffe3c632Sopenharmony_ci// met:
9ffe3c632Sopenharmony_ci//
10ffe3c632Sopenharmony_ci//     * Redistributions of source code must retain the above copyright
11ffe3c632Sopenharmony_ci// notice, this list of conditions and the following disclaimer.
12ffe3c632Sopenharmony_ci//     * Redistributions in binary form must reproduce the above
13ffe3c632Sopenharmony_ci// copyright notice, this list of conditions and the following disclaimer
14ffe3c632Sopenharmony_ci// in the documentation and/or other materials provided with the
15ffe3c632Sopenharmony_ci// distribution.
16ffe3c632Sopenharmony_ci//     * Neither the name of Google Inc. nor the names of its
17ffe3c632Sopenharmony_ci// contributors may be used to endorse or promote products derived from
18ffe3c632Sopenharmony_ci// this software without specific prior written permission.
19ffe3c632Sopenharmony_ci//
20ffe3c632Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21ffe3c632Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22ffe3c632Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23ffe3c632Sopenharmony_ci// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24ffe3c632Sopenharmony_ci// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25ffe3c632Sopenharmony_ci// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26ffe3c632Sopenharmony_ci// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27ffe3c632Sopenharmony_ci// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28ffe3c632Sopenharmony_ci// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29ffe3c632Sopenharmony_ci// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30ffe3c632Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31ffe3c632Sopenharmony_ci#endregion
32ffe3c632Sopenharmony_ci
33ffe3c632Sopenharmony_ciusing BenchmarkDotNet.Attributes;
34ffe3c632Sopenharmony_ciusing System;
35ffe3c632Sopenharmony_ciusing System.Buffers.Binary;
36ffe3c632Sopenharmony_ciusing System.Collections.Generic;
37ffe3c632Sopenharmony_ciusing System.IO;
38ffe3c632Sopenharmony_ciusing System.Buffers;
39ffe3c632Sopenharmony_ci
40ffe3c632Sopenharmony_cinamespace Google.Protobuf.Benchmarks
41ffe3c632Sopenharmony_ci{
42ffe3c632Sopenharmony_ci    /// <summary>
43ffe3c632Sopenharmony_ci    /// Benchmarks throughput when parsing raw primitives.
44ffe3c632Sopenharmony_ci    /// </summary>
45ffe3c632Sopenharmony_ci    [MemoryDiagnoser]
46ffe3c632Sopenharmony_ci    public class ParseRawPrimitivesBenchmark
47ffe3c632Sopenharmony_ci    {
48ffe3c632Sopenharmony_ci        // key is the encodedSize of varint values
49ffe3c632Sopenharmony_ci        Dictionary<int, byte[]> varintInputBuffers;
50ffe3c632Sopenharmony_ci
51ffe3c632Sopenharmony_ci        byte[] doubleInputBuffer;
52ffe3c632Sopenharmony_ci        byte[] floatInputBuffer;
53ffe3c632Sopenharmony_ci        byte[] fixedIntInputBuffer;
54ffe3c632Sopenharmony_ci
55ffe3c632Sopenharmony_ci        // key is the encodedSize of string values
56ffe3c632Sopenharmony_ci        Dictionary<int, byte[]> stringInputBuffers;
57ffe3c632Sopenharmony_ci        Dictionary<int, ReadOnlySequence<byte>> stringInputBuffersSegmented;
58ffe3c632Sopenharmony_ci
59ffe3c632Sopenharmony_ci        Random random = new Random(417384220);  // random but deterministic seed
60ffe3c632Sopenharmony_ci
61ffe3c632Sopenharmony_ci        public IEnumerable<int> StringEncodedSizes => new[] { 1, 4, 10, 105, 10080 };
62ffe3c632Sopenharmony_ci        public IEnumerable<int> StringSegmentedEncodedSizes => new[] { 105, 10080 };
63ffe3c632Sopenharmony_ci
64ffe3c632Sopenharmony_ci        [GlobalSetup]
65ffe3c632Sopenharmony_ci        public void GlobalSetup()
66ffe3c632Sopenharmony_ci        {
67ffe3c632Sopenharmony_ci            // add some extra values that we won't read just to make sure we are far enough from the end of the buffer
68ffe3c632Sopenharmony_ci            // which allows the parser fastpath to always kick in.
69ffe3c632Sopenharmony_ci            const int paddingValueCount = 100;
70ffe3c632Sopenharmony_ci
71ffe3c632Sopenharmony_ci            varintInputBuffers = new Dictionary<int, byte[]>();
72ffe3c632Sopenharmony_ci            for (int encodedSize = 1; encodedSize <= 10; encodedSize++)
73ffe3c632Sopenharmony_ci            {
74ffe3c632Sopenharmony_ci                byte[] buffer = CreateBufferWithRandomVarints(random, BytesToParse / encodedSize, encodedSize, paddingValueCount);
75ffe3c632Sopenharmony_ci                varintInputBuffers.Add(encodedSize, buffer);
76ffe3c632Sopenharmony_ci            }
77ffe3c632Sopenharmony_ci
78ffe3c632Sopenharmony_ci            doubleInputBuffer = CreateBufferWithRandomDoubles(random, BytesToParse / sizeof(double), paddingValueCount);
79ffe3c632Sopenharmony_ci            floatInputBuffer = CreateBufferWithRandomFloats(random, BytesToParse / sizeof(float), paddingValueCount);
80ffe3c632Sopenharmony_ci            fixedIntInputBuffer = CreateBufferWithRandomData(random, BytesToParse / sizeof(long), sizeof(long), paddingValueCount);
81ffe3c632Sopenharmony_ci
82ffe3c632Sopenharmony_ci            stringInputBuffers = new Dictionary<int, byte[]>();
83ffe3c632Sopenharmony_ci            foreach (var encodedSize in StringEncodedSizes)
84ffe3c632Sopenharmony_ci            {
85ffe3c632Sopenharmony_ci                byte[] buffer = CreateBufferWithStrings(BytesToParse / encodedSize, encodedSize, encodedSize < 10 ? 10 : 1 );
86ffe3c632Sopenharmony_ci                stringInputBuffers.Add(encodedSize, buffer);
87ffe3c632Sopenharmony_ci            }
88ffe3c632Sopenharmony_ci
89ffe3c632Sopenharmony_ci            stringInputBuffersSegmented = new Dictionary<int, ReadOnlySequence<byte>>();
90ffe3c632Sopenharmony_ci            foreach (var encodedSize in StringSegmentedEncodedSizes)
91ffe3c632Sopenharmony_ci            {
92ffe3c632Sopenharmony_ci                byte[] buffer = CreateBufferWithStrings(BytesToParse / encodedSize, encodedSize, encodedSize < 10 ? 10 : 1);
93ffe3c632Sopenharmony_ci                stringInputBuffersSegmented.Add(encodedSize, ReadOnlySequenceFactory.CreateWithContent(buffer, segmentSize: 128, addEmptySegmentDelimiters: false));
94ffe3c632Sopenharmony_ci            }
95ffe3c632Sopenharmony_ci        }
96ffe3c632Sopenharmony_ci
97ffe3c632Sopenharmony_ci        // Total number of bytes that each benchmark will parse.
98ffe3c632Sopenharmony_ci        // Measuring the time taken to parse buffer of given size makes it easier to compare parsing speed for different
99ffe3c632Sopenharmony_ci        // types and makes it easy to calculate the througput (in MB/s)
100ffe3c632Sopenharmony_ci        // 10800 bytes is chosen because it is divisible by all possible encoded sizes for all primitive types {1..10}
101ffe3c632Sopenharmony_ci        [Params(10080)]
102ffe3c632Sopenharmony_ci        public int BytesToParse { get; set; }
103ffe3c632Sopenharmony_ci
104ffe3c632Sopenharmony_ci        [Benchmark]
105ffe3c632Sopenharmony_ci        [Arguments(1)]
106ffe3c632Sopenharmony_ci        [Arguments(2)]
107ffe3c632Sopenharmony_ci        [Arguments(3)]
108ffe3c632Sopenharmony_ci        [Arguments(4)]
109ffe3c632Sopenharmony_ci        [Arguments(5)]
110ffe3c632Sopenharmony_ci        public int ParseRawVarint32_CodedInputStream(int encodedSize)
111ffe3c632Sopenharmony_ci        {
112ffe3c632Sopenharmony_ci            CodedInputStream cis = new CodedInputStream(varintInputBuffers[encodedSize]);
113ffe3c632Sopenharmony_ci            int sum = 0;
114ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
115ffe3c632Sopenharmony_ci            {
116ffe3c632Sopenharmony_ci                sum += cis.ReadInt32();
117ffe3c632Sopenharmony_ci            }
118ffe3c632Sopenharmony_ci            return sum;
119ffe3c632Sopenharmony_ci        }
120ffe3c632Sopenharmony_ci
121ffe3c632Sopenharmony_ci        [Benchmark]
122ffe3c632Sopenharmony_ci        [Arguments(1)]
123ffe3c632Sopenharmony_ci        [Arguments(2)]
124ffe3c632Sopenharmony_ci        [Arguments(3)]
125ffe3c632Sopenharmony_ci        [Arguments(4)]
126ffe3c632Sopenharmony_ci        [Arguments(5)]
127ffe3c632Sopenharmony_ci        public int ParseRawVarint32_ParseContext(int encodedSize)
128ffe3c632Sopenharmony_ci        {
129ffe3c632Sopenharmony_ci            InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx);
130ffe3c632Sopenharmony_ci            int sum = 0;
131ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
132ffe3c632Sopenharmony_ci            {
133ffe3c632Sopenharmony_ci                sum += ctx.ReadInt32();
134ffe3c632Sopenharmony_ci            }
135ffe3c632Sopenharmony_ci            return sum;
136ffe3c632Sopenharmony_ci        }
137ffe3c632Sopenharmony_ci
138ffe3c632Sopenharmony_ci        [Benchmark]
139ffe3c632Sopenharmony_ci        [Arguments(1)]
140ffe3c632Sopenharmony_ci        [Arguments(2)]
141ffe3c632Sopenharmony_ci        [Arguments(3)]
142ffe3c632Sopenharmony_ci        [Arguments(4)]
143ffe3c632Sopenharmony_ci        [Arguments(5)]
144ffe3c632Sopenharmony_ci        [Arguments(6)]
145ffe3c632Sopenharmony_ci        [Arguments(7)]
146ffe3c632Sopenharmony_ci        [Arguments(8)]
147ffe3c632Sopenharmony_ci        [Arguments(9)]
148ffe3c632Sopenharmony_ci        [Arguments(10)]
149ffe3c632Sopenharmony_ci        public long ParseRawVarint64_CodedInputStream(int encodedSize)
150ffe3c632Sopenharmony_ci        {
151ffe3c632Sopenharmony_ci            CodedInputStream cis = new CodedInputStream(varintInputBuffers[encodedSize]);
152ffe3c632Sopenharmony_ci            long sum = 0;
153ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
154ffe3c632Sopenharmony_ci            {
155ffe3c632Sopenharmony_ci                sum += cis.ReadInt64();
156ffe3c632Sopenharmony_ci            }
157ffe3c632Sopenharmony_ci            return sum;
158ffe3c632Sopenharmony_ci        }
159ffe3c632Sopenharmony_ci
160ffe3c632Sopenharmony_ci        [Benchmark]
161ffe3c632Sopenharmony_ci        [Arguments(1)]
162ffe3c632Sopenharmony_ci        [Arguments(2)]
163ffe3c632Sopenharmony_ci        [Arguments(3)]
164ffe3c632Sopenharmony_ci        [Arguments(4)]
165ffe3c632Sopenharmony_ci        [Arguments(5)]
166ffe3c632Sopenharmony_ci        [Arguments(6)]
167ffe3c632Sopenharmony_ci        [Arguments(7)]
168ffe3c632Sopenharmony_ci        [Arguments(8)]
169ffe3c632Sopenharmony_ci        [Arguments(9)]
170ffe3c632Sopenharmony_ci        [Arguments(10)]
171ffe3c632Sopenharmony_ci        public long ParseRawVarint64_ParseContext(int encodedSize)
172ffe3c632Sopenharmony_ci        {
173ffe3c632Sopenharmony_ci            InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx);
174ffe3c632Sopenharmony_ci            long sum = 0;
175ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
176ffe3c632Sopenharmony_ci            {
177ffe3c632Sopenharmony_ci                sum += ctx.ReadInt64();
178ffe3c632Sopenharmony_ci            }
179ffe3c632Sopenharmony_ci            return sum;
180ffe3c632Sopenharmony_ci        }
181ffe3c632Sopenharmony_ci
182ffe3c632Sopenharmony_ci        [Benchmark]
183ffe3c632Sopenharmony_ci        public uint ParseFixed32_CodedInputStream()
184ffe3c632Sopenharmony_ci        {
185ffe3c632Sopenharmony_ci            const int encodedSize = sizeof(uint);
186ffe3c632Sopenharmony_ci            CodedInputStream cis = new CodedInputStream(fixedIntInputBuffer);
187ffe3c632Sopenharmony_ci            uint sum = 0;
188ffe3c632Sopenharmony_ci            for (uint i = 0; i < BytesToParse / encodedSize; i++)
189ffe3c632Sopenharmony_ci            {
190ffe3c632Sopenharmony_ci                sum += cis.ReadFixed32();
191ffe3c632Sopenharmony_ci            }
192ffe3c632Sopenharmony_ci            return sum;
193ffe3c632Sopenharmony_ci        }
194ffe3c632Sopenharmony_ci
195ffe3c632Sopenharmony_ci        [Benchmark]
196ffe3c632Sopenharmony_ci        public uint ParseFixed32_ParseContext()
197ffe3c632Sopenharmony_ci        {
198ffe3c632Sopenharmony_ci            const int encodedSize = sizeof(uint);
199ffe3c632Sopenharmony_ci            InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx);
200ffe3c632Sopenharmony_ci            uint sum = 0;
201ffe3c632Sopenharmony_ci            for (uint i = 0; i < BytesToParse / encodedSize; i++)
202ffe3c632Sopenharmony_ci            {
203ffe3c632Sopenharmony_ci                sum += ctx.ReadFixed32();
204ffe3c632Sopenharmony_ci            }
205ffe3c632Sopenharmony_ci            return sum;
206ffe3c632Sopenharmony_ci        }
207ffe3c632Sopenharmony_ci
208ffe3c632Sopenharmony_ci        [Benchmark]
209ffe3c632Sopenharmony_ci        public ulong ParseFixed64_CodedInputStream()
210ffe3c632Sopenharmony_ci        {
211ffe3c632Sopenharmony_ci            const int encodedSize = sizeof(ulong);
212ffe3c632Sopenharmony_ci            CodedInputStream cis = new CodedInputStream(fixedIntInputBuffer);
213ffe3c632Sopenharmony_ci            ulong sum = 0;
214ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
215ffe3c632Sopenharmony_ci            {
216ffe3c632Sopenharmony_ci                sum += cis.ReadFixed64();
217ffe3c632Sopenharmony_ci            }
218ffe3c632Sopenharmony_ci            return sum;
219ffe3c632Sopenharmony_ci        }
220ffe3c632Sopenharmony_ci
221ffe3c632Sopenharmony_ci        [Benchmark]
222ffe3c632Sopenharmony_ci        public ulong ParseFixed64_ParseContext()
223ffe3c632Sopenharmony_ci        {
224ffe3c632Sopenharmony_ci            const int encodedSize = sizeof(ulong);
225ffe3c632Sopenharmony_ci            InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx);
226ffe3c632Sopenharmony_ci            ulong sum = 0;
227ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
228ffe3c632Sopenharmony_ci            {
229ffe3c632Sopenharmony_ci                sum += ctx.ReadFixed64();
230ffe3c632Sopenharmony_ci            }
231ffe3c632Sopenharmony_ci            return sum;
232ffe3c632Sopenharmony_ci        }
233ffe3c632Sopenharmony_ci
234ffe3c632Sopenharmony_ci        [Benchmark]
235ffe3c632Sopenharmony_ci        public float ParseRawFloat_CodedInputStream()
236ffe3c632Sopenharmony_ci        {
237ffe3c632Sopenharmony_ci            const int encodedSize = sizeof(float);
238ffe3c632Sopenharmony_ci            CodedInputStream cis = new CodedInputStream(floatInputBuffer);
239ffe3c632Sopenharmony_ci            float sum = 0;
240ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
241ffe3c632Sopenharmony_ci            {
242ffe3c632Sopenharmony_ci               sum += cis.ReadFloat();
243ffe3c632Sopenharmony_ci            }
244ffe3c632Sopenharmony_ci            return sum;
245ffe3c632Sopenharmony_ci        }
246ffe3c632Sopenharmony_ci
247ffe3c632Sopenharmony_ci        [Benchmark]
248ffe3c632Sopenharmony_ci        public float ParseRawFloat_ParseContext()
249ffe3c632Sopenharmony_ci        {
250ffe3c632Sopenharmony_ci            const int encodedSize = sizeof(float);
251ffe3c632Sopenharmony_ci            InitializeParseContext(floatInputBuffer, out ParseContext ctx);
252ffe3c632Sopenharmony_ci            float sum = 0;
253ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
254ffe3c632Sopenharmony_ci            {
255ffe3c632Sopenharmony_ci               sum += ctx.ReadFloat();
256ffe3c632Sopenharmony_ci            }
257ffe3c632Sopenharmony_ci            return sum;
258ffe3c632Sopenharmony_ci        }
259ffe3c632Sopenharmony_ci
260ffe3c632Sopenharmony_ci        [Benchmark]
261ffe3c632Sopenharmony_ci        public double ParseRawDouble_CodedInputStream()
262ffe3c632Sopenharmony_ci        {
263ffe3c632Sopenharmony_ci            const int encodedSize = sizeof(double);
264ffe3c632Sopenharmony_ci            CodedInputStream cis = new CodedInputStream(doubleInputBuffer);
265ffe3c632Sopenharmony_ci            double sum = 0;
266ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
267ffe3c632Sopenharmony_ci            {
268ffe3c632Sopenharmony_ci                sum += cis.ReadDouble();
269ffe3c632Sopenharmony_ci            }
270ffe3c632Sopenharmony_ci            return sum;
271ffe3c632Sopenharmony_ci        }
272ffe3c632Sopenharmony_ci
273ffe3c632Sopenharmony_ci        [Benchmark]
274ffe3c632Sopenharmony_ci        public double ParseRawDouble_ParseContext()
275ffe3c632Sopenharmony_ci        {
276ffe3c632Sopenharmony_ci            const int encodedSize = sizeof(double);
277ffe3c632Sopenharmony_ci            InitializeParseContext(doubleInputBuffer, out ParseContext ctx);
278ffe3c632Sopenharmony_ci            double sum = 0;
279ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
280ffe3c632Sopenharmony_ci            {
281ffe3c632Sopenharmony_ci                sum += ctx.ReadDouble();
282ffe3c632Sopenharmony_ci            }
283ffe3c632Sopenharmony_ci            return sum;
284ffe3c632Sopenharmony_ci        }
285ffe3c632Sopenharmony_ci
286ffe3c632Sopenharmony_ci        [Benchmark]
287ffe3c632Sopenharmony_ci        [ArgumentsSource(nameof(StringEncodedSizes))]
288ffe3c632Sopenharmony_ci        public int ParseString_CodedInputStream(int encodedSize)
289ffe3c632Sopenharmony_ci        {
290ffe3c632Sopenharmony_ci            CodedInputStream cis = new CodedInputStream(stringInputBuffers[encodedSize]);
291ffe3c632Sopenharmony_ci            int sum = 0;
292ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
293ffe3c632Sopenharmony_ci            {
294ffe3c632Sopenharmony_ci                sum += cis.ReadString().Length;
295ffe3c632Sopenharmony_ci            }
296ffe3c632Sopenharmony_ci            return sum;
297ffe3c632Sopenharmony_ci        }
298ffe3c632Sopenharmony_ci
299ffe3c632Sopenharmony_ci        [Benchmark]
300ffe3c632Sopenharmony_ci        [ArgumentsSource(nameof(StringEncodedSizes))]
301ffe3c632Sopenharmony_ci        public int ParseString_ParseContext(int encodedSize)
302ffe3c632Sopenharmony_ci        {
303ffe3c632Sopenharmony_ci            InitializeParseContext(stringInputBuffers[encodedSize], out ParseContext ctx);
304ffe3c632Sopenharmony_ci            int sum = 0;
305ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
306ffe3c632Sopenharmony_ci            {
307ffe3c632Sopenharmony_ci                sum += ctx.ReadString().Length;
308ffe3c632Sopenharmony_ci            }
309ffe3c632Sopenharmony_ci            return sum;
310ffe3c632Sopenharmony_ci        }
311ffe3c632Sopenharmony_ci
312ffe3c632Sopenharmony_ci        [Benchmark]
313ffe3c632Sopenharmony_ci        [ArgumentsSource(nameof(StringSegmentedEncodedSizes))]
314ffe3c632Sopenharmony_ci        public int ParseString_ParseContext_MultipleSegments(int encodedSize)
315ffe3c632Sopenharmony_ci        {
316ffe3c632Sopenharmony_ci            InitializeParseContext(stringInputBuffersSegmented[encodedSize], out ParseContext ctx);
317ffe3c632Sopenharmony_ci            int sum = 0;
318ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
319ffe3c632Sopenharmony_ci            {
320ffe3c632Sopenharmony_ci                sum += ctx.ReadString().Length;
321ffe3c632Sopenharmony_ci            }
322ffe3c632Sopenharmony_ci            return sum;
323ffe3c632Sopenharmony_ci        }
324ffe3c632Sopenharmony_ci
325ffe3c632Sopenharmony_ci        [Benchmark]
326ffe3c632Sopenharmony_ci        [ArgumentsSource(nameof(StringEncodedSizes))]
327ffe3c632Sopenharmony_ci        public int ParseBytes_CodedInputStream(int encodedSize)
328ffe3c632Sopenharmony_ci        {
329ffe3c632Sopenharmony_ci            CodedInputStream cis = new CodedInputStream(stringInputBuffers[encodedSize]);
330ffe3c632Sopenharmony_ci            int sum = 0;
331ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
332ffe3c632Sopenharmony_ci            {
333ffe3c632Sopenharmony_ci                sum += cis.ReadBytes().Length;
334ffe3c632Sopenharmony_ci            }
335ffe3c632Sopenharmony_ci            return sum;
336ffe3c632Sopenharmony_ci        }
337ffe3c632Sopenharmony_ci
338ffe3c632Sopenharmony_ci        [Benchmark]
339ffe3c632Sopenharmony_ci        [ArgumentsSource(nameof(StringEncodedSizes))]
340ffe3c632Sopenharmony_ci        public int ParseBytes_ParseContext(int encodedSize)
341ffe3c632Sopenharmony_ci        {
342ffe3c632Sopenharmony_ci            InitializeParseContext(stringInputBuffers[encodedSize], out ParseContext ctx);
343ffe3c632Sopenharmony_ci            int sum = 0;
344ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
345ffe3c632Sopenharmony_ci            {
346ffe3c632Sopenharmony_ci                sum += ctx.ReadBytes().Length;
347ffe3c632Sopenharmony_ci            }
348ffe3c632Sopenharmony_ci            return sum;
349ffe3c632Sopenharmony_ci        }
350ffe3c632Sopenharmony_ci
351ffe3c632Sopenharmony_ci        [Benchmark]
352ffe3c632Sopenharmony_ci        [ArgumentsSource(nameof(StringSegmentedEncodedSizes))]
353ffe3c632Sopenharmony_ci        public int ParseBytes_ParseContext_MultipleSegments(int encodedSize)
354ffe3c632Sopenharmony_ci        {
355ffe3c632Sopenharmony_ci            InitializeParseContext(stringInputBuffersSegmented[encodedSize], out ParseContext ctx);
356ffe3c632Sopenharmony_ci            int sum = 0;
357ffe3c632Sopenharmony_ci            for (int i = 0; i < BytesToParse / encodedSize; i++)
358ffe3c632Sopenharmony_ci            {
359ffe3c632Sopenharmony_ci                sum += ctx.ReadBytes().Length;
360ffe3c632Sopenharmony_ci            }
361ffe3c632Sopenharmony_ci            return sum;
362ffe3c632Sopenharmony_ci        }
363ffe3c632Sopenharmony_ci
364ffe3c632Sopenharmony_ci        private static void InitializeParseContext(byte[] buffer, out ParseContext ctx)
365ffe3c632Sopenharmony_ci        {
366ffe3c632Sopenharmony_ci            ParseContext.Initialize(new ReadOnlySequence<byte>(buffer), out ctx);
367ffe3c632Sopenharmony_ci        }
368ffe3c632Sopenharmony_ci
369ffe3c632Sopenharmony_ci        private static void InitializeParseContext(ReadOnlySequence<byte> buffer, out ParseContext ctx)
370ffe3c632Sopenharmony_ci        {
371ffe3c632Sopenharmony_ci            ParseContext.Initialize(buffer, out ctx);
372ffe3c632Sopenharmony_ci        }
373ffe3c632Sopenharmony_ci
374ffe3c632Sopenharmony_ci        private static byte[] CreateBufferWithRandomVarints(Random random, int valueCount, int encodedSize, int paddingValueCount)
375ffe3c632Sopenharmony_ci        {
376ffe3c632Sopenharmony_ci            MemoryStream ms = new MemoryStream();
377ffe3c632Sopenharmony_ci            CodedOutputStream cos = new CodedOutputStream(ms);
378ffe3c632Sopenharmony_ci            for (int i = 0; i < valueCount + paddingValueCount; i++)
379ffe3c632Sopenharmony_ci            {
380ffe3c632Sopenharmony_ci                cos.WriteUInt64(RandomUnsignedVarint(random, encodedSize, false));
381ffe3c632Sopenharmony_ci            }
382ffe3c632Sopenharmony_ci            cos.Flush();
383ffe3c632Sopenharmony_ci            var buffer = ms.ToArray();
384ffe3c632Sopenharmony_ci
385ffe3c632Sopenharmony_ci            if (buffer.Length != encodedSize * (valueCount + paddingValueCount))
386ffe3c632Sopenharmony_ci            {
387ffe3c632Sopenharmony_ci                throw new InvalidOperationException($"Unexpected output buffer length {buffer.Length}");
388ffe3c632Sopenharmony_ci            }
389ffe3c632Sopenharmony_ci            return buffer;
390ffe3c632Sopenharmony_ci        }
391ffe3c632Sopenharmony_ci
392ffe3c632Sopenharmony_ci        private static byte[] CreateBufferWithRandomFloats(Random random, int valueCount, int paddingValueCount)
393ffe3c632Sopenharmony_ci        {
394ffe3c632Sopenharmony_ci            MemoryStream ms = new MemoryStream();
395ffe3c632Sopenharmony_ci            CodedOutputStream cos = new CodedOutputStream(ms);
396ffe3c632Sopenharmony_ci            for (int i = 0; i < valueCount + paddingValueCount; i++)
397ffe3c632Sopenharmony_ci            {
398ffe3c632Sopenharmony_ci                cos.WriteFloat((float)random.NextDouble());
399ffe3c632Sopenharmony_ci            }
400ffe3c632Sopenharmony_ci            cos.Flush();
401ffe3c632Sopenharmony_ci            var buffer = ms.ToArray();
402ffe3c632Sopenharmony_ci            return buffer;
403ffe3c632Sopenharmony_ci        }
404ffe3c632Sopenharmony_ci
405ffe3c632Sopenharmony_ci        private static byte[] CreateBufferWithRandomDoubles(Random random, int valueCount, int paddingValueCount)
406ffe3c632Sopenharmony_ci        {
407ffe3c632Sopenharmony_ci            MemoryStream ms = new MemoryStream();
408ffe3c632Sopenharmony_ci            CodedOutputStream cos = new CodedOutputStream(ms);
409ffe3c632Sopenharmony_ci            for (int i = 0; i < valueCount + paddingValueCount; i++)
410ffe3c632Sopenharmony_ci            {
411ffe3c632Sopenharmony_ci                cos.WriteDouble(random.NextDouble());
412ffe3c632Sopenharmony_ci            }
413ffe3c632Sopenharmony_ci            cos.Flush();
414ffe3c632Sopenharmony_ci            var buffer = ms.ToArray();
415ffe3c632Sopenharmony_ci            return buffer;
416ffe3c632Sopenharmony_ci        }
417ffe3c632Sopenharmony_ci
418ffe3c632Sopenharmony_ci        private static byte[] CreateBufferWithRandomData(Random random, int valueCount, int encodedSize, int paddingValueCount)
419ffe3c632Sopenharmony_ci        {
420ffe3c632Sopenharmony_ci            int bufferSize = (valueCount + paddingValueCount) * encodedSize;
421ffe3c632Sopenharmony_ci            byte[] buffer = new byte[bufferSize];
422ffe3c632Sopenharmony_ci            random.NextBytes(buffer);
423ffe3c632Sopenharmony_ci            return buffer;
424ffe3c632Sopenharmony_ci        }
425ffe3c632Sopenharmony_ci
426ffe3c632Sopenharmony_ci        /// <summary>
427ffe3c632Sopenharmony_ci        /// Generate a random value that will take exactly "encodedSize" bytes when varint-encoded.
428ffe3c632Sopenharmony_ci        /// </summary>
429ffe3c632Sopenharmony_ci        public static ulong RandomUnsignedVarint(Random random, int encodedSize, bool fitsIn32Bits)
430ffe3c632Sopenharmony_ci        {
431ffe3c632Sopenharmony_ci            Span<byte> randomBytesBuffer = stackalloc byte[8];
432ffe3c632Sopenharmony_ci
433ffe3c632Sopenharmony_ci            if (encodedSize < 1 || encodedSize > 10 || (fitsIn32Bits && encodedSize > 5))
434ffe3c632Sopenharmony_ci            {
435ffe3c632Sopenharmony_ci                throw new ArgumentException("Illegal encodedSize value requested", nameof(encodedSize));
436ffe3c632Sopenharmony_ci            }
437ffe3c632Sopenharmony_ci            const int bitsPerByte = 7;
438ffe3c632Sopenharmony_ci
439ffe3c632Sopenharmony_ci            ulong result = 0;
440ffe3c632Sopenharmony_ci            while (true)
441ffe3c632Sopenharmony_ci            {
442ffe3c632Sopenharmony_ci                random.NextBytes(randomBytesBuffer);
443ffe3c632Sopenharmony_ci                ulong randomValue = BinaryPrimitives.ReadUInt64LittleEndian(randomBytesBuffer);
444ffe3c632Sopenharmony_ci
445ffe3c632Sopenharmony_ci                // only use the number of random bits we need
446ffe3c632Sopenharmony_ci                ulong bitmask = encodedSize < 10 ? ((1UL << (encodedSize * bitsPerByte)) - 1) : ulong.MaxValue;
447ffe3c632Sopenharmony_ci                result = randomValue & bitmask;
448ffe3c632Sopenharmony_ci
449ffe3c632Sopenharmony_ci                if (fitsIn32Bits)
450ffe3c632Sopenharmony_ci                {
451ffe3c632Sopenharmony_ci                    // make sure the resulting value is representable by a uint.
452ffe3c632Sopenharmony_ci                    result &= uint.MaxValue;
453ffe3c632Sopenharmony_ci                }
454ffe3c632Sopenharmony_ci
455ffe3c632Sopenharmony_ci                if (encodedSize == 10)
456ffe3c632Sopenharmony_ci                {
457ffe3c632Sopenharmony_ci                    // for 10-byte values the highest bit always needs to be set (7*9=63)
458ffe3c632Sopenharmony_ci                    result |= ulong.MaxValue;
459ffe3c632Sopenharmony_ci                    break;
460ffe3c632Sopenharmony_ci                }
461ffe3c632Sopenharmony_ci
462ffe3c632Sopenharmony_ci                // some random values won't require the full "encodedSize" bytes, check that at least
463ffe3c632Sopenharmony_ci                // one of the top 7 bits is set. Retrying is fine since it only happens rarely
464ffe3c632Sopenharmony_ci                if (encodedSize == 1 || (result & (0x7FUL << ((encodedSize - 1) * bitsPerByte))) != 0)
465ffe3c632Sopenharmony_ci                {
466ffe3c632Sopenharmony_ci                    break;
467ffe3c632Sopenharmony_ci                }
468ffe3c632Sopenharmony_ci            }
469ffe3c632Sopenharmony_ci            return result;
470ffe3c632Sopenharmony_ci        }
471ffe3c632Sopenharmony_ci
472ffe3c632Sopenharmony_ci        private static byte[] CreateBufferWithStrings(int valueCount, int encodedSize, int paddingValueCount)
473ffe3c632Sopenharmony_ci        {
474ffe3c632Sopenharmony_ci            var str = CreateStringWithEncodedSize(encodedSize);
475ffe3c632Sopenharmony_ci
476ffe3c632Sopenharmony_ci            MemoryStream ms = new MemoryStream();
477ffe3c632Sopenharmony_ci            CodedOutputStream cos = new CodedOutputStream(ms);
478ffe3c632Sopenharmony_ci            for (int i = 0; i < valueCount + paddingValueCount; i++)
479ffe3c632Sopenharmony_ci            {
480ffe3c632Sopenharmony_ci                cos.WriteString(str);
481ffe3c632Sopenharmony_ci            }
482ffe3c632Sopenharmony_ci            cos.Flush();
483ffe3c632Sopenharmony_ci            var buffer = ms.ToArray();
484ffe3c632Sopenharmony_ci
485ffe3c632Sopenharmony_ci            if (buffer.Length != encodedSize * (valueCount + paddingValueCount))
486ffe3c632Sopenharmony_ci            {
487ffe3c632Sopenharmony_ci                throw new InvalidOperationException($"Unexpected output buffer length {buffer.Length}");
488ffe3c632Sopenharmony_ci            }
489ffe3c632Sopenharmony_ci            return buffer;
490ffe3c632Sopenharmony_ci        }
491ffe3c632Sopenharmony_ci
492ffe3c632Sopenharmony_ci        public static string CreateStringWithEncodedSize(int encodedSize)
493ffe3c632Sopenharmony_ci        {
494ffe3c632Sopenharmony_ci            var str = new string('a', encodedSize);
495ffe3c632Sopenharmony_ci            while (CodedOutputStream.ComputeStringSize(str) > encodedSize)
496ffe3c632Sopenharmony_ci            {
497ffe3c632Sopenharmony_ci                str = str.Substring(1);
498ffe3c632Sopenharmony_ci            }
499ffe3c632Sopenharmony_ci
500ffe3c632Sopenharmony_ci            if (CodedOutputStream.ComputeStringSize(str) != encodedSize)
501ffe3c632Sopenharmony_ci            {
502ffe3c632Sopenharmony_ci                throw new InvalidOperationException($"Generated string with wrong encodedSize");
503ffe3c632Sopenharmony_ci            }
504ffe3c632Sopenharmony_ci            return str;
505ffe3c632Sopenharmony_ci        }
506ffe3c632Sopenharmony_ci
507ffe3c632Sopenharmony_ci        public static string CreateNonAsciiStringWithEncodedSize(int encodedSize)
508ffe3c632Sopenharmony_ci        {
509ffe3c632Sopenharmony_ci            if (encodedSize < 3)
510ffe3c632Sopenharmony_ci            {
511ffe3c632Sopenharmony_ci                throw new ArgumentException("Illegal encoded size for a string with non-ascii chars.");
512ffe3c632Sopenharmony_ci            }
513ffe3c632Sopenharmony_ci            var twoByteChar = '\u00DC';  // U-umlaut, UTF8 encoding has 2 bytes
514ffe3c632Sopenharmony_ci            var str = new string(twoByteChar, encodedSize / 2);
515ffe3c632Sopenharmony_ci            while (CodedOutputStream.ComputeStringSize(str) > encodedSize)
516ffe3c632Sopenharmony_ci            {
517ffe3c632Sopenharmony_ci                str = str.Substring(1);
518ffe3c632Sopenharmony_ci            }
519ffe3c632Sopenharmony_ci
520ffe3c632Sopenharmony_ci            // add padding of ascii characters to reach the desired encoded size.
521ffe3c632Sopenharmony_ci            while (CodedOutputStream.ComputeStringSize(str) < encodedSize)
522ffe3c632Sopenharmony_ci            {
523ffe3c632Sopenharmony_ci                str += 'a';
524ffe3c632Sopenharmony_ci            }
525ffe3c632Sopenharmony_ci
526ffe3c632Sopenharmony_ci            // Note that for a few specific encodedSize values, it might be impossible to generate
527ffe3c632Sopenharmony_ci            // the string with the desired encodedSize using the algorithm above. For testing purposes, checking that
528ffe3c632Sopenharmony_ci            // the encoded size we got is actually correct is good enough.
529ffe3c632Sopenharmony_ci            if (CodedOutputStream.ComputeStringSize(str) != encodedSize)
530ffe3c632Sopenharmony_ci            {
531ffe3c632Sopenharmony_ci                throw new InvalidOperationException($"Generated string with wrong encodedSize");
532ffe3c632Sopenharmony_ci            }
533ffe3c632Sopenharmony_ci            return str;
534ffe3c632Sopenharmony_ci        }
535ffe3c632Sopenharmony_ci    }
536ffe3c632Sopenharmony_ci}
537