ParseMessagesBenchmark.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. namespace Google.Protobuf.Benchmarks
  40. {
  41. /// <summary>
  42. /// Benchmark that tests parsing performance for various messages.
  43. /// </summary>
  44. [MemoryDiagnoser]
  45. public class ParseMessagesBenchmark
  46. {
  47. const int MaxMessages = 100;
  48. SubTest manyWrapperFieldsTest = new SubTest(CreateManyWrapperFieldsMessage(), ManyWrapperFieldsMessage.Parser, () => new ManyWrapperFieldsMessage(), MaxMessages);
  49. SubTest manyPrimitiveFieldsTest = new SubTest(CreateManyPrimitiveFieldsMessage(), ManyPrimitiveFieldsMessage.Parser, () => new ManyPrimitiveFieldsMessage(), MaxMessages);
  50. SubTest emptyMessageTest = new SubTest(new Empty(), Empty.Parser, () => new Empty(), MaxMessages);
  51. public IEnumerable<int> MessageCountValues => new[] { 10, 100 };
  52. [GlobalSetup]
  53. public void GlobalSetup()
  54. {
  55. }
  56. [Benchmark]
  57. public IMessage ManyWrapperFieldsMessage_ParseFromByteArray()
  58. {
  59. return manyWrapperFieldsTest.ParseFromByteArray();
  60. }
  61. [Benchmark]
  62. public IMessage ManyWrapperFieldsMessage_ParseFromReadOnlySequence()
  63. {
  64. return manyWrapperFieldsTest.ParseFromReadOnlySequence();
  65. }
  66. [Benchmark]
  67. public IMessage ManyPrimitiveFieldsMessage_ParseFromByteArray()
  68. {
  69. return manyPrimitiveFieldsTest.ParseFromByteArray();
  70. }
  71. [Benchmark]
  72. public IMessage ManyPrimitiveFieldsMessage_ParseFromReadOnlySequence()
  73. {
  74. return manyPrimitiveFieldsTest.ParseFromReadOnlySequence();
  75. }
  76. [Benchmark]
  77. public IMessage EmptyMessage_ParseFromByteArray()
  78. {
  79. return emptyMessageTest.ParseFromByteArray();
  80. }
  81. [Benchmark]
  82. public IMessage EmptyMessage_ParseFromReadOnlySequence()
  83. {
  84. return emptyMessageTest.ParseFromReadOnlySequence();
  85. }
  86. [Benchmark]
  87. [ArgumentsSource(nameof(MessageCountValues))]
  88. public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
  89. {
  90. manyWrapperFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount);
  91. }
  92. [Benchmark]
  93. [ArgumentsSource(nameof(MessageCountValues))]
  94. public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
  95. {
  96. manyWrapperFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
  97. }
  98. [Benchmark]
  99. [ArgumentsSource(nameof(MessageCountValues))]
  100. public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
  101. {
  102. manyPrimitiveFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount);
  103. }
  104. [Benchmark]
  105. [ArgumentsSource(nameof(MessageCountValues))]
  106. public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
  107. {
  108. manyPrimitiveFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
  109. }
  110. private static ManyWrapperFieldsMessage CreateManyWrapperFieldsMessage()
  111. {
  112. // Example data match data of an internal benchmarks
  113. return new ManyWrapperFieldsMessage()
  114. {
  115. Int64Field19 = 123,
  116. Int64Field37 = 1000032,
  117. Int64Field26 = 3453524500,
  118. DoubleField79 = 1.2,
  119. DoubleField25 = 234,
  120. DoubleField9 = 123.3,
  121. DoubleField28 = 23,
  122. DoubleField7 = 234,
  123. DoubleField50 = 2.45
  124. };
  125. }
  126. private static ManyPrimitiveFieldsMessage CreateManyPrimitiveFieldsMessage()
  127. {
  128. // Example data match data of an internal benchmarks
  129. return new ManyPrimitiveFieldsMessage()
  130. {
  131. Int64Field19 = 123,
  132. Int64Field37 = 1000032,
  133. Int64Field26 = 3453524500,
  134. DoubleField79 = 1.2,
  135. DoubleField25 = 234,
  136. DoubleField9 = 123.3,
  137. DoubleField28 = 23,
  138. DoubleField7 = 234,
  139. DoubleField50 = 2.45
  140. };
  141. }
  142. private class SubTest
  143. {
  144. private readonly IMessage message;
  145. private readonly MessageParser parser;
  146. private readonly Func<IMessage> factory;
  147. private readonly byte[] data;
  148. private readonly byte[] multipleMessagesData;
  149. private ReadOnlySequence<byte> dataSequence;
  150. private ReadOnlySequence<byte> multipleMessagesDataSequence;
  151. public SubTest(IMessage message, MessageParser parser, Func<IMessage> factory, int maxMessageCount)
  152. {
  153. this.message = message;
  154. this.parser = parser;
  155. this.factory = factory;
  156. this.data = message.ToByteArray();
  157. this.multipleMessagesData = CreateBufferWithMultipleMessages(message, maxMessageCount);
  158. this.dataSequence = new ReadOnlySequence<byte>(this.data);
  159. this.multipleMessagesDataSequence = new ReadOnlySequence<byte>(this.multipleMessagesData);
  160. }
  161. public IMessage ParseFromByteArray() => parser.ParseFrom(data);
  162. public IMessage ParseFromReadOnlySequence() => parser.ParseFrom(dataSequence);
  163. public void ParseDelimitedMessagesFromByteArray(int messageCount)
  164. {
  165. var input = new CodedInputStream(multipleMessagesData);
  166. for (int i = 0; i < messageCount; i++)
  167. {
  168. var msg = factory();
  169. input.ReadMessage(msg);
  170. }
  171. }
  172. public void ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
  173. {
  174. ParseContext.Initialize(multipleMessagesDataSequence, out ParseContext ctx);
  175. for (int i = 0; i < messageCount; i++)
  176. {
  177. var msg = factory();
  178. ctx.ReadMessage(msg);
  179. }
  180. }
  181. private static byte[] CreateBufferWithMultipleMessages(IMessage msg, int msgCount)
  182. {
  183. var ms = new MemoryStream();
  184. var cos = new CodedOutputStream(ms);
  185. for (int i = 0; i < msgCount; i++)
  186. {
  187. cos.WriteMessage(msg);
  188. }
  189. cos.Flush();
  190. return ms.ToArray();
  191. }
  192. }
  193. }
  194. }