1*1b3f573fSAndroid Build Coastguard Worker #region Copyright notice and license
2*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format
3*1b3f573fSAndroid Build Coastguard Worker // Copyright 2019 Google Inc.  All rights reserved.
4*1b3f573fSAndroid Build Coastguard Worker // https://github.com/protocolbuffers/protobuf
5*1b3f573fSAndroid Build Coastguard Worker //
6*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
7*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are
8*1b3f573fSAndroid Build Coastguard Worker // met:
9*1b3f573fSAndroid Build Coastguard Worker //
10*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions of source code must retain the above copyright
11*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
12*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions in binary form must reproduce the above
13*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer
14*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the
15*1b3f573fSAndroid Build Coastguard Worker // distribution.
16*1b3f573fSAndroid Build Coastguard Worker //     * Neither the name of Google Inc. nor the names of its
17*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from
18*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission.
19*1b3f573fSAndroid Build Coastguard Worker //
20*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*1b3f573fSAndroid Build Coastguard Worker #endregion
32*1b3f573fSAndroid Build Coastguard Worker 
33*1b3f573fSAndroid Build Coastguard Worker using BenchmarkDotNet.Attributes;
34*1b3f573fSAndroid Build Coastguard Worker using System;
35*1b3f573fSAndroid Build Coastguard Worker using System.Buffers.Binary;
36*1b3f573fSAndroid Build Coastguard Worker using System.Collections.Generic;
37*1b3f573fSAndroid Build Coastguard Worker using System.IO;
38*1b3f573fSAndroid Build Coastguard Worker using System.Buffers;
39*1b3f573fSAndroid Build Coastguard Worker using System.Text;
40*1b3f573fSAndroid Build Coastguard Worker 
41*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf.Benchmarks
42*1b3f573fSAndroid Build Coastguard Worker {
43*1b3f573fSAndroid Build Coastguard Worker     /// <summary>
44*1b3f573fSAndroid Build Coastguard Worker     /// Benchmarks throughput when writing raw primitives.
45*1b3f573fSAndroid Build Coastguard Worker     /// </summary>
46*1b3f573fSAndroid Build Coastguard Worker     [MemoryDiagnoser]
47*1b3f573fSAndroid Build Coastguard Worker     public class WriteRawPrimitivesBenchmark
48*1b3f573fSAndroid Build Coastguard Worker     {
49*1b3f573fSAndroid Build Coastguard Worker         // key is the encodedSize of varint values
50*1b3f573fSAndroid Build Coastguard Worker         Dictionary<int, uint[]> varint32Values;
51*1b3f573fSAndroid Build Coastguard Worker         Dictionary<int, ulong[]> varint64Values;
52*1b3f573fSAndroid Build Coastguard Worker 
53*1b3f573fSAndroid Build Coastguard Worker         double[] doubleValues;
54*1b3f573fSAndroid Build Coastguard Worker         float[] floatValues;
55*1b3f573fSAndroid Build Coastguard Worker 
56*1b3f573fSAndroid Build Coastguard Worker         // key is the encodedSize of string values
57*1b3f573fSAndroid Build Coastguard Worker         Dictionary<int, string[]> stringValues;
58*1b3f573fSAndroid Build Coastguard Worker 
59*1b3f573fSAndroid Build Coastguard Worker         // key is the encodedSize of string values
60*1b3f573fSAndroid Build Coastguard Worker         Dictionary<int, string[]> nonAsciiStringValues;
61*1b3f573fSAndroid Build Coastguard Worker 
62*1b3f573fSAndroid Build Coastguard Worker         // key is the encodedSize of string values
63*1b3f573fSAndroid Build Coastguard Worker         Dictionary<int, ByteString[]> byteStringValues;
64*1b3f573fSAndroid Build Coastguard Worker 
65*1b3f573fSAndroid Build Coastguard Worker         // the buffer to which all the data will be written
66*1b3f573fSAndroid Build Coastguard Worker         byte[] outputBuffer;
67*1b3f573fSAndroid Build Coastguard Worker 
68*1b3f573fSAndroid Build Coastguard Worker         Random random = new Random(417384220);  // random but deterministic seed
69*1b3f573fSAndroid Build Coastguard Worker 
70*1b3f573fSAndroid Build Coastguard Worker         public IEnumerable<int> StringEncodedSizes => new[] { 1, 4, 10, 105, 10080 };
71*1b3f573fSAndroid Build Coastguard Worker 
72*1b3f573fSAndroid Build Coastguard Worker         public IEnumerable<int> NonAsciiStringEncodedSizes => new[] { 4, 10, 105, 10080 };
73*1b3f573fSAndroid Build Coastguard Worker 
74*1b3f573fSAndroid Build Coastguard Worker         [GlobalSetup]
GlobalSetup()75*1b3f573fSAndroid Build Coastguard Worker         public void GlobalSetup()
76*1b3f573fSAndroid Build Coastguard Worker         {
77*1b3f573fSAndroid Build Coastguard Worker             outputBuffer = new byte[BytesToWrite];
78*1b3f573fSAndroid Build Coastguard Worker 
79*1b3f573fSAndroid Build Coastguard Worker             varint32Values = new Dictionary<int, uint[]>();
80*1b3f573fSAndroid Build Coastguard Worker             varint64Values = new Dictionary<int, ulong[]>();
81*1b3f573fSAndroid Build Coastguard Worker             for (int encodedSize = 1; encodedSize <= 10; encodedSize++)
82*1b3f573fSAndroid Build Coastguard Worker             {
83*1b3f573fSAndroid Build Coastguard Worker                 if (encodedSize <= 5)
84*1b3f573fSAndroid Build Coastguard Worker                 {
85*1b3f573fSAndroid Build Coastguard Worker                     varint32Values.Add(encodedSize, CreateRandomVarints32(random, BytesToWrite / encodedSize, encodedSize));
86*1b3f573fSAndroid Build Coastguard Worker                 }
87*1b3f573fSAndroid Build Coastguard Worker                 varint64Values.Add(encodedSize, CreateRandomVarints64(random, BytesToWrite / encodedSize, encodedSize));
88*1b3f573fSAndroid Build Coastguard Worker             }
89*1b3f573fSAndroid Build Coastguard Worker 
90*1b3f573fSAndroid Build Coastguard Worker             doubleValues = CreateRandomDoubles(random, BytesToWrite / sizeof(double));
91*1b3f573fSAndroid Build Coastguard Worker             floatValues = CreateRandomFloats(random, BytesToWrite / sizeof(float));
92*1b3f573fSAndroid Build Coastguard Worker 
93*1b3f573fSAndroid Build Coastguard Worker             stringValues = new Dictionary<int, string[]>();
94*1b3f573fSAndroid Build Coastguard Worker 
95*1b3f573fSAndroid Build Coastguard Worker             byteStringValues = new Dictionary<int, ByteString[]>();
96*1b3f573fSAndroid Build Coastguard Worker             foreach(var encodedSize in StringEncodedSizes)
97*1b3f573fSAndroid Build Coastguard Worker             {
98*1b3f573fSAndroid Build Coastguard Worker                 stringValues.Add(encodedSize, CreateStrings(BytesToWrite / encodedSize, encodedSize));
99*1b3f573fSAndroid Build Coastguard Worker                 byteStringValues.Add(encodedSize, CreateByteStrings(BytesToWrite / encodedSize, encodedSize));
100*1b3f573fSAndroid Build Coastguard Worker             }
101*1b3f573fSAndroid Build Coastguard Worker 
102*1b3f573fSAndroid Build Coastguard Worker             nonAsciiStringValues = new Dictionary<int, string[]>();
103*1b3f573fSAndroid Build Coastguard Worker             foreach(var encodedSize in NonAsciiStringEncodedSizes)
104*1b3f573fSAndroid Build Coastguard Worker             {
105*1b3f573fSAndroid Build Coastguard Worker                 nonAsciiStringValues.Add(encodedSize, CreateNonAsciiStrings(BytesToWrite / encodedSize, encodedSize));
106*1b3f573fSAndroid Build Coastguard Worker             }
107*1b3f573fSAndroid Build Coastguard Worker         }
108*1b3f573fSAndroid Build Coastguard Worker 
109*1b3f573fSAndroid Build Coastguard Worker         // Total number of bytes that each benchmark will write.
110*1b3f573fSAndroid Build Coastguard Worker         // Measuring the time taken to write buffer of given size makes it easier to compare parsing speed for different
111*1b3f573fSAndroid Build Coastguard Worker         // types and makes it easy to calculate the througput (in MB/s)
112*1b3f573fSAndroid Build Coastguard Worker         // 10800 bytes is chosen because it is divisible by all possible encoded sizes for all primitive types {1..10}
113*1b3f573fSAndroid Build Coastguard Worker         [Params(10080)]
114*1b3f573fSAndroid Build Coastguard Worker         public int BytesToWrite { get; set; }
115*1b3f573fSAndroid Build Coastguard Worker 
116*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
117*1b3f573fSAndroid Build Coastguard Worker         [Arguments(1)]
118*1b3f573fSAndroid Build Coastguard Worker         [Arguments(2)]
119*1b3f573fSAndroid Build Coastguard Worker         [Arguments(3)]
120*1b3f573fSAndroid Build Coastguard Worker         [Arguments(4)]
121*1b3f573fSAndroid Build Coastguard Worker         [Arguments(5)]
WriteRawVarint32_CodedOutputStream(int encodedSize)122*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawVarint32_CodedOutputStream(int encodedSize)
123*1b3f573fSAndroid Build Coastguard Worker         {
124*1b3f573fSAndroid Build Coastguard Worker             var values = varint32Values[encodedSize];
125*1b3f573fSAndroid Build Coastguard Worker             var cos = new CodedOutputStream(outputBuffer);
126*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < values.Length; i++)
127*1b3f573fSAndroid Build Coastguard Worker             {
128*1b3f573fSAndroid Build Coastguard Worker                 cos.WriteRawVarint32(values[i]);
129*1b3f573fSAndroid Build Coastguard Worker             }
130*1b3f573fSAndroid Build Coastguard Worker             cos.Flush();
131*1b3f573fSAndroid Build Coastguard Worker             cos.CheckNoSpaceLeft();
132*1b3f573fSAndroid Build Coastguard Worker         }
133*1b3f573fSAndroid Build Coastguard Worker 
134*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
135*1b3f573fSAndroid Build Coastguard Worker         [Arguments(1)]
136*1b3f573fSAndroid Build Coastguard Worker         [Arguments(2)]
137*1b3f573fSAndroid Build Coastguard Worker         [Arguments(3)]
138*1b3f573fSAndroid Build Coastguard Worker         [Arguments(4)]
139*1b3f573fSAndroid Build Coastguard Worker         [Arguments(5)]
WriteRawVarint32_WriteContext(int encodedSize)140*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawVarint32_WriteContext(int encodedSize)
141*1b3f573fSAndroid Build Coastguard Worker         {
142*1b3f573fSAndroid Build Coastguard Worker             var values = varint32Values[encodedSize];
143*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
144*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
145*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < values.Length; i++)
146*1b3f573fSAndroid Build Coastguard Worker             {
147*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteUInt32(values[i]);
148*1b3f573fSAndroid Build Coastguard Worker             }
149*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
150*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
151*1b3f573fSAndroid Build Coastguard Worker         }
152*1b3f573fSAndroid Build Coastguard Worker 
153*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
154*1b3f573fSAndroid Build Coastguard Worker         [Arguments(1)]
155*1b3f573fSAndroid Build Coastguard Worker         [Arguments(2)]
156*1b3f573fSAndroid Build Coastguard Worker         [Arguments(3)]
157*1b3f573fSAndroid Build Coastguard Worker         [Arguments(4)]
158*1b3f573fSAndroid Build Coastguard Worker         [Arguments(5)]
159*1b3f573fSAndroid Build Coastguard Worker         [Arguments(6)]
160*1b3f573fSAndroid Build Coastguard Worker         [Arguments(7)]
161*1b3f573fSAndroid Build Coastguard Worker         [Arguments(8)]
162*1b3f573fSAndroid Build Coastguard Worker         [Arguments(9)]
163*1b3f573fSAndroid Build Coastguard Worker         [Arguments(10)]
WriteRawVarint64_CodedOutputStream(int encodedSize)164*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawVarint64_CodedOutputStream(int encodedSize)
165*1b3f573fSAndroid Build Coastguard Worker         {
166*1b3f573fSAndroid Build Coastguard Worker             var values = varint64Values[encodedSize];
167*1b3f573fSAndroid Build Coastguard Worker             var cos = new CodedOutputStream(outputBuffer);
168*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < values.Length; i++)
169*1b3f573fSAndroid Build Coastguard Worker             {
170*1b3f573fSAndroid Build Coastguard Worker                 cos.WriteRawVarint64(values[i]);
171*1b3f573fSAndroid Build Coastguard Worker             }
172*1b3f573fSAndroid Build Coastguard Worker             cos.Flush();
173*1b3f573fSAndroid Build Coastguard Worker             cos.CheckNoSpaceLeft();
174*1b3f573fSAndroid Build Coastguard Worker         }
175*1b3f573fSAndroid Build Coastguard Worker 
176*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
177*1b3f573fSAndroid Build Coastguard Worker         [Arguments(1)]
178*1b3f573fSAndroid Build Coastguard Worker         [Arguments(2)]
179*1b3f573fSAndroid Build Coastguard Worker         [Arguments(3)]
180*1b3f573fSAndroid Build Coastguard Worker         [Arguments(4)]
181*1b3f573fSAndroid Build Coastguard Worker         [Arguments(5)]
182*1b3f573fSAndroid Build Coastguard Worker         [Arguments(6)]
183*1b3f573fSAndroid Build Coastguard Worker         [Arguments(7)]
184*1b3f573fSAndroid Build Coastguard Worker         [Arguments(8)]
185*1b3f573fSAndroid Build Coastguard Worker         [Arguments(9)]
186*1b3f573fSAndroid Build Coastguard Worker         [Arguments(10)]
WriteRawVarint64_WriteContext(int encodedSize)187*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawVarint64_WriteContext(int encodedSize)
188*1b3f573fSAndroid Build Coastguard Worker         {
189*1b3f573fSAndroid Build Coastguard Worker             var values = varint64Values[encodedSize];
190*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
191*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
192*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < values.Length; i++)
193*1b3f573fSAndroid Build Coastguard Worker             {
194*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteUInt64(values[i]);
195*1b3f573fSAndroid Build Coastguard Worker             }
196*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
197*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
198*1b3f573fSAndroid Build Coastguard Worker         }
199*1b3f573fSAndroid Build Coastguard Worker 
200*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteFixed32_CodedOutputStream()201*1b3f573fSAndroid Build Coastguard Worker         public void WriteFixed32_CodedOutputStream()
202*1b3f573fSAndroid Build Coastguard Worker         {
203*1b3f573fSAndroid Build Coastguard Worker             const int encodedSize = sizeof(uint);
204*1b3f573fSAndroid Build Coastguard Worker             var cos = new CodedOutputStream(outputBuffer);
205*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < BytesToWrite / encodedSize; i++)
206*1b3f573fSAndroid Build Coastguard Worker             {
207*1b3f573fSAndroid Build Coastguard Worker                 cos.WriteFixed32(12345);
208*1b3f573fSAndroid Build Coastguard Worker             }
209*1b3f573fSAndroid Build Coastguard Worker             cos.Flush();
210*1b3f573fSAndroid Build Coastguard Worker             cos.CheckNoSpaceLeft();
211*1b3f573fSAndroid Build Coastguard Worker         }
212*1b3f573fSAndroid Build Coastguard Worker 
213*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteFixed32_WriteContext()214*1b3f573fSAndroid Build Coastguard Worker         public void WriteFixed32_WriteContext()
215*1b3f573fSAndroid Build Coastguard Worker         {
216*1b3f573fSAndroid Build Coastguard Worker             const int encodedSize = sizeof(uint);
217*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
218*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
219*1b3f573fSAndroid Build Coastguard Worker             for (uint i = 0; i < BytesToWrite / encodedSize; i++)
220*1b3f573fSAndroid Build Coastguard Worker             {
221*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteFixed32(12345);
222*1b3f573fSAndroid Build Coastguard Worker             }
223*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
224*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
225*1b3f573fSAndroid Build Coastguard Worker         }
226*1b3f573fSAndroid Build Coastguard Worker 
227*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteFixed64_CodedOutputStream()228*1b3f573fSAndroid Build Coastguard Worker         public void WriteFixed64_CodedOutputStream()
229*1b3f573fSAndroid Build Coastguard Worker         {
230*1b3f573fSAndroid Build Coastguard Worker             const int encodedSize = sizeof(ulong);
231*1b3f573fSAndroid Build Coastguard Worker             var cos = new CodedOutputStream(outputBuffer);
232*1b3f573fSAndroid Build Coastguard Worker             for(int i = 0; i < BytesToWrite / encodedSize; i++)
233*1b3f573fSAndroid Build Coastguard Worker             {
234*1b3f573fSAndroid Build Coastguard Worker                 cos.WriteFixed64(123456789);
235*1b3f573fSAndroid Build Coastguard Worker             }
236*1b3f573fSAndroid Build Coastguard Worker             cos.Flush();
237*1b3f573fSAndroid Build Coastguard Worker             cos.CheckNoSpaceLeft();
238*1b3f573fSAndroid Build Coastguard Worker         }
239*1b3f573fSAndroid Build Coastguard Worker 
240*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteFixed64_WriteContext()241*1b3f573fSAndroid Build Coastguard Worker         public void WriteFixed64_WriteContext()
242*1b3f573fSAndroid Build Coastguard Worker         {
243*1b3f573fSAndroid Build Coastguard Worker             const int encodedSize = sizeof(ulong);
244*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
245*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
246*1b3f573fSAndroid Build Coastguard Worker             for (uint i = 0; i < BytesToWrite / encodedSize; i++)
247*1b3f573fSAndroid Build Coastguard Worker             {
248*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteFixed64(123456789);
249*1b3f573fSAndroid Build Coastguard Worker             }
250*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
251*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
252*1b3f573fSAndroid Build Coastguard Worker         }
253*1b3f573fSAndroid Build Coastguard Worker 
254*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteRawTag_OneByte_WriteContext()255*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawTag_OneByte_WriteContext()
256*1b3f573fSAndroid Build Coastguard Worker         {
257*1b3f573fSAndroid Build Coastguard Worker             const int encodedSize = 1;
258*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
259*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
260*1b3f573fSAndroid Build Coastguard Worker             for (uint i = 0; i < BytesToWrite / encodedSize; i++)
261*1b3f573fSAndroid Build Coastguard Worker             {
262*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteRawTag(16);
263*1b3f573fSAndroid Build Coastguard Worker             }
264*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
265*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
266*1b3f573fSAndroid Build Coastguard Worker         }
267*1b3f573fSAndroid Build Coastguard Worker 
268*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteRawTag_TwoBytes_WriteContext()269*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawTag_TwoBytes_WriteContext()
270*1b3f573fSAndroid Build Coastguard Worker         {
271*1b3f573fSAndroid Build Coastguard Worker             const int encodedSize = 2;
272*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
273*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
274*1b3f573fSAndroid Build Coastguard Worker             for (uint i = 0; i < BytesToWrite / encodedSize; i++)
275*1b3f573fSAndroid Build Coastguard Worker             {
276*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteRawTag(137, 6);
277*1b3f573fSAndroid Build Coastguard Worker             }
278*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
279*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
280*1b3f573fSAndroid Build Coastguard Worker         }
281*1b3f573fSAndroid Build Coastguard Worker 
282*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteRawTag_ThreeBytes_WriteContext()283*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawTag_ThreeBytes_WriteContext()
284*1b3f573fSAndroid Build Coastguard Worker         {
285*1b3f573fSAndroid Build Coastguard Worker             const int encodedSize = 3;
286*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
287*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
288*1b3f573fSAndroid Build Coastguard Worker             for (uint i = 0; i < BytesToWrite / encodedSize; i++)
289*1b3f573fSAndroid Build Coastguard Worker             {
290*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteRawTag(160, 131, 1);
291*1b3f573fSAndroid Build Coastguard Worker             }
292*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
293*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
294*1b3f573fSAndroid Build Coastguard Worker         }
295*1b3f573fSAndroid Build Coastguard Worker 
296*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
Baseline_WriteContext()297*1b3f573fSAndroid Build Coastguard Worker         public void Baseline_WriteContext()
298*1b3f573fSAndroid Build Coastguard Worker         {
299*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
300*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
301*1b3f573fSAndroid Build Coastguard Worker             ctx.state.position = outputBuffer.Length;
302*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
303*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
304*1b3f573fSAndroid Build Coastguard Worker         }
305*1b3f573fSAndroid Build Coastguard Worker 
306*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteRawFloat_CodedOutputStream()307*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawFloat_CodedOutputStream()
308*1b3f573fSAndroid Build Coastguard Worker         {
309*1b3f573fSAndroid Build Coastguard Worker             var cos = new CodedOutputStream(outputBuffer);
310*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in floatValues)
311*1b3f573fSAndroid Build Coastguard Worker             {
312*1b3f573fSAndroid Build Coastguard Worker                 cos.WriteFloat(value);
313*1b3f573fSAndroid Build Coastguard Worker             }
314*1b3f573fSAndroid Build Coastguard Worker             cos.Flush();
315*1b3f573fSAndroid Build Coastguard Worker             cos.CheckNoSpaceLeft();
316*1b3f573fSAndroid Build Coastguard Worker         }
317*1b3f573fSAndroid Build Coastguard Worker 
318*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteRawFloat_WriteContext()319*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawFloat_WriteContext()
320*1b3f573fSAndroid Build Coastguard Worker         {
321*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
322*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
323*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in floatValues)
324*1b3f573fSAndroid Build Coastguard Worker             {
325*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteFloat(value);
326*1b3f573fSAndroid Build Coastguard Worker             }
327*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
328*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
329*1b3f573fSAndroid Build Coastguard Worker         }
330*1b3f573fSAndroid Build Coastguard Worker 
331*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteRawDouble_CodedOutputStream()332*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawDouble_CodedOutputStream()
333*1b3f573fSAndroid Build Coastguard Worker         {
334*1b3f573fSAndroid Build Coastguard Worker             var cos = new CodedOutputStream(outputBuffer);
335*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in doubleValues)
336*1b3f573fSAndroid Build Coastguard Worker             {
337*1b3f573fSAndroid Build Coastguard Worker                 cos.WriteDouble(value);
338*1b3f573fSAndroid Build Coastguard Worker             }
339*1b3f573fSAndroid Build Coastguard Worker             cos.Flush();
340*1b3f573fSAndroid Build Coastguard Worker             cos.CheckNoSpaceLeft();
341*1b3f573fSAndroid Build Coastguard Worker         }
342*1b3f573fSAndroid Build Coastguard Worker 
343*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
WriteRawDouble_WriteContext()344*1b3f573fSAndroid Build Coastguard Worker         public void WriteRawDouble_WriteContext()
345*1b3f573fSAndroid Build Coastguard Worker         {
346*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
347*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
348*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in doubleValues)
349*1b3f573fSAndroid Build Coastguard Worker             {
350*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteDouble(value);
351*1b3f573fSAndroid Build Coastguard Worker             }
352*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
353*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
354*1b3f573fSAndroid Build Coastguard Worker         }
355*1b3f573fSAndroid Build Coastguard Worker 
356*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
357*1b3f573fSAndroid Build Coastguard Worker         [ArgumentsSource(nameof(StringEncodedSizes))]
WriteString_CodedOutputStream(int encodedSize)358*1b3f573fSAndroid Build Coastguard Worker         public void WriteString_CodedOutputStream(int encodedSize)
359*1b3f573fSAndroid Build Coastguard Worker         {
360*1b3f573fSAndroid Build Coastguard Worker             var values = stringValues[encodedSize];
361*1b3f573fSAndroid Build Coastguard Worker             var cos = new CodedOutputStream(outputBuffer);
362*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in values)
363*1b3f573fSAndroid Build Coastguard Worker             {
364*1b3f573fSAndroid Build Coastguard Worker                 cos.WriteString(value);
365*1b3f573fSAndroid Build Coastguard Worker             }
366*1b3f573fSAndroid Build Coastguard Worker             cos.Flush();
367*1b3f573fSAndroid Build Coastguard Worker             cos.CheckNoSpaceLeft();
368*1b3f573fSAndroid Build Coastguard Worker         }
369*1b3f573fSAndroid Build Coastguard Worker 
370*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
371*1b3f573fSAndroid Build Coastguard Worker         [ArgumentsSource(nameof(StringEncodedSizes))]
WriteString_WriteContext(int encodedSize)372*1b3f573fSAndroid Build Coastguard Worker         public void WriteString_WriteContext(int encodedSize)
373*1b3f573fSAndroid Build Coastguard Worker         {
374*1b3f573fSAndroid Build Coastguard Worker             var values = stringValues[encodedSize];
375*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
376*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
377*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in values)
378*1b3f573fSAndroid Build Coastguard Worker             {
379*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteString(value);
380*1b3f573fSAndroid Build Coastguard Worker             }
381*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
382*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
383*1b3f573fSAndroid Build Coastguard Worker         }
384*1b3f573fSAndroid Build Coastguard Worker 
385*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
386*1b3f573fSAndroid Build Coastguard Worker         [ArgumentsSource(nameof(NonAsciiStringEncodedSizes))]
WriteNonAsciiString_CodedOutputStream(int encodedSize)387*1b3f573fSAndroid Build Coastguard Worker         public void WriteNonAsciiString_CodedOutputStream(int encodedSize)
388*1b3f573fSAndroid Build Coastguard Worker         {
389*1b3f573fSAndroid Build Coastguard Worker             var values = nonAsciiStringValues[encodedSize];
390*1b3f573fSAndroid Build Coastguard Worker             var cos = new CodedOutputStream(outputBuffer);
391*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in values)
392*1b3f573fSAndroid Build Coastguard Worker             {
393*1b3f573fSAndroid Build Coastguard Worker                 cos.WriteString(value);
394*1b3f573fSAndroid Build Coastguard Worker             }
395*1b3f573fSAndroid Build Coastguard Worker             cos.Flush();
396*1b3f573fSAndroid Build Coastguard Worker             cos.CheckNoSpaceLeft();
397*1b3f573fSAndroid Build Coastguard Worker         }
398*1b3f573fSAndroid Build Coastguard Worker 
399*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
400*1b3f573fSAndroid Build Coastguard Worker         [ArgumentsSource(nameof(NonAsciiStringEncodedSizes))]
WriteNonAsciiString_WriteContext(int encodedSize)401*1b3f573fSAndroid Build Coastguard Worker         public void WriteNonAsciiString_WriteContext(int encodedSize)
402*1b3f573fSAndroid Build Coastguard Worker         {
403*1b3f573fSAndroid Build Coastguard Worker             var values = nonAsciiStringValues[encodedSize];
404*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
405*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
406*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in values)
407*1b3f573fSAndroid Build Coastguard Worker             {
408*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteString(value);
409*1b3f573fSAndroid Build Coastguard Worker             }
410*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
411*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
412*1b3f573fSAndroid Build Coastguard Worker         }
413*1b3f573fSAndroid Build Coastguard Worker 
414*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
415*1b3f573fSAndroid Build Coastguard Worker         [ArgumentsSource(nameof(StringEncodedSizes))]
WriteBytes_CodedOutputStream(int encodedSize)416*1b3f573fSAndroid Build Coastguard Worker         public void WriteBytes_CodedOutputStream(int encodedSize)
417*1b3f573fSAndroid Build Coastguard Worker         {
418*1b3f573fSAndroid Build Coastguard Worker             var values = byteStringValues[encodedSize];
419*1b3f573fSAndroid Build Coastguard Worker             var cos = new CodedOutputStream(outputBuffer);
420*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in values)
421*1b3f573fSAndroid Build Coastguard Worker             {
422*1b3f573fSAndroid Build Coastguard Worker                 cos.WriteBytes(value);
423*1b3f573fSAndroid Build Coastguard Worker             }
424*1b3f573fSAndroid Build Coastguard Worker             cos.Flush();
425*1b3f573fSAndroid Build Coastguard Worker             cos.CheckNoSpaceLeft();
426*1b3f573fSAndroid Build Coastguard Worker         }
427*1b3f573fSAndroid Build Coastguard Worker 
428*1b3f573fSAndroid Build Coastguard Worker         [Benchmark]
429*1b3f573fSAndroid Build Coastguard Worker         [ArgumentsSource(nameof(StringEncodedSizes))]
WriteBytes_WriteContext(int encodedSize)430*1b3f573fSAndroid Build Coastguard Worker         public void WriteBytes_WriteContext(int encodedSize)
431*1b3f573fSAndroid Build Coastguard Worker         {
432*1b3f573fSAndroid Build Coastguard Worker             var values = byteStringValues[encodedSize];
433*1b3f573fSAndroid Build Coastguard Worker             var span = new Span<byte>(outputBuffer);
434*1b3f573fSAndroid Build Coastguard Worker             WriteContext.Initialize(ref span, out WriteContext ctx);
435*1b3f573fSAndroid Build Coastguard Worker             foreach (var value in values)
436*1b3f573fSAndroid Build Coastguard Worker             {
437*1b3f573fSAndroid Build Coastguard Worker                 ctx.WriteBytes(value);
438*1b3f573fSAndroid Build Coastguard Worker             }
439*1b3f573fSAndroid Build Coastguard Worker             ctx.Flush();
440*1b3f573fSAndroid Build Coastguard Worker             ctx.CheckNoSpaceLeft();
441*1b3f573fSAndroid Build Coastguard Worker         }
442*1b3f573fSAndroid Build Coastguard Worker 
CreateRandomVarints32(Random random, int valueCount, int encodedSize)443*1b3f573fSAndroid Build Coastguard Worker         private static uint[] CreateRandomVarints32(Random random, int valueCount, int encodedSize)
444*1b3f573fSAndroid Build Coastguard Worker         {
445*1b3f573fSAndroid Build Coastguard Worker             var result = new uint[valueCount];
446*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < valueCount; i++)
447*1b3f573fSAndroid Build Coastguard Worker             {
448*1b3f573fSAndroid Build Coastguard Worker                 result[i] = (uint) ParseRawPrimitivesBenchmark.RandomUnsignedVarint(random, encodedSize, true);
449*1b3f573fSAndroid Build Coastguard Worker             }
450*1b3f573fSAndroid Build Coastguard Worker             return result;
451*1b3f573fSAndroid Build Coastguard Worker         }
452*1b3f573fSAndroid Build Coastguard Worker 
CreateRandomVarints64(Random random, int valueCount, int encodedSize)453*1b3f573fSAndroid Build Coastguard Worker         private static ulong[] CreateRandomVarints64(Random random, int valueCount, int encodedSize)
454*1b3f573fSAndroid Build Coastguard Worker         {
455*1b3f573fSAndroid Build Coastguard Worker             var result = new ulong[valueCount];
456*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < valueCount; i++)
457*1b3f573fSAndroid Build Coastguard Worker             {
458*1b3f573fSAndroid Build Coastguard Worker                 result[i] = ParseRawPrimitivesBenchmark.RandomUnsignedVarint(random, encodedSize, false);
459*1b3f573fSAndroid Build Coastguard Worker             }
460*1b3f573fSAndroid Build Coastguard Worker             return result;
461*1b3f573fSAndroid Build Coastguard Worker         }
462*1b3f573fSAndroid Build Coastguard Worker 
CreateRandomFloats(Random random, int valueCount)463*1b3f573fSAndroid Build Coastguard Worker         private static float[] CreateRandomFloats(Random random, int valueCount)
464*1b3f573fSAndroid Build Coastguard Worker         {
465*1b3f573fSAndroid Build Coastguard Worker             var result = new float[valueCount];
466*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < valueCount; i++)
467*1b3f573fSAndroid Build Coastguard Worker             {
468*1b3f573fSAndroid Build Coastguard Worker                 result[i] = (float)random.NextDouble();
469*1b3f573fSAndroid Build Coastguard Worker             }
470*1b3f573fSAndroid Build Coastguard Worker             return result;
471*1b3f573fSAndroid Build Coastguard Worker         }
472*1b3f573fSAndroid Build Coastguard Worker 
CreateRandomDoubles(Random random, int valueCount)473*1b3f573fSAndroid Build Coastguard Worker         private static double[] CreateRandomDoubles(Random random, int valueCount)
474*1b3f573fSAndroid Build Coastguard Worker         {
475*1b3f573fSAndroid Build Coastguard Worker             var result = new double[valueCount];
476*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < valueCount; i++)
477*1b3f573fSAndroid Build Coastguard Worker             {
478*1b3f573fSAndroid Build Coastguard Worker                 result[i] = random.NextDouble();
479*1b3f573fSAndroid Build Coastguard Worker             }
480*1b3f573fSAndroid Build Coastguard Worker             return result;
481*1b3f573fSAndroid Build Coastguard Worker         }
482*1b3f573fSAndroid Build Coastguard Worker 
CreateStrings(int valueCount, int encodedSize)483*1b3f573fSAndroid Build Coastguard Worker         private static string[] CreateStrings(int valueCount, int encodedSize)
484*1b3f573fSAndroid Build Coastguard Worker         {
485*1b3f573fSAndroid Build Coastguard Worker             var str = ParseRawPrimitivesBenchmark.CreateStringWithEncodedSize(encodedSize);
486*1b3f573fSAndroid Build Coastguard Worker 
487*1b3f573fSAndroid Build Coastguard Worker             var result = new string[valueCount];
488*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < valueCount; i++)
489*1b3f573fSAndroid Build Coastguard Worker             {
490*1b3f573fSAndroid Build Coastguard Worker                 result[i] = str;
491*1b3f573fSAndroid Build Coastguard Worker             }
492*1b3f573fSAndroid Build Coastguard Worker             return result;
493*1b3f573fSAndroid Build Coastguard Worker         }
494*1b3f573fSAndroid Build Coastguard Worker 
CreateNonAsciiStrings(int valueCount, int encodedSize)495*1b3f573fSAndroid Build Coastguard Worker         private static string[] CreateNonAsciiStrings(int valueCount, int encodedSize)
496*1b3f573fSAndroid Build Coastguard Worker         {
497*1b3f573fSAndroid Build Coastguard Worker             var str = ParseRawPrimitivesBenchmark.CreateNonAsciiStringWithEncodedSize(encodedSize);
498*1b3f573fSAndroid Build Coastguard Worker 
499*1b3f573fSAndroid Build Coastguard Worker             var result = new string[valueCount];
500*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < valueCount; i++)
501*1b3f573fSAndroid Build Coastguard Worker             {
502*1b3f573fSAndroid Build Coastguard Worker                 result[i] = str;
503*1b3f573fSAndroid Build Coastguard Worker             }
504*1b3f573fSAndroid Build Coastguard Worker             return result;
505*1b3f573fSAndroid Build Coastguard Worker         }
506*1b3f573fSAndroid Build Coastguard Worker 
CreateByteStrings(int valueCount, int encodedSize)507*1b3f573fSAndroid Build Coastguard Worker         private static ByteString[] CreateByteStrings(int valueCount, int encodedSize)
508*1b3f573fSAndroid Build Coastguard Worker         {
509*1b3f573fSAndroid Build Coastguard Worker             var str = ParseRawPrimitivesBenchmark.CreateStringWithEncodedSize(encodedSize);
510*1b3f573fSAndroid Build Coastguard Worker 
511*1b3f573fSAndroid Build Coastguard Worker             var result = new ByteString[valueCount];
512*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < valueCount; i++)
513*1b3f573fSAndroid Build Coastguard Worker             {
514*1b3f573fSAndroid Build Coastguard Worker                 result[i] = ByteString.CopyFrom(Encoding.UTF8.GetBytes(str));
515*1b3f573fSAndroid Build Coastguard Worker             }
516*1b3f573fSAndroid Build Coastguard Worker             return result;
517*1b3f573fSAndroid Build Coastguard Worker         }
518*1b3f573fSAndroid Build Coastguard Worker     }
519*1b3f573fSAndroid Build Coastguard Worker }
520