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
45using benchmarks::BenchmarkDataset;
46using google::protobuf::Arena;
47using google::protobuf::Descriptor;
48using google::protobuf::DescriptorPool;
49using google::protobuf::Message;
50using google::protobuf::MessageFactory;
51
52class Fixture : public benchmark::Fixture {
53 public:
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
77class WrappingCounter {
78 public:
79  WrappingCounter(size_t limit) : value_(0), limit_(limit) {}
80
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
94template <class T>
95class ParseNewFixture : public Fixture {
96 public:
97  ParseNewFixture(const BenchmarkDataset& dataset)
98      : Fixture(dataset, "_parse_new") {}
99
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
115template <class T>
116class ParseNewArenaFixture : public Fixture {
117 public:
118  ParseNewArenaFixture(const BenchmarkDataset& dataset)
119      : Fixture(dataset, "_parse_newarena") {}
120
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
138template <class T>
139class ParseReuseFixture : public Fixture {
140 public:
141  ParseReuseFixture(const BenchmarkDataset& dataset)
142      : Fixture(dataset, "_parse_reuse") {}
143
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
159template <class T>
160class SerializeFixture : public Fixture {
161 public:
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
170  ~SerializeFixture() {
171    for (size_t i = 0; i < message_.size(); i++) {
172      delete message_[i];
173    }
174  }
175
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
194std::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
204template <class T>
205void 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
216void 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
240int 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