|  | // Protocol Buffers - Google's data interchange format | 
|  | // Copyright 2008 Google Inc.  All rights reserved. | 
|  | // https://developers.google.com/protocol-buffers/ | 
|  | // | 
|  | // Redistribution and use in source and binary forms, with or without | 
|  | // modification, are permitted provided that the following conditions are | 
|  | // met: | 
|  | // | 
|  | //     * Redistributions of source code must retain the above copyright | 
|  | // notice, this list of conditions and the following disclaimer. | 
|  | //     * Redistributions in binary form must reproduce the above | 
|  | // copyright notice, this list of conditions and the following disclaimer | 
|  | // in the documentation and/or other materials provided with the | 
|  | // distribution. | 
|  | //     * Neither the name of Google Inc. nor the names of its | 
|  | // contributors may be used to endorse or promote products derived from | 
|  | // this software without specific prior written permission. | 
|  | // | 
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  |  | 
|  | #include <fstream> | 
|  | #include <iostream> | 
|  | #include "benchmark/benchmark.h" | 
|  | #include "benchmarks.pb.h" | 
|  | #include "datasets/google_message1/proto2/benchmark_message1_proto2.pb.h" | 
|  | #include "datasets/google_message1/proto3/benchmark_message1_proto3.pb.h" | 
|  | #include "datasets/google_message2/benchmark_message2.pb.h" | 
|  | #include "datasets/google_message3/benchmark_message3.pb.h" | 
|  | #include "datasets/google_message4/benchmark_message4.pb.h" | 
|  |  | 
|  |  | 
|  | #define PREFIX "dataset." | 
|  | #define SUFFIX ".pb" | 
|  |  | 
|  | using benchmarks::BenchmarkDataset; | 
|  | using google::protobuf::Arena; | 
|  | using google::protobuf::Descriptor; | 
|  | using google::protobuf::DescriptorPool; | 
|  | using google::protobuf::Message; | 
|  | using google::protobuf::MessageFactory; | 
|  |  | 
|  | class Fixture : public benchmark::Fixture { | 
|  | public: | 
|  | Fixture(const BenchmarkDataset& dataset, const std::string& suffix) { | 
|  | for (int i = 0; i < dataset.payload_size(); i++) { | 
|  | payloads_.push_back(dataset.payload(i)); | 
|  | } | 
|  |  | 
|  | const Descriptor* d = | 
|  | DescriptorPool::generated_pool()->FindMessageTypeByName( | 
|  | dataset.message_name()); | 
|  |  | 
|  | if (!d) { | 
|  | std::cerr << "Couldn't find message named '" << dataset.message_name() | 
|  | << "\n"; | 
|  | } | 
|  |  | 
|  | prototype_ = MessageFactory::generated_factory()->GetPrototype(d); | 
|  | SetName((dataset.name() + suffix).c_str()); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | std::vector<std::string> payloads_; | 
|  | const Message* prototype_; | 
|  | }; | 
|  |  | 
|  | class WrappingCounter { | 
|  | public: | 
|  | WrappingCounter(size_t limit) : value_(0), limit_(limit) {} | 
|  |  | 
|  | size_t Next() { | 
|  | size_t ret = value_; | 
|  | if (++value_ == limit_) { | 
|  | value_ = 0; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | private: | 
|  | size_t value_; | 
|  | size_t limit_; | 
|  | }; | 
|  |  | 
|  | template <class T> | 
|  | class ParseNewFixture : public Fixture { | 
|  | public: | 
|  | ParseNewFixture(const BenchmarkDataset& dataset) | 
|  | : Fixture(dataset, "_parse_new") {} | 
|  |  | 
|  | virtual void BenchmarkCase(benchmark::State& state) { | 
|  | WrappingCounter i(payloads_.size()); | 
|  | size_t total = 0; | 
|  |  | 
|  | while (state.KeepRunning()) { | 
|  | T m; | 
|  | const std::string& payload = payloads_[i.Next()]; | 
|  | total += payload.size(); | 
|  | m.ParseFromString(payload); | 
|  | } | 
|  |  | 
|  | state.SetBytesProcessed(total); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <class T> | 
|  | class ParseNewArenaFixture : public Fixture { | 
|  | public: | 
|  | ParseNewArenaFixture(const BenchmarkDataset& dataset) | 
|  | : Fixture(dataset, "_parse_newarena") {} | 
|  |  | 
|  | virtual void BenchmarkCase(benchmark::State& state) { | 
|  | WrappingCounter i(payloads_.size()); | 
|  | size_t total = 0; | 
|  | Arena arena; | 
|  |  | 
|  | while (state.KeepRunning()) { | 
|  | arena.Reset(); | 
|  | Message* m = Arena::CreateMessage<T>(&arena); | 
|  | const std::string& payload = payloads_[i.Next()]; | 
|  | total += payload.size(); | 
|  | m->ParseFromString(payload); | 
|  | } | 
|  |  | 
|  | state.SetBytesProcessed(total); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <class T> | 
|  | class ParseReuseFixture : public Fixture { | 
|  | public: | 
|  | ParseReuseFixture(const BenchmarkDataset& dataset) | 
|  | : Fixture(dataset, "_parse_reuse") {} | 
|  |  | 
|  | virtual void BenchmarkCase(benchmark::State& state) { | 
|  | T m; | 
|  | WrappingCounter i(payloads_.size()); | 
|  | size_t total = 0; | 
|  |  | 
|  | while (state.KeepRunning()) { | 
|  | const std::string& payload = payloads_[i.Next()]; | 
|  | total += payload.size(); | 
|  | m.ParseFromString(payload); | 
|  | } | 
|  |  | 
|  | state.SetBytesProcessed(total); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <class T> | 
|  | class SerializeFixture : public Fixture { | 
|  | public: | 
|  | SerializeFixture(const BenchmarkDataset& dataset) | 
|  | : Fixture(dataset, "_serialize") { | 
|  | for (size_t i = 0; i < payloads_.size(); i++) { | 
|  | message_.push_back(new T); | 
|  | message_.back()->ParseFromString(payloads_[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | ~SerializeFixture() { | 
|  | for (size_t i = 0; i < message_.size(); i++) { | 
|  | delete message_[i]; | 
|  | } | 
|  | } | 
|  |  | 
|  | virtual void BenchmarkCase(benchmark::State& state) { | 
|  | size_t total = 0; | 
|  | std::string str; | 
|  | WrappingCounter i(payloads_.size()); | 
|  |  | 
|  | while (state.KeepRunning()) { | 
|  | str.clear(); | 
|  | message_[i.Next()]->SerializeToString(&str); | 
|  | total += str.size(); | 
|  | } | 
|  |  | 
|  | state.SetBytesProcessed(total); | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::vector<T*> message_; | 
|  | }; | 
|  |  | 
|  | std::string ReadFile(const std::string& name) { | 
|  | std::ifstream file(name.c_str()); | 
|  | GOOGLE_CHECK(file.is_open()) << "Couldn't find file '" << name << | 
|  | "', please make sure you are running " | 
|  | "this command from the benchmarks/ " | 
|  | "directory.\n"; | 
|  | return std::string((std::istreambuf_iterator<char>(file)), | 
|  | std::istreambuf_iterator<char>()); | 
|  | } | 
|  |  | 
|  | template <class T> | 
|  | void RegisterBenchmarksForType(const BenchmarkDataset& dataset) { | 
|  | ::benchmark::internal::RegisterBenchmarkInternal( | 
|  | new ParseNewFixture<T>(dataset)); | 
|  | ::benchmark::internal::RegisterBenchmarkInternal( | 
|  | new ParseReuseFixture<T>(dataset)); | 
|  | ::benchmark::internal::RegisterBenchmarkInternal( | 
|  | new ParseNewArenaFixture<T>(dataset)); | 
|  | ::benchmark::internal::RegisterBenchmarkInternal( | 
|  | new SerializeFixture<T>(dataset)); | 
|  | } | 
|  |  | 
|  | void RegisterBenchmarks(const std::string& dataset_bytes) { | 
|  | BenchmarkDataset dataset; | 
|  | GOOGLE_CHECK(dataset.ParseFromString(dataset_bytes)); | 
|  |  | 
|  | if (dataset.message_name() == "benchmarks.proto3.GoogleMessage1") { | 
|  | RegisterBenchmarksForType<benchmarks::proto3::GoogleMessage1>(dataset); | 
|  | } else if (dataset.message_name() == "benchmarks.proto2.GoogleMessage1") { | 
|  | RegisterBenchmarksForType<benchmarks::proto2::GoogleMessage1>(dataset); | 
|  | } else if (dataset.message_name() == "benchmarks.proto2.GoogleMessage2") { | 
|  | RegisterBenchmarksForType<benchmarks::proto2::GoogleMessage2>(dataset); | 
|  | } else if (dataset.message_name() == | 
|  | "benchmarks.google_message3.GoogleMessage3") { | 
|  | RegisterBenchmarksForType | 
|  | <benchmarks::google_message3::GoogleMessage3>(dataset); | 
|  | } else if (dataset.message_name() == | 
|  | "benchmarks.google_message4.GoogleMessage4") { | 
|  | RegisterBenchmarksForType | 
|  | <benchmarks::google_message4::GoogleMessage4>(dataset); | 
|  | } else { | 
|  | std::cerr << "Unknown message type: " << dataset.message_name(); | 
|  | exit(1); | 
|  | } | 
|  | } | 
|  |  | 
|  | int main(int argc, char *argv[]) { | 
|  | ::benchmark::Initialize(&argc, argv); | 
|  | if (argc == 1) { | 
|  | std::cerr << "Usage: ./cpp-benchmark <input data>" << std::endl; | 
|  | std::cerr << "input data is in the format of \"benchmarks.proto\"" | 
|  | << std::endl; | 
|  | return 1; | 
|  | } else { | 
|  | for (int i = 1; i < argc; i++) { | 
|  | RegisterBenchmarks(ReadFile(argv[i])); | 
|  | } | 
|  | } | 
|  |  | 
|  | ::benchmark::RunSpecifiedBenchmarks(); | 
|  | } |