• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2019 Google Inc.  All rights reserved.
4 // https://github.com/protocolbuffers/protobuf
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 //     * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #endregion
32 
33 using BenchmarkDotNet.Attributes;
34 using System;
35 using System.Collections.Generic;
36 using System.IO;
37 using System.Linq;
38 using System.Buffers;
39 using Google.Protobuf.WellKnownTypes;
40 using Benchmarks.Proto3;
41 
42 namespace Google.Protobuf.Benchmarks
43 {
44     /// <summary>
45     /// Benchmark that tests parsing performance for various messages.
46     /// </summary>
47     [MemoryDiagnoser]
48     public class ParseMessagesBenchmark
49     {
50         const int MaxMessages = 100;
51 
52         SubTest manyWrapperFieldsTest = new SubTest(CreateManyWrapperFieldsMessage(), ManyWrapperFieldsMessage.Parser, () => new ManyWrapperFieldsMessage(), MaxMessages);
53         SubTest manyPrimitiveFieldsTest = new SubTest(CreateManyPrimitiveFieldsMessage(), ManyPrimitiveFieldsMessage.Parser, () => new ManyPrimitiveFieldsMessage(), MaxMessages);
54         SubTest repeatedFieldTest = new SubTest(CreateRepeatedFieldMessage(), GoogleMessage1.Parser, () => new GoogleMessage1(), MaxMessages);
55         SubTest emptyMessageTest = new SubTest(new Empty(), Empty.Parser, () => new Empty(), MaxMessages);
56 
57         public IEnumerable<int> MessageCountValues => new[] { 10, 100 };
58 
59         [GlobalSetup]
GlobalSetup()60         public void GlobalSetup()
61         {
62         }
63 
64         [Benchmark]
ManyWrapperFieldsMessage_ParseFromByteArray()65         public IMessage ManyWrapperFieldsMessage_ParseFromByteArray()
66         {
67             return manyWrapperFieldsTest.ParseFromByteArray();
68         }
69 
70         [Benchmark]
ManyWrapperFieldsMessage_ParseFromReadOnlySequence()71         public IMessage ManyWrapperFieldsMessage_ParseFromReadOnlySequence()
72         {
73             return manyWrapperFieldsTest.ParseFromReadOnlySequence();
74         }
75 
76         [Benchmark]
ManyPrimitiveFieldsMessage_ParseFromByteArray()77         public IMessage ManyPrimitiveFieldsMessage_ParseFromByteArray()
78         {
79             return manyPrimitiveFieldsTest.ParseFromByteArray();
80         }
81 
82         [Benchmark]
ManyPrimitiveFieldsMessage_ParseFromReadOnlySequence()83         public IMessage ManyPrimitiveFieldsMessage_ParseFromReadOnlySequence()
84         {
85             return manyPrimitiveFieldsTest.ParseFromReadOnlySequence();
86         }
87 
88         [Benchmark]
RepeatedFieldMessage_ParseFromByteArray()89         public IMessage RepeatedFieldMessage_ParseFromByteArray()
90         {
91             return repeatedFieldTest.ParseFromByteArray();
92         }
93 
94         [Benchmark]
RepeatedFieldMessage_ParseFromReadOnlySequence()95         public IMessage RepeatedFieldMessage_ParseFromReadOnlySequence()
96         {
97             return repeatedFieldTest.ParseFromReadOnlySequence();
98         }
99 
100         [Benchmark]
EmptyMessage_ParseFromByteArray()101         public IMessage EmptyMessage_ParseFromByteArray()
102         {
103             return emptyMessageTest.ParseFromByteArray();
104         }
105 
106         [Benchmark]
EmptyMessage_ParseFromReadOnlySequence()107         public IMessage EmptyMessage_ParseFromReadOnlySequence()
108         {
109             return emptyMessageTest.ParseFromReadOnlySequence();
110         }
111 
112         [Benchmark]
113         [ArgumentsSource(nameof(MessageCountValues))]
ManyWrapperFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)114         public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
115         {
116             manyWrapperFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount);
117         }
118 
119         [Benchmark]
120         [ArgumentsSource(nameof(MessageCountValues))]
ManyWrapperFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)121         public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
122         {
123             manyWrapperFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
124         }
125 
126         [Benchmark]
127         [ArgumentsSource(nameof(MessageCountValues))]
ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)128         public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
129         {
130             manyPrimitiveFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount);
131         }
132 
133         [Benchmark]
134         [ArgumentsSource(nameof(MessageCountValues))]
ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)135         public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
136         {
137             manyPrimitiveFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
138         }
139 
140         [Benchmark]
141         [ArgumentsSource(nameof(MessageCountValues))]
RepeatedFieldMessage_ParseDelimitedMessagesFromByteArray(int messageCount)142         public void RepeatedFieldMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
143         {
144             repeatedFieldTest.ParseDelimitedMessagesFromByteArray(messageCount);
145         }
146 
147         [Benchmark]
148         [ArgumentsSource(nameof(MessageCountValues))]
RepeatedFieldMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)149         public void RepeatedFieldMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
150         {
151             repeatedFieldTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
152         }
153 
CreateManyWrapperFieldsMessage()154         public static ManyWrapperFieldsMessage CreateManyWrapperFieldsMessage()
155         {
156             // Example data match data of an internal benchmarks
157             return new ManyWrapperFieldsMessage()
158             {
159                 Int64Field19 = 123,
160                 Int64Field37 = 1000032,
161                 Int64Field26 = 3453524500,
162                 DoubleField79 = 1.2,
163                 DoubleField25 = 234,
164                 DoubleField9 = 123.3,
165                 DoubleField28 = 23,
166                 DoubleField7 = 234,
167                 DoubleField50 = 2.45
168             };
169         }
170 
CreateManyPrimitiveFieldsMessage()171         public static ManyPrimitiveFieldsMessage CreateManyPrimitiveFieldsMessage()
172         {
173             // Example data match data of an internal benchmarks
174             return new ManyPrimitiveFieldsMessage()
175             {
176                 Int64Field19 = 123,
177                 Int64Field37 = 1000032,
178                 Int64Field26 = 3453524500,
179                 DoubleField79 = 1.2,
180                 DoubleField25 = 234,
181                 DoubleField9 = 123.3,
182                 DoubleField28 = 23,
183                 DoubleField7 = 234,
184                 DoubleField50 = 2.45
185             };
186         }
187 
CreateRepeatedFieldMessage()188         public static GoogleMessage1 CreateRepeatedFieldMessage()
189         {
190             // Message with a repeated fixed length item collection
191             var message = new GoogleMessage1();
192             for (ulong i = 0; i < 1000; i++)
193             {
194                 message.Field5.Add(i);
195             }
196             return message;
197         }
198 
199         private class SubTest
200         {
201             private readonly IMessage message;
202             private readonly MessageParser parser;
203             private readonly Func<IMessage> factory;
204             private readonly byte[] data;
205             private readonly byte[] multipleMessagesData;
206 
207             private ReadOnlySequence<byte> dataSequence;
208             private ReadOnlySequence<byte> multipleMessagesDataSequence;
209 
SubTest(IMessage message, MessageParser parser, Func<IMessage> factory, int maxMessageCount)210             public SubTest(IMessage message, MessageParser parser, Func<IMessage> factory, int maxMessageCount)
211             {
212                 this.message = message;
213                 this.parser = parser;
214                 this.factory = factory;
215                 this.data = message.ToByteArray();
216                 this.multipleMessagesData = CreateBufferWithMultipleMessages(message, maxMessageCount);
217                 this.dataSequence = new ReadOnlySequence<byte>(this.data);
218                 this.multipleMessagesDataSequence = new ReadOnlySequence<byte>(this.multipleMessagesData);
219             }
220 
ParseFromByteArray()221             public IMessage ParseFromByteArray() => parser.ParseFrom(data);
222 
ParseFromReadOnlySequence()223             public IMessage ParseFromReadOnlySequence() => parser.ParseFrom(dataSequence);
224 
ParseDelimitedMessagesFromByteArray(int messageCount)225             public void ParseDelimitedMessagesFromByteArray(int messageCount)
226             {
227                 var input = new CodedInputStream(multipleMessagesData);
228                 for (int i = 0; i < messageCount; i++)
229                 {
230                     var msg = factory();
231                     input.ReadMessage(msg);
232                 }
233             }
234 
ParseDelimitedMessagesFromReadOnlySequence(int messageCount)235             public void ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
236             {
237                 ParseContext.Initialize(multipleMessagesDataSequence, out ParseContext ctx);
238                 for (int i = 0; i < messageCount; i++)
239                 {
240                     var msg = factory();
241                     ctx.ReadMessage(msg);
242                 }
243             }
244 
CreateBufferWithMultipleMessages(IMessage msg, int msgCount)245             private static byte[] CreateBufferWithMultipleMessages(IMessage msg, int msgCount)
246             {
247                 var ms = new MemoryStream();
248                 var cos = new CodedOutputStream(ms);
249                 for (int i = 0; i < msgCount; i++)
250                 {
251                     cos.WriteMessage(msg);
252                 }
253                 cos.Flush();
254                 return ms.ToArray();
255             }
256         }
257     }
258 }
259