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