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