1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include <fstream>
32 #include <iostream>
33 #include "benchmark/benchmark.h"
34 #include "benchmarks.pb.h"
35 #include "datasets/google_message1/proto2/benchmark_message1_proto2.pb.h"
36 #include "datasets/google_message1/proto3/benchmark_message1_proto3.pb.h"
37 #include "datasets/google_message2/benchmark_message2.pb.h"
38 #include "datasets/google_message3/benchmark_message3.pb.h"
39 #include "datasets/google_message4/benchmark_message4.pb.h"
40 
41 
42 #define PREFIX "dataset."
43 #define SUFFIX ".pb"
44 
45 using benchmarks::BenchmarkDataset;
46 using google::protobuf::Arena;
47 using google::protobuf::Descriptor;
48 using google::protobuf::DescriptorPool;
49 using google::protobuf::Message;
50 using google::protobuf::MessageFactory;
51 
52 class Fixture : public benchmark::Fixture {
53  public:
Fixture(const BenchmarkDataset & dataset,const std::string & suffix)54   Fixture(const BenchmarkDataset& dataset, const std::string& suffix) {
55     for (int i = 0; i < dataset.payload_size(); i++) {
56       payloads_.push_back(dataset.payload(i));
57     }
58 
59     const Descriptor* d =
60         DescriptorPool::generated_pool()->FindMessageTypeByName(
61             dataset.message_name());
62 
63     if (!d) {
64       std::cerr << "Couldn't find message named '" << dataset.message_name()
65                 << "\n";
66     }
67 
68     prototype_ = MessageFactory::generated_factory()->GetPrototype(d);
69     SetName((dataset.name() + suffix).c_str());
70   }
71 
72  protected:
73   std::vector<std::string> payloads_;
74   const Message* prototype_;
75 };
76 
77 class WrappingCounter {
78  public:
WrappingCounter(size_t limit)79   WrappingCounter(size_t limit) : value_(0), limit_(limit) {}
80 
Next()81   size_t Next() {
82     size_t ret = value_;
83     if (++value_ == limit_) {
84       value_ = 0;
85     }
86     return ret;
87   }
88 
89  private:
90   size_t value_;
91   size_t limit_;
92 };
93 
94 template <class T>
95 class ParseNewFixture : public Fixture {
96  public:
ParseNewFixture(const BenchmarkDataset & dataset)97   ParseNewFixture(const BenchmarkDataset& dataset)
98       : Fixture(dataset, "_parse_new") {}
99 
BenchmarkCase(benchmark::State & state)100   virtual void BenchmarkCase(benchmark::State& state) {
101     WrappingCounter i(payloads_.size());
102     size_t total = 0;
103 
104     while (state.KeepRunning()) {
105       T m;
106       const std::string& payload = payloads_[i.Next()];
107       total += payload.size();
108       m.ParseFromString(payload);
109     }
110 
111     state.SetBytesProcessed(total);
112   }
113 };
114 
115 template <class T>
116 class ParseNewArenaFixture : public Fixture {
117  public:
ParseNewArenaFixture(const BenchmarkDataset & dataset)118   ParseNewArenaFixture(const BenchmarkDataset& dataset)
119       : Fixture(dataset, "_parse_newarena") {}
120 
BenchmarkCase(benchmark::State & state)121   virtual void BenchmarkCase(benchmark::State& state) {
122     WrappingCounter i(payloads_.size());
123     size_t total = 0;
124     Arena arena;
125 
126     while (state.KeepRunning()) {
127       arena.Reset();
128       Message* m = Arena::CreateMessage<T>(&arena);
129       const std::string& payload = payloads_[i.Next()];
130       total += payload.size();
131       m->ParseFromString(payload);
132     }
133 
134     state.SetBytesProcessed(total);
135   }
136 };
137 
138 template <class T>
139 class ParseReuseFixture : public Fixture {
140  public:
ParseReuseFixture(const BenchmarkDataset & dataset)141   ParseReuseFixture(const BenchmarkDataset& dataset)
142       : Fixture(dataset, "_parse_reuse") {}
143 
BenchmarkCase(benchmark::State & state)144   virtual void BenchmarkCase(benchmark::State& state) {
145     T m;
146     WrappingCounter i(payloads_.size());
147     size_t total = 0;
148 
149     while (state.KeepRunning()) {
150       const std::string& payload = payloads_[i.Next()];
151       total += payload.size();
152       m.ParseFromString(payload);
153     }
154 
155     state.SetBytesProcessed(total);
156   }
157 };
158 
159 template <class T>
160 class SerializeFixture : public Fixture {
161  public:
SerializeFixture(const BenchmarkDataset & dataset)162   SerializeFixture(const BenchmarkDataset& dataset)
163       : Fixture(dataset, "_serialize") {
164     for (size_t i = 0; i < payloads_.size(); i++) {
165       message_.push_back(new T);
166       message_.back()->ParseFromString(payloads_[i]);
167     }
168   }
169 
~SerializeFixture()170   ~SerializeFixture() {
171     for (size_t i = 0; i < message_.size(); i++) {
172       delete message_[i];
173     }
174   }
175 
BenchmarkCase(benchmark::State & state)176   virtual void BenchmarkCase(benchmark::State& state) {
177     size_t total = 0;
178     std::string str;
179     WrappingCounter i(payloads_.size());
180 
181     while (state.KeepRunning()) {
182       str.clear();
183       message_[i.Next()]->SerializeToString(&str);
184       total += str.size();
185     }
186 
187     state.SetBytesProcessed(total);
188   }
189 
190  private:
191   std::vector<T*> message_;
192 };
193 
ReadFile(const std::string & name)194 std::string ReadFile(const std::string& name) {
195   std::ifstream file(name.c_str());
196   GOOGLE_CHECK(file.is_open()) << "Couldn't find file '" << name <<
197                                   "', please make sure you are running "
198                                   "this command from the benchmarks/ "
199                                   "directory.\n";
200   return std::string((std::istreambuf_iterator<char>(file)),
201                      std::istreambuf_iterator<char>());
202 }
203 
204 template <class T>
RegisterBenchmarksForType(const BenchmarkDataset & dataset)205 void RegisterBenchmarksForType(const BenchmarkDataset& dataset) {
206   ::benchmark::internal::RegisterBenchmarkInternal(
207       new ParseNewFixture<T>(dataset));
208   ::benchmark::internal::RegisterBenchmarkInternal(
209       new ParseReuseFixture<T>(dataset));
210   ::benchmark::internal::RegisterBenchmarkInternal(
211       new ParseNewArenaFixture<T>(dataset));
212   ::benchmark::internal::RegisterBenchmarkInternal(
213       new SerializeFixture<T>(dataset));
214 }
215 
RegisterBenchmarks(const std::string & dataset_bytes)216 void RegisterBenchmarks(const std::string& dataset_bytes) {
217   BenchmarkDataset dataset;
218   GOOGLE_CHECK(dataset.ParseFromString(dataset_bytes));
219 
220   if (dataset.message_name() == "benchmarks.proto3.GoogleMessage1") {
221     RegisterBenchmarksForType<benchmarks::proto3::GoogleMessage1>(dataset);
222   } else if (dataset.message_name() == "benchmarks.proto2.GoogleMessage1") {
223     RegisterBenchmarksForType<benchmarks::proto2::GoogleMessage1>(dataset);
224   } else if (dataset.message_name() == "benchmarks.proto2.GoogleMessage2") {
225     RegisterBenchmarksForType<benchmarks::proto2::GoogleMessage2>(dataset);
226   } else if (dataset.message_name() ==
227       "benchmarks.google_message3.GoogleMessage3") {
228     RegisterBenchmarksForType
229     <benchmarks::google_message3::GoogleMessage3>(dataset);
230   } else if (dataset.message_name() ==
231       "benchmarks.google_message4.GoogleMessage4") {
232     RegisterBenchmarksForType
233     <benchmarks::google_message4::GoogleMessage4>(dataset);
234   } else {
235     std::cerr << "Unknown message type: " << dataset.message_name();
236     exit(1);
237   }
238 }
239 
main(int argc,char * argv[])240 int main(int argc, char *argv[]) {
241   ::benchmark::Initialize(&argc, argv);
242   if (argc == 1) {
243     std::cerr << "Usage: ./cpp-benchmark <input data>" << std::endl;
244     std::cerr << "input data is in the format of \"benchmarks.proto\""
245         << std::endl;
246     return 1;
247   } else {
248     for (int i = 1; i < argc; i++) {
249       RegisterBenchmarks(ReadFile(argv[i]));
250     }
251   }
252 
253   ::benchmark::RunSpecifiedBenchmarks();
254 }
255