ParseMessagesBenchmark.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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. using BenchmarkDotNet.Attributes;
  33. using System;
  34. using System.Collections.Generic;
  35. using System.IO;
  36. using System.Linq;
  37. using System.Buffers;
  38. using Google.Protobuf.WellKnownTypes;
  39. using Benchmarks.Proto3;
  40. namespace Google.Protobuf.Benchmarks
  41. {
  42. /// <summary>
  43. /// Benchmark that tests parsing performance for various messages.
  44. /// </summary>
  45. [MemoryDiagnoser]
  46. public class ParseMessagesBenchmark
  47. {
  48. const int MaxMessages = 100;
  49. SubTest manyWrapperFieldsTest = new SubTest(CreateManyWrapperFieldsMessage(), ManyWrapperFieldsMessage.Parser, () => new ManyWrapperFieldsMessage(), MaxMessages);
  50. SubTest manyPrimitiveFieldsTest = new SubTest(CreateManyPrimitiveFieldsMessage(), ManyPrimitiveFieldsMessage.Parser, () => new ManyPrimitiveFieldsMessage(), MaxMessages);
  51. SubTest repeatedFieldTest = new SubTest(CreateRepeatedFieldMessage(), GoogleMessage1.Parser, () => new GoogleMessage1(), MaxMessages);
  52. SubTest emptyMessageTest = new SubTest(new Empty(), Empty.Parser, () => new Empty(), MaxMessages);
  53. public IEnumerable<int> MessageCountValues => new[] { 10, 100 };
  54. [GlobalSetup]
  55. public void GlobalSetup()
  56. {
  57. }
  58. [Benchmark]
  59. public IMessage ManyWrapperFieldsMessage_ParseFromByteArray()
  60. {
  61. return manyWrapperFieldsTest.ParseFromByteArray();
  62. }
  63. [Benchmark]
  64. public IMessage ManyWrapperFieldsMessage_ParseFromReadOnlySequence()
  65. {
  66. return manyWrapperFieldsTest.ParseFromReadOnlySequence();
  67. }
  68. [Benchmark]
  69. public IMessage ManyPrimitiveFieldsMessage_ParseFromByteArray()
  70. {
  71. return manyPrimitiveFieldsTest.ParseFromByteArray();
  72. }
  73. [Benchmark]
  74. public IMessage ManyPrimitiveFieldsMessage_ParseFromReadOnlySequence()
  75. {
  76. return manyPrimitiveFieldsTest.ParseFromReadOnlySequence();
  77. }
  78. [Benchmark]
  79. public IMessage RepeatedFieldMessage_ParseFromByteArray()
  80. {
  81. return repeatedFieldTest.ParseFromByteArray();
  82. }
  83. [Benchmark]
  84. public IMessage RepeatedFieldMessage_ParseFromReadOnlySequence()
  85. {
  86. return repeatedFieldTest.ParseFromReadOnlySequence();
  87. }
  88. [Benchmark]
  89. public IMessage EmptyMessage_ParseFromByteArray()
  90. {
  91. return emptyMessageTest.ParseFromByteArray();
  92. }
  93. [Benchmark]
  94. public IMessage EmptyMessage_ParseFromReadOnlySequence()
  95. {
  96. return emptyMessageTest.ParseFromReadOnlySequence();
  97. }
  98. [Benchmark]
  99. [ArgumentsSource(nameof(MessageCountValues))]
  100. public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
  101. {
  102. manyWrapperFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount);
  103. }
  104. [Benchmark]
  105. [ArgumentsSource(nameof(MessageCountValues))]
  106. public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
  107. {
  108. manyWrapperFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
  109. }
  110. [Benchmark]
  111. [ArgumentsSource(nameof(MessageCountValues))]
  112. public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
  113. {
  114. manyPrimitiveFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount);
  115. }
  116. [Benchmark]
  117. [ArgumentsSource(nameof(MessageCountValues))]
  118. public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
  119. {
  120. manyPrimitiveFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
  121. }
  122. [Benchmark]
  123. [ArgumentsSource(nameof(MessageCountValues))]
  124. public void RepeatedFieldMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
  125. {
  126. repeatedFieldTest.ParseDelimitedMessagesFromByteArray(messageCount);
  127. }
  128. [Benchmark]
  129. [ArgumentsSource(nameof(MessageCountValues))]
  130. public void RepeatedFieldMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
  131. {
  132. repeatedFieldTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
  133. }
  134. public static ManyWrapperFieldsMessage CreateManyWrapperFieldsMessage()
  135. {
  136. // Example data match data of an internal benchmarks
  137. return new ManyWrapperFieldsMessage()
  138. {
  139. Int64Field19 = 123,
  140. Int64Field37 = 1000032,
  141. Int64Field26 = 3453524500,
  142. DoubleField79 = 1.2,
  143. DoubleField25 = 234,
  144. DoubleField9 = 123.3,
  145. DoubleField28 = 23,
  146. DoubleField7 = 234,
  147. DoubleField50 = 2.45
  148. };
  149. }
  150. public static ManyPrimitiveFieldsMessage CreateManyPrimitiveFieldsMessage()
  151. {
  152. // Example data match data of an internal benchmarks
  153. return new ManyPrimitiveFieldsMessage()
  154. {
  155. Int64Field19 = 123,
  156. Int64Field37 = 1000032,
  157. Int64Field26 = 3453524500,
  158. DoubleField79 = 1.2,
  159. DoubleField25 = 234,
  160. DoubleField9 = 123.3,
  161. DoubleField28 = 23,
  162. DoubleField7 = 234,
  163. DoubleField50 = 2.45
  164. };
  165. }
  166. public static GoogleMessage1 CreateRepeatedFieldMessage()
  167. {
  168. // Message with a repeated fixed length item collection
  169. var message = new GoogleMessage1();
  170. for (ulong i = 0; i < 1000; i++)
  171. {
  172. message.Field5.Add(i);
  173. }
  174. return message;
  175. }
  176. private class SubTest
  177. {
  178. private readonly IMessage message;
  179. private readonly MessageParser parser;
  180. private readonly Func<IMessage> factory;
  181. private readonly byte[] data;
  182. private readonly byte[] multipleMessagesData;
  183. private ReadOnlySequence<byte> dataSequence;
  184. private ReadOnlySequence<byte> multipleMessagesDataSequence;
  185. public SubTest(IMessage message, MessageParser parser, Func<IMessage> factory, int maxMessageCount)
  186. {
  187. this.message = message;
  188. this.parser = parser;
  189. this.factory = factory;
  190. this.data = message.ToByteArray();
  191. this.multipleMessagesData = CreateBufferWithMultipleMessages(message, maxMessageCount);
  192. this.dataSequence = new ReadOnlySequence<byte>(this.data);
  193. this.multipleMessagesDataSequence = new ReadOnlySequence<byte>(this.multipleMessagesData);
  194. }
  195. public IMessage ParseFromByteArray() => parser.ParseFrom(data);
  196. public IMessage ParseFromReadOnlySequence() => parser.ParseFrom(dataSequence);
  197. public void ParseDelimitedMessagesFromByteArray(int messageCount)
  198. {
  199. var input = new CodedInputStream(multipleMessagesData);
  200. for (int i = 0; i < messageCount; i++)
  201. {
  202. var msg = factory();
  203. input.ReadMessage(msg);
  204. }
  205. }
  206. public void ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
  207. {
  208. ParseContext.Initialize(multipleMessagesDataSequence, out ParseContext ctx);
  209. for (int i = 0; i < messageCount; i++)
  210. {
  211. var msg = factory();
  212. ctx.ReadMessage(msg);
  213. }
  214. }
  215. private static byte[] CreateBufferWithMultipleMessages(IMessage msg, int msgCount)
  216. {
  217. var ms = new MemoryStream();
  218. var cos = new CodedOutputStream(ms);
  219. for (int i = 0; i < msgCount; i++)
  220. {
  221. cos.WriteMessage(msg);
  222. }
  223. cos.Flush();
  224. return ms.ToArray();
  225. }
  226. }
  227. }
  228. }