blob: 7a9370e434ba90ec1cdbf41fda6659be25b3d0d1 [file] [log] [blame]
Jon Skeet0aac0e42009-09-09 18:48:02 +01001#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
Jon Skeetad748532009-06-25 16:55:58 +01003// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
6// http://code.google.com/p/protobuf/
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11//
12// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
21//
22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet0aac0e42009-09-09 18:48:02 +010033#endregion
34
Jon Skeetad748532009-06-25 16:55:58 +010035using System;
Jon Skeet8f8186a2009-01-16 10:57:40 +000036using System.Diagnostics;
37using System.IO;
Jon Skeet8f8186a2009-01-16 10:57:40 +000038
Jon Skeeta3767342009-01-16 18:06:56 +000039namespace Google.ProtocolBuffers.ProtoBench
40{
Jon Skeet8f8186a2009-01-16 10:57:40 +000041 /// <summary>
42 /// Simple benchmarking of arbitrary messages.
43 /// </summary>
44 public sealed class Program {
45
46 private static readonly TimeSpan MinSampleTime = TimeSpan.FromSeconds(2);
47 private static readonly TimeSpan TargetTime = TimeSpan.FromSeconds(30);
48
49 // Avoid a .NET 3.5 dependency
50 delegate void Action();
51
52 public static int Main(string[] args) {
Jon Skeet79c72a92009-01-16 13:19:31 +000053 if (args.Length < 2 || (args.Length % 2) != 0) {
54 Console.Error.WriteLine("Usage: ProtoBench <descriptor type name> <input data>");
Jon Skeet8f8186a2009-01-16 10:57:40 +000055 Console.Error.WriteLine("The descriptor type name is the fully-qualified message name,");
56 Console.Error.WriteLine("including assembly - e.g. Google.ProtocolBuffers.BenchmarkProtos.Message1,ProtoBench");
Jon Skeet79c72a92009-01-16 13:19:31 +000057 Console.Error.WriteLine("(You can specify multiple pairs of descriptor type name and input data.)");
Jon Skeet8f8186a2009-01-16 10:57:40 +000058 return 1;
59 }
Jon Skeet79c72a92009-01-16 13:19:31 +000060 bool success = true;
61 for (int i = 0; i < args.Length; i += 2) {
62 success &= RunTest(args[i], args[i + 1]);
63 }
64 return success ? 0 : 1;
65 }
66
67 /// <summary>
68 /// Runs a single test. Error messages are displayed to Console.Error, and the return value indicates
69 /// general success/failure.
70 /// </summary>
71 public static bool RunTest(string typeName, string file) {
72 Console.WriteLine("Benchmarking {0} with file {1}", typeName, file);
Jon Skeet8f8186a2009-01-16 10:57:40 +000073 IMessage defaultMessage;
74 try {
Jon Skeet79c72a92009-01-16 13:19:31 +000075 defaultMessage = MessageUtil.GetDefaultMessage(typeName);
Jon Skeet8f8186a2009-01-16 10:57:40 +000076 } catch (ArgumentException e) {
77 Console.Error.WriteLine(e.Message);
Jon Skeet79c72a92009-01-16 13:19:31 +000078 return false;
Jon Skeet8f8186a2009-01-16 10:57:40 +000079 }
80 try {
Jon Skeet79c72a92009-01-16 13:19:31 +000081 byte[] inputData = File.ReadAllBytes(file);
82 MemoryStream inputStream = new MemoryStream(inputData);
Jon Skeet8f8186a2009-01-16 10:57:40 +000083 ByteString inputString = ByteString.CopyFrom(inputData);
84 IMessage sampleMessage = defaultMessage.WeakCreateBuilderForType().WeakMergeFrom(inputString).WeakBuild();
Jon Skeet8f8186a2009-01-16 10:57:40 +000085 Benchmark("Serialize to byte string", inputData.Length, () => sampleMessage.ToByteString());
86 Benchmark("Serialize to byte array", inputData.Length, () => sampleMessage.ToByteArray());
87 Benchmark("Serialize to memory stream", inputData.Length, () => sampleMessage.WriteTo(new MemoryStream()));
Jon Skeeta3767342009-01-16 18:06:56 +000088 Benchmark("Deserialize from byte string", inputData.Length,
89 () => defaultMessage.WeakCreateBuilderForType()
90 .WeakMergeFrom(inputString)
91 .WeakBuild()
Jon Skeet79c72a92009-01-16 13:19:31 +000092 );
Jon Skeeta3767342009-01-16 18:06:56 +000093 Benchmark("Deserialize from byte array", inputData.Length,
94 () => defaultMessage.WeakCreateBuilderForType()
95 .WeakMergeFrom(CodedInputStream.CreateInstance(inputData))
96 .WeakBuild()
Jon Skeet8f8186a2009-01-16 10:57:40 +000097 );
Jon Skeeta3767342009-01-16 18:06:56 +000098 Benchmark("Deserialize from memory stream", inputData.Length, () => {
99 inputStream.Position = 0;
Jon Skeet8f8186a2009-01-16 10:57:40 +0000100 defaultMessage.WeakCreateBuilderForType()
Jon Skeeta3767342009-01-16 18:06:56 +0000101 .WeakMergeFrom(CodedInputStream.CreateInstance(inputStream))
102 .WeakBuild();
103 });
Jon Skeet75f42682009-03-05 14:22:28 +0000104 Console.WriteLine();
Jon Skeet79c72a92009-01-16 13:19:31 +0000105 return true;
Jon Skeet8f8186a2009-01-16 10:57:40 +0000106 } catch (Exception e) {
107 Console.Error.WriteLine("Error: {0}", e.Message);
108 Console.Error.WriteLine();
109 Console.Error.WriteLine("Detailed exception information: {0}", e);
Jon Skeet79c72a92009-01-16 13:19:31 +0000110 return false;
Jon Skeet8f8186a2009-01-16 10:57:40 +0000111 }
112 }
113
Jon Skeet79c72a92009-01-16 13:19:31 +0000114 private static void Benchmark(string name, long dataSize, Action action) {
Jon Skeet8f8186a2009-01-16 10:57:40 +0000115 // Make sure it's JITted
116 action();
117 // Run it progressively more times until we've got a reasonable sample
118
119 int iterations = 1;
120 TimeSpan elapsed = TimeAction(action, iterations);
121 while (elapsed < MinSampleTime) {
122 iterations *= 2;
123 elapsed = TimeAction(action, iterations);
124 }
125 // Upscale the sample to the target time. Do this in floating point arithmetic
126 // to avoid overflow issues.
127 iterations = (int) ((TargetTime.Ticks / (double)elapsed.Ticks) * iterations);
128 elapsed = TimeAction(action, iterations);
129 Console.WriteLine("{0}: {1} iterations in {2:f3}s; {3:f3}MB/s",
Jon Skeeta3767342009-01-16 18:06:56 +0000130 name, iterations, elapsed.TotalSeconds,
131 (iterations * dataSize) / (elapsed.TotalSeconds * 1024 * 1024));
Jon Skeet8f8186a2009-01-16 10:57:40 +0000132 }
133
134 private static TimeSpan TimeAction(Action action, int iterations) {
Jon Skeet75f42682009-03-05 14:22:28 +0000135 GC.Collect();
136 GC.WaitForPendingFinalizers();
Jon Skeet8f8186a2009-01-16 10:57:40 +0000137 Stopwatch sw = Stopwatch.StartNew();
138 for (int i = 0; i < iterations; i++) {
139 action();
140 }
141 sw.Stop();
142 return sw.Elapsed;
143 }
144 }
Jon Skeeta3767342009-01-16 18:06:56 +0000145}