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