Commit 4a32903c authored by Kenton Varda's avatar Kenton Varda

Separate benchmark cases into separate binaries in order to compare binary sizes for each case.

parent 98873d06
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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 "carsales.capnp.h"
#include "capnproto-common.h"
namespace capnproto {
namespace benchmark {
namespace capnp {
template <typename ReaderOrBuilder>
uint64_t carValue(ReaderOrBuilder car) {
// Do not think too hard about realism.
uint64_t result = 0;
result += car.getSeats() * 200;
result += car.getDoors() * 350;
for (auto wheel: car.getWheels()) {
result += wheel.getDiameter() * wheel.getDiameter();
result += wheel.getSnowTires() ? 100 : 0;
}
result += car.getLength() * car.getWidth() * car.getHeight() / 50;
auto engine = car.getEngine();
result += engine.getHorsepower() * 40;
if (engine.getUsesElectric()) {
if (engine.getUsesGas()) {
// hybrid
result += 5000;
} else {
result += 3000;
}
}
result += car.getHasPowerWindows() ? 100 : 0;
result += car.getHasPowerSteering() ? 200 : 0;
result += car.getHasCruiseControl() ? 400 : 0;
result += car.getHasNavSystem() ? 2000 : 0;
result += car.getCupHolders() * 25;
return result;
}
void randomCar(Car::Builder car) {
// Do not think too hard about realism.
static const char* const MAKES[] = { "Toyota", "GM", "Ford", "Honda", "Tesla" };
static const char* const MODELS[] = { "Camry", "Prius", "Volt", "Accord", "Leaf", "Model S" };
car.setMake(MAKES[fastRand(sizeof(MAKES) / sizeof(MAKES[0]))]);
car.setModel(MODELS[fastRand(sizeof(MODELS) / sizeof(MODELS[0]))]);
// TODO: Color_RANGE or something.
car.setColor((Color)fastRand((uint)Color::SILVER + 1));
car.setSeats(2 + fastRand(6));
car.setDoors(2 + fastRand(3));
for (auto wheel: car.initWheels(4)) {
wheel.setDiameter(25 + fastRand(15));
wheel.setAirPressure(30 + fastRandDouble(20));
wheel.setSnowTires(fastRand(16) == 0);
}
car.setLength(170 + fastRand(150));
car.setWidth(48 + fastRand(36));
car.setHeight(54 + fastRand(48));
car.setWeight(car.getLength() * car.getWidth() * car.getHeight() / 200);
auto engine = car.initEngine();
engine.setHorsepower(100 * fastRand(400));
engine.setCylinders(4 + 2 * fastRand(3));
engine.setCc(800 + fastRand(10000));
car.setFuelCapacity(10.0 + fastRandDouble(30.0));
car.setFuelLevel(fastRandDouble(car.getFuelCapacity()));
car.setHasPowerWindows(fastRand(2));
car.setHasPowerSteering(fastRand(2));
car.setHasCruiseControl(fastRand(2));
car.setCupHolders(fastRand(12));
car.setHasNavSystem(fastRand(2));
}
class CarSalesTestCase {
public:
typedef ParkingLot Request;
typedef TotalValue Response;
typedef uint64_t Expectation;
static uint64_t setupRequest(ParkingLot::Builder request) {
uint64_t result = 0;
for (auto car: request.initCars(fastRand(200))) {
randomCar(car);
result += carValue(car);
}
return result;
}
static void handleRequest(ParkingLot::Reader request, TotalValue::Builder response) {
uint64_t result = 0;
for (auto car: request.getCars()) {
result += carValue(car);
}
response.setAmount(result);
}
static inline bool checkResponse(TotalValue::Reader response, uint64_t expected) {
return response.getAmount() == expected;
}
};
} // namespace capnp
} // namespace benchmark
} // namespace capnproto
int main(int argc, char* argv[]) {
return capnproto::benchmark::benchmarkMain<
capnproto::benchmark::capnp::BenchmarkTypes,
capnproto::benchmark::capnp::CarSalesTestCase>(argc, argv);
}
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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 "catrank.capnp.h"
#include "capnproto-common.h"
namespace capnproto {
namespace benchmark {
namespace capnp {
struct ScoredResult {
double score;
SearchResult::Reader result;
ScoredResult() = default;
ScoredResult(double score, SearchResult::Reader result): score(score), result(result) {}
inline bool operator<(const ScoredResult& other) const { return score > other.score; }
};
class CatRankTestCase {
public:
typedef SearchResultList Request;
typedef SearchResultList Response;
typedef int Expectation;
static int setupRequest(SearchResultList::Builder request) {
int count = fastRand(1000);
int goodCount = 0;
auto list = request.initResults(count);
for (int i = 0; i < count; i++) {
SearchResult::Builder result = list[i];
result.setScore(1000 - i);
int urlSize = fastRand(100);
static const char URL_PREFIX[] = "http://example.com/";
auto url = result.initUrl(urlSize + sizeof(URL_PREFIX));
strcpy(url.data(), URL_PREFIX);
char* pos = url.data() + strlen(URL_PREFIX);
for (int j = 0; j < urlSize; j++) {
*pos++ = 'a' + fastRand(26);
}
bool isCat = fastRand(8) == 0;
bool isDog = fastRand(8) == 0;
goodCount += isCat && !isDog;
static std::string snippet;
snippet.clear();
snippet.push_back(' ');
int prefix = fastRand(20);
for (int j = 0; j < prefix; j++) {
snippet.append(WORDS[fastRand(WORDS_COUNT)]);
}
if (isCat) snippet.append("cat ");
if (isDog) snippet.append("dog ");
int suffix = fastRand(20);
for (int j = 0; j < suffix; j++) {
snippet.append(WORDS[fastRand(WORDS_COUNT)]);
}
result.setSnippet(snippet);
}
return goodCount;
}
static inline void handleRequest(SearchResultList::Reader request,
SearchResultList::Builder response) {
std::vector<ScoredResult> scoredResults;
for (auto result: request.getResults()) {
double score = result.getScore();
if (strstr(result.getSnippet().c_str(), " cat ") != nullptr) {
score *= 10000;
}
if (strstr(result.getSnippet().c_str(), " dog ") != nullptr) {
score /= 10000;
}
scoredResults.emplace_back(score, result);
}
std::sort(scoredResults.begin(), scoredResults.end());
auto list = response.initResults(scoredResults.size());
auto iter = list.begin();
for (auto result: scoredResults) {
iter->setScore(result.score);
iter->setUrl(result.result.getUrl());
iter->setSnippet(result.result.getSnippet());
++iter;
}
}
static inline bool checkResponse(SearchResultList::Reader response, int expectedGoodCount) {
int goodCount = 0;
for (auto result: response.getResults()) {
if (result.getScore() > 1001) {
++goodCount;
} else {
break;
}
}
return goodCount == expectedGoodCount;
}
};
} // namespace capnp
} // namespace benchmark
} // namespace capnproto
int main(int argc, char* argv[]) {
return capnproto::benchmark::benchmarkMain<
capnproto::benchmark::capnp::BenchmarkTypes,
capnproto::benchmark::capnp::CatRankTestCase>(argc, argv);
}
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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 "eval.capnp.h"
#include "capnproto-common.h"
namespace capnproto {
namespace benchmark {
namespace capnp {
int32_t makeExpression(Expression::Builder exp, uint depth) {
// TODO: Operation_RANGE or something.
exp.setOp((Operation)(fastRand((int)Operation::MODULUS + 1)));
uint32_t left, right;
if (fastRand(8) < depth) {
exp.setLeftIsValue(true);
left = fastRand(128) + 1;
exp.setLeftValue(left);
} else {
left = makeExpression(exp.initLeftExpression(), depth + 1);
}
if (fastRand(8) < depth) {
exp.setRightIsValue(true);
right = fastRand(128) + 1;
exp.setRightValue(right);
} else {
right = makeExpression(exp.initRightExpression(), depth + 1);
}
switch (exp.getOp()) {
case Operation::ADD:
return left + right;
case Operation::SUBTRACT:
return left - right;
case Operation::MULTIPLY:
return left * right;
case Operation::DIVIDE:
return div(left, right);
case Operation::MODULUS:
return mod(left, right);
}
throw std::logic_error("Can't get here.");
}
int32_t evaluateExpression(Expression::Reader exp) {
int32_t left, right;
if (exp.getLeftIsValue()) {
left = exp.getLeftValue();
} else {
left = evaluateExpression(exp.getLeftExpression());
}
if (exp.getRightIsValue()) {
right = exp.getRightValue();
} else {
right = evaluateExpression(exp.getRightExpression());
}
switch (exp.getOp()) {
case Operation::ADD:
return left + right;
case Operation::SUBTRACT:
return left - right;
case Operation::MULTIPLY:
return left * right;
case Operation::DIVIDE:
return div(left, right);
case Operation::MODULUS:
return mod(left, right);
}
throw std::logic_error("Can't get here.");
}
class ExpressionTestCase {
public:
~ExpressionTestCase() {}
typedef Expression Request;
typedef EvaluationResult Response;
typedef int32_t Expectation;
static inline int32_t setupRequest(Expression::Builder request) {
return makeExpression(request, 0);
}
static inline void handleRequest(Expression::Reader request, EvaluationResult::Builder response) {
response.setValue(evaluateExpression(request));
}
static inline bool checkResponse(EvaluationResult::Reader response, int32_t expected) {
return response.getValue() == expected;
}
};
} // namespace capnp
} // namespace benchmark
} // namespace capnproto
int main(int argc, char* argv[]) {
return capnproto::benchmark::benchmarkMain<
capnproto::benchmark::capnp::BenchmarkTypes,
capnproto::benchmark::capnp::ExpressionTestCase>(argc, argv);
}
......@@ -21,46 +21,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
enum Operation {
add = 0;
subtract = 1;
multiply = 2;
divide = 3;
modulus = 4;
}
struct Expression {
op@0: Operation;
# TODO: Use unions once fully-implemented.
leftIsValue@1: Bool;
leftValue@2: Int32;
leftExpression@3: Expression;
rightIsValue@4: Bool;
rightValue@5: Int32;
rightExpression@6: Expression;
}
struct EvaluationResult {
value@0: Int32;
}
# ========================================================================================
struct SearchResultList {
results@0: List(SearchResult);
}
struct SearchResult {
url@0: Text;
score@1: Float64;
snippet@2: Text;
}
# ========================================================================================
struct ParkingLot {
cars@0: List(Car);
}
......
......@@ -23,42 +23,6 @@
package capnproto.benchmark.protobuf;
enum Operation {
ADD = 0;
SUBTRACT = 1;
MULTIPLY = 2;
DIVIDE = 3;
MODULUS = 4;
}
message Expression {
required Operation op = 1;
optional int32 left_value = 2;
optional Expression left_expression = 3;
optional int32 right_value = 4;
optional Expression right_expression = 5;
}
message EvaluationResult {
required sint32 value = 1;
}
// =======================================================================================
message SearchResultList {
repeated SearchResult result = 1;
}
message SearchResult {
optional string url = 1;
optional double score = 2;
optional string snippet = 3;
}
// =======================================================================================
message ParkingLot {
repeated Car car = 1;
}
......
# Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. 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.
#
# 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.
struct SearchResultList {
results@0: List(SearchResult);
}
struct SearchResult {
url@0: Text;
score@1: Float64;
snippet@2: Text;
}
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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.
package capnproto.benchmark.protobuf;
message SearchResultList {
repeated SearchResult result = 1;
}
message SearchResult {
optional string url = 1;
optional double score = 2;
optional string snippet = 3;
}
......@@ -21,8 +21,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CAPNPROTO_BENCHMARK_BENCHMARK_COMMON_H_
#define CAPNPROTO_BENCHMARK_BENCHMARK_COMMON_H_
#ifndef CAPNPROTO_BENCHMARK_COMMON_H_
#define CAPNPROTO_BENCHMARK_COMMON_H_
#include <unistd.h>
#include <limits>
......@@ -260,33 +260,16 @@ uint64_t doBenchmark3(const std::string& mode, const std::string& reuse,
}
}
template <typename BenchmarkTypes>
template <typename BenchmarkTypes, typename TestCase>
int benchmarkMain(int argc, char* argv[]) {
if (argc != 6) {
fprintf(stderr, "USAGE: %s TEST_CASE MODE REUSE COMPRESSION ITERATION_COUNT\n", argv[0]);
return 1;
}
uint64_t iters = strtoull(argv[5], nullptr, 0);
uint64_t throughput;
std::string testcase = argv[1];
if (testcase == "eval") {
throughput = doBenchmark3<BenchmarkTypes, typename BenchmarkTypes::ExpressionTestCase>(
argv[2], argv[3], argv[4], iters);
} else if (testcase == "catrank") {
throughput = doBenchmark3<BenchmarkTypes, typename BenchmarkTypes::CatRankTestCase>(
argv[2], argv[3], argv[4], iters);
} else if (testcase == "carsales") {
throughput = doBenchmark3<BenchmarkTypes, typename BenchmarkTypes::CarSalesTestCase>(
argv[2], argv[3], argv[4], iters);
} else {
fprintf(stderr, "Unknown test case: %s\n", testcase.c_str());
if (argc != 5) {
fprintf(stderr, "USAGE: %s MODE REUSE COMPRESSION ITERATION_COUNT\n", argv[0]);
return 1;
}
fprintf(stdout, "%llu", (long long unsigned int)throughput);
uint64_t iters = strtoull(argv[4], nullptr, 0);
uint64_t throughput = doBenchmark3<BenchmarkTypes, TestCase>(argv[1], argv[2], argv[3], iters);
fprintf(stdout, "%llu\n", (long long unsigned int)throughput);
return 0;
}
......@@ -294,4 +277,4 @@ int benchmarkMain(int argc, char* argv[]) {
} // namespace capnproto
} // namespace benchmark
#endif // CAPNPROTO_BENCHMARK_BENCHMARK_COMMON_H_
#endif // CAPNPROTO_BENCHMARK_COMMON_H_
# Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. 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.
#
# 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.
enum Operation {
add = 0;
subtract = 1;
multiply = 2;
divide = 3;
modulus = 4;
}
struct Expression {
op@0: Operation;
# TODO: Use unions once fully-implemented.
leftIsValue@1: Bool;
leftValue@2: Int32;
leftExpression@3: Expression;
rightIsValue@4: Bool;
rightValue@5: Int32;
rightExpression@6: Expression;
}
struct EvaluationResult {
value@0: Int32;
}
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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.
package capnproto.benchmark.protobuf;
enum Operation {
ADD = 0;
SUBTRACT = 1;
MULTIPLY = 2;
DIVIDE = 3;
MODULUS = 4;
}
message Expression {
required Operation op = 1;
optional int32 left_value = 2;
optional Expression left_expression = 3;
optional int32 right_value = 4;
optional Expression right_expression = 5;
}
message EvaluationResult {
required sint32 value = 1;
}
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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 "null-common.h"
namespace capnproto {
namespace benchmark {
namespace null {
struct SearchResult {
const char* url;
double score;
const char* snippet;
};
struct ScoredResult {
double score;
const SearchResult* result;
ScoredResult() = default;
ScoredResult(double score, const SearchResult* result): score(score), result(result) {}
inline bool operator<(const ScoredResult& other) const { return score > other.score; }
};
class CatRankTestCase {
public:
typedef List<SearchResult> Request;
typedef List<SearchResult> Response;
typedef int Expectation;
static int setupRequest(List<SearchResult>* request) {
int count = fastRand(1000);
int goodCount = 0;
request->init(count);
for (int i = 0; i < count; i++) {
SearchResult& result = request->items[i];
result.score = 1000 - i;
char* pos = reinterpret_cast<char*>(arenaPos);
result.url = pos;
strcpy(pos, "http://example.com/");
pos += strlen("http://example.com/");
int urlSize = fastRand(100);
for (int j = 0; j < urlSize; j++) {
*pos++ = 'a' + fastRand(26);
}
*pos++ = '\0';
// Retroactively allocate the space we used.
if (allocate<char>(pos - result.url) != result.url) {
throw std::bad_alloc();
}
bool isCat = fastRand(8) == 0;
bool isDog = fastRand(8) == 0;
goodCount += isCat && !isDog;
pos = reinterpret_cast<char*>(arenaPos);
result.snippet = pos;
*pos++ = ' ';
int prefix = fastRand(20);
for (int j = 0; j < prefix; j++) {
const char* word = WORDS[fastRand(WORDS_COUNT)];
size_t len = strlen(word);
memcpy(pos, word, len);
pos += len;
}
if (isCat) {
strcpy(pos, "cat ");
pos += 4;
}
if (isDog) {
strcpy(pos, "dog ");
pos += 4;
}
int suffix = fastRand(20);
for (int j = 0; j < suffix; j++) {
const char* word = WORDS[fastRand(WORDS_COUNT)];
size_t len = strlen(word);
memcpy(pos, word, len);
pos += len;
}
*pos++ = '\0';
// Retroactively allocate the space we used.
if (allocate<char>(pos - result.snippet) != result.snippet) {
throw std::bad_alloc();
}
}
return goodCount;
}
static inline void handleRequest(
const List<SearchResult>& request, List<SearchResult>* response) {
std::vector<ScoredResult> scoredResults;
scoredResults.reserve(request.size);
for (auto& result: request) {
double score = result.score;
if (strstr(result.snippet, " cat ") != nullptr) {
score *= 10000;
}
if (strstr(result.snippet, " dog ") != nullptr) {
score /= 10000;
}
scoredResults.emplace_back(score, &result);
}
std::sort(scoredResults.begin(), scoredResults.end());
response->init(scoredResults.size());
SearchResult* dst = response->items;
for (auto& result: scoredResults) {
dst->url = copyString(result.result->url);
dst->score = result.score;
dst->snippet = copyString(result.result->snippet);
++dst;
}
}
static inline bool checkResponse(
const List<SearchResult>& response, int expectedGoodCount) {
int goodCount = 0;
for (auto& result: response) {
if (result.score > 1001) {
++goodCount;
} else {
break;
}
}
return goodCount == expectedGoodCount;
}
};
} // namespace null
} // namespace benchmark
} // namespace capnproto
int main(int argc, char* argv[]) {
return capnproto::benchmark::benchmarkMain<
capnproto::benchmark::null::BenchmarkTypes,
capnproto::benchmark::null::CatRankTestCase>(argc, argv);
}
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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 "common.h"
namespace capnproto {
namespace benchmark {
namespace null {
uint64_t arena[1024*1024];
uint64_t* arenaPos = arena;
template <typename T>
T* allocate(int count = 1) {
T* result = reinterpret_cast<T*>(arenaPos);
arenaPos += (sizeof(T) * count + 7) / 8;
if (arenaPos > arena + sizeof(arena) / sizeof(arena[0])) {
throw std::bad_alloc();
}
return result;
}
char* copyString(const char* str) {
size_t len = strlen(str);
char* result = allocate<char>(len);
memcpy(result, str, len + 1);
return result;
}
template <typename T>
struct List {
size_t size;
T* items;
inline T* begin() const { return items; }
inline T* end() const { return items + size; }
inline List<T>& init(size_t size) {
this->size = size;
items = allocate<T>(size);
return *this;
}
};
// =======================================================================================
struct SingleUseObjects {
template <typename ObjectType>
struct Object {
struct Reusable {};
struct SingleUse {
ObjectType value;
inline SingleUse(Reusable&) {}
};
};
};
struct ReusableObjects {
template <typename ObjectType>
struct Object {
typedef ObjectType Reusable;
struct SingleUse {
ObjectType& value;
inline SingleUse(Reusable& reusable): value(reusable) {}
};
};
};
// =======================================================================================
template <typename TestCase, typename ReuseStrategy, typename Compression>
struct BenchmarkMethods {
static uint64_t syncClient(int inputFd, int outputFd, uint64_t iters) {
fprintf(stderr, "Null benchmark doesn't do I/O.\n");
exit(1);
}
static uint64_t asyncClientSender(
int outputFd, ProducerConsumerQueue<typename TestCase::Expectation>* expectations,
uint64_t iters) {
fprintf(stderr, "Null benchmark doesn't do I/O.\n");
exit(1);
}
static void asyncClientReceiver(
int inputFd, ProducerConsumerQueue<typename TestCase::Expectation>* expectations,
uint64_t iters) {
fprintf(stderr, "Null benchmark doesn't do I/O.\n");
exit(1);
}
static uint64_t asyncClient(int inputFd, int outputFd, uint64_t iters) {
fprintf(stderr, "Null benchmark doesn't do I/O.\n");
exit(1);
}
static uint64_t server(int inputFd, int outputFd, uint64_t iters) {
fprintf(stderr, "Null benchmark doesn't do I/O.\n");
exit(1);
}
static uint64_t passByObject(uint64_t iters, bool countObjectSize) {
uint64_t throughput = 0;
for (; iters > 0; --iters) {
arenaPos = arena;
typename TestCase::Request request;
typename TestCase::Expectation expected = TestCase::setupRequest(&request);
typename TestCase::Response response;
TestCase::handleRequest(request, &response);
if (!TestCase::checkResponse(response, expected)) {
throw std::logic_error("Incorrect response.");
}
throughput += (arenaPos - arena) * sizeof(arena[0]);
}
return throughput;
}
static uint64_t passByBytes(uint64_t iters) {
fprintf(stderr, "Null benchmark doesn't do I/O.\n");
exit(1);
}
};
struct BenchmarkTypes {
typedef void SnappyCompressed;
typedef void Uncompressed;
typedef void ReusableResources;
typedef void SingleUseResources;
template <typename TestCase, typename ReuseStrategy, typename Compression>
struct BenchmarkMethods: public null::BenchmarkMethods<TestCase, ReuseStrategy, Compression> {};
};
} // namespace null
} // namespace benchmark
} // namespace capnproto
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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 "null-common.h"
namespace capnproto {
namespace benchmark {
namespace null {
enum class Operation {
ADD,
SUBTRACT,
MULTIPLY,
DIVIDE,
MODULUS
};
uint OPERATION_RANGE = static_cast<uint>(Operation::MODULUS) + 1;
struct Expression {
Operation op;
bool leftIsValue;
bool rightIsValue;
union {
int32_t leftValue;
Expression* leftExpression;
};
union {
int32_t rightValue;
Expression* rightExpression;
};
};
int32_t makeExpression(Expression* exp, uint depth) {
exp->op = (Operation)(fastRand(OPERATION_RANGE));
int32_t left, right;
if (fastRand(8) < depth) {
exp->leftIsValue = true;
left = fastRand(128) + 1;
exp->leftValue = left;
} else {
exp->leftIsValue = false;
exp->leftExpression = allocate<Expression>();
left = makeExpression(exp->leftExpression, depth + 1);
}
if (fastRand(8) < depth) {
exp->rightIsValue = true;
right = fastRand(128) + 1;
exp->rightValue = right;
} else {
exp->rightIsValue = false;
exp->rightExpression = allocate<Expression>();
right = makeExpression(exp->rightExpression, depth + 1);
}
switch (exp->op) {
case Operation::ADD:
return left + right;
case Operation::SUBTRACT:
return left - right;
case Operation::MULTIPLY:
return left * right;
case Operation::DIVIDE:
return div(left, right);
case Operation::MODULUS:
return mod(left, right);
}
throw std::logic_error("Can't get here.");
}
int32_t evaluateExpression(const Expression& exp) {
uint32_t left, right;
if (exp.leftIsValue) {
left = exp.leftValue;
} else {
left = evaluateExpression(*exp.leftExpression);
}
if (exp.rightIsValue) {
right = exp.rightValue;
} else {
right = evaluateExpression(*exp.rightExpression);
}
switch (exp.op) {
case Operation::ADD:
return left + right;
case Operation::SUBTRACT:
return left - right;
case Operation::MULTIPLY:
return left * right;
case Operation::DIVIDE:
return div(left, right);
case Operation::MODULUS:
return mod(left, right);
}
throw std::logic_error("Can't get here.");
}
class ExpressionTestCase {
public:
typedef Expression Request;
typedef int32_t Response;
typedef int32_t Expectation;
static inline int32_t setupRequest(Expression* request) {
return makeExpression(request, 0);
}
static inline void handleRequest(const Expression& request, int32_t* response) {
*response = evaluateExpression(request);
}
static inline bool checkResponse(int32_t response, int32_t expected) {
return response == expected;
}
static size_t spaceUsed(const Expression& expression) {
return sizeof(Expression) +
(expression.leftExpression == nullptr ? 0 : spaceUsed(*expression.leftExpression)) +
(expression.rightExpression == nullptr ? 0 : spaceUsed(*expression.rightExpression));
}
};
} // namespace null
} // namespace benchmark
} // namespace capnproto
int main(int argc, char* argv[]) {
return capnproto::benchmark::benchmarkMain<
capnproto::benchmark::null::BenchmarkTypes,
capnproto::benchmark::null::ExpressionTestCase>(argc, argv);
}
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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 "carsales.pb.h"
#include "protobuf-common.h"
namespace capnproto {
namespace benchmark {
namespace protobuf {
uint64_t carValue(const Car& car) {
// Do not think too hard about realism.
uint64_t result = 0;
result += car.seats() * 200;
result += car.doors() * 350;
for (auto& wheel: car.wheel()) {
result += wheel.diameter() * wheel.diameter();
result += wheel.snow_tires() ? 100 : 0;
}
result += car.length() * car.width() * car.height() / 50;
const Engine& engine = car.engine();
result += engine.horsepower() * 40;
if (engine.uses_electric()) {
if (engine.uses_gas()) {
// hybrid
result += 5000;
} else {
result += 3000;
}
}
result += car.has_power_windows() ? 100 : 0;
result += car.has_power_steering() ? 200 : 0;
result += car.has_cruise_control() ? 400 : 0;
result += car.has_nav_system() ? 2000 : 0;
result += car.cup_holders() * 25;
return result;
}
void randomCar(Car* car) {
// Do not think too hard about realism.
static const char* const MAKES[] = { "Toyota", "GM", "Ford", "Honda", "Tesla" };
static const char* const MODELS[] = { "Camry", "Prius", "Volt", "Accord", "Leaf", "Model S" };
car->set_make(MAKES[fastRand(sizeof(MAKES) / sizeof(MAKES[0]))]);
car->set_model(MODELS[fastRand(sizeof(MODELS) / sizeof(MODELS[0]))]);
car->set_color((Color)fastRand(Color_MAX));
car->set_seats(2 + fastRand(6));
car->set_doors(2 + fastRand(3));
for (uint i = 0; i < 4; i++) {
Wheel* wheel = car->add_wheel();
wheel->set_diameter(25 + fastRand(15));
wheel->set_air_pressure(30 + fastRandDouble(20));
wheel->set_snow_tires(fastRand(16) == 0);
}
car->set_length(170 + fastRand(150));
car->set_width(48 + fastRand(36));
car->set_height(54 + fastRand(48));
car->set_weight(car->length() * car->width() * car->height() / 200);
Engine* engine = car->mutable_engine();
engine->set_horsepower(100 * fastRand(400));
engine->set_cylinders(4 + 2 * fastRand(3));
engine->set_cc(800 + fastRand(10000));
car->set_fuel_capacity(10.0 + fastRandDouble(30.0));
car->set_fuel_level(fastRandDouble(car->fuel_capacity()));
car->set_has_power_windows(fastRand(2));
car->set_has_power_steering(fastRand(2));
car->set_has_cruise_control(fastRand(2));
car->set_cup_holders(fastRand(12));
car->set_has_nav_system(fastRand(2));
}
class CarSalesTestCase {
public:
typedef ParkingLot Request;
typedef TotalValue Response;
typedef uint64_t Expectation;
static uint64_t setupRequest(ParkingLot* request) {
uint count = fastRand(200);
uint64_t result = 0;
for (uint i = 0; i < count; i++) {
Car* car = request->add_car();
randomCar(car);
result += carValue(*car);
}
return result;
}
static void handleRequest(const ParkingLot& request, TotalValue* response) {
uint64_t result = 0;
for (auto& car: request.car()) {
result += carValue(car);
}
response->set_amount(result);
}
static inline bool checkResponse(const TotalValue& response, uint64_t expected) {
return response.amount() == expected;
}
};
} // namespace protobuf
} // namespace benchmark
} // namespace capnproto
int main(int argc, char* argv[]) {
return capnproto::benchmark::benchmarkMain<
capnproto::benchmark::protobuf::BenchmarkTypes,
capnproto::benchmark::protobuf::CarSalesTestCase>(argc, argv);
}
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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 "catrank.pb.h"
#include "protobuf-common.h"
namespace capnproto {
namespace benchmark {
namespace protobuf {
struct ScoredResult {
double score;
const SearchResult* result;
ScoredResult() = default;
ScoredResult(double score, const SearchResult* result): score(score), result(result) {}
inline bool operator<(const ScoredResult& other) const { return score > other.score; }
};
class CatRankTestCase {
public:
typedef SearchResultList Request;
typedef SearchResultList Response;
typedef int Expectation;
static int setupRequest(SearchResultList* request) {
int count = fastRand(1000);
int goodCount = 0;
for (int i = 0; i < count; i++) {
SearchResult* result = request->add_result();
result->set_score(1000 - i);
result->set_url("http://example.com/");
std::string* url = result->mutable_url();
int urlSize = fastRand(100);
for (int j = 0; j < urlSize; j++) {
url->push_back('a' + fastRand(26));
}
bool isCat = fastRand(8) == 0;
bool isDog = fastRand(8) == 0;
goodCount += isCat && !isDog;
std::string* snippet = result->mutable_snippet();
snippet->push_back(' ');
int prefix = fastRand(20);
for (int j = 0; j < prefix; j++) {
snippet->append(WORDS[fastRand(WORDS_COUNT)]);
}
if (isCat) snippet->append("cat ");
if (isDog) snippet->append("dog ");
int suffix = fastRand(20);
for (int j = 0; j < suffix; j++) {
snippet->append(WORDS[fastRand(WORDS_COUNT)]);
}
}
return goodCount;
}
static inline void handleRequest(const SearchResultList& request, SearchResultList* response) {
std::vector<ScoredResult> scoredResults;
for (auto& result: request.result()) {
double score = result.score();
if (result.snippet().find(" cat ") != std::string::npos) {
score *= 10000;
}
if (result.snippet().find(" dog ") != std::string::npos) {
score /= 10000;
}
scoredResults.emplace_back(score, &result);
}
std::sort(scoredResults.begin(), scoredResults.end());
for (auto& result: scoredResults) {
SearchResult* out = response->add_result();
out->set_score(result.score);
out->set_url(result.result->url());
out->set_snippet(result.result->snippet());
}
}
static inline bool checkResponse(const SearchResultList& response, int expectedGoodCount) {
int goodCount = 0;
for (auto& result: response.result()) {
if (result.score() > 1001) {
++goodCount;
} else {
break;
}
}
return goodCount == expectedGoodCount;
}
};
} // namespace protobuf
} // namespace benchmark
} // namespace capnproto
int main(int argc, char* argv[]) {
return capnproto::benchmark::benchmarkMain<
capnproto::benchmark::protobuf::BenchmarkTypes,
capnproto::benchmark::protobuf::CatRankTestCase>(argc, argv);
}
......@@ -21,8 +21,7 @@
// (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 "benchmark.pb.h"
#include "benchmark-common.h"
#include "common.h"
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <thread>
#include <snappy/snappy.h>
......@@ -32,299 +31,6 @@ namespace capnproto {
namespace benchmark {
namespace protobuf {
// =======================================================================================
// Test case: Expression evaluation
int32_t makeExpression(Expression* exp, uint depth) {
exp->set_op((Operation)(fastRand(Operation_MAX + 1)));
int32_t left, right;
if (fastRand(8) < depth) {
left = fastRand(128) + 1;
exp->set_left_value(left);
} else {
left = makeExpression(exp->mutable_left_expression(), depth + 1);
}
if (fastRand(8) < depth) {
right = fastRand(128) + 1;
exp->set_right_value(right);
} else {
right = makeExpression(exp->mutable_right_expression(), depth + 1);
}
switch (exp->op()) {
case Operation::ADD:
return left + right;
case Operation::SUBTRACT:
return left - right;
case Operation::MULTIPLY:
return left * right;
case Operation::DIVIDE:
return div(left, right);
case Operation::MODULUS:
return mod(left, right);
}
throw std::logic_error("Can't get here.");
}
int32_t evaluateExpression(const Expression& exp) {
uint32_t left, right;
if (exp.has_left_value()) {
left = exp.left_value();
} else {
left = evaluateExpression(exp.left_expression());
}
if (exp.has_right_value()) {
right = exp.right_value();
} else {
right = evaluateExpression(exp.right_expression());
}
switch (exp.op()) {
case Operation::ADD:
return left + right;
case Operation::SUBTRACT:
return left - right;
case Operation::MULTIPLY:
return left * right;
case Operation::DIVIDE:
return div(left, right);
case Operation::MODULUS:
return mod(left, right);
}
throw std::logic_error("Can't get here.");
}
class ExpressionTestCase {
public:
typedef Expression Request;
typedef EvaluationResult Response;
typedef int32_t Expectation;
static inline int32_t setupRequest(Expression* request) {
return makeExpression(request, 0);
}
static inline void handleRequest(const Expression& request, EvaluationResult* response) {
response->set_value(evaluateExpression(request));
}
static inline bool checkResponse(const EvaluationResult& response, int32_t expected) {
return response.value() == expected;
}
};
// =======================================================================================
// Test case: Cat Rank
//
// The server receives a list of candidate search results with scores. It promotes the ones that
// mention "cat" in their snippet and demotes the ones that mention "dog", sorts the results by
// descending score, and returns.
//
// The promotion multiplier is large enough that all the results mentioning "cat" but not "dog"
// should end up at the front ofthe list, which is how we verify the result.
struct ScoredResult {
double score;
const SearchResult* result;
ScoredResult() = default;
ScoredResult(double score, const SearchResult* result): score(score), result(result) {}
inline bool operator<(const ScoredResult& other) const { return score > other.score; }
};
class CatRankTestCase {
public:
typedef SearchResultList Request;
typedef SearchResultList Response;
typedef int Expectation;
static int setupRequest(SearchResultList* request) {
int count = fastRand(1000);
int goodCount = 0;
for (int i = 0; i < count; i++) {
SearchResult* result = request->add_result();
result->set_score(1000 - i);
result->set_url("http://example.com/");
std::string* url = result->mutable_url();
int urlSize = fastRand(100);
for (int j = 0; j < urlSize; j++) {
url->push_back('a' + fastRand(26));
}
bool isCat = fastRand(8) == 0;
bool isDog = fastRand(8) == 0;
goodCount += isCat && !isDog;
std::string* snippet = result->mutable_snippet();
snippet->push_back(' ');
int prefix = fastRand(20);
for (int j = 0; j < prefix; j++) {
snippet->append(WORDS[fastRand(WORDS_COUNT)]);
}
if (isCat) snippet->append("cat ");
if (isDog) snippet->append("dog ");
int suffix = fastRand(20);
for (int j = 0; j < suffix; j++) {
snippet->append(WORDS[fastRand(WORDS_COUNT)]);
}
}
return goodCount;
}
static inline void handleRequest(const SearchResultList& request, SearchResultList* response) {
std::vector<ScoredResult> scoredResults;
for (auto& result: request.result()) {
double score = result.score();
if (result.snippet().find(" cat ") != std::string::npos) {
score *= 10000;
}
if (result.snippet().find(" dog ") != std::string::npos) {
score /= 10000;
}
scoredResults.emplace_back(score, &result);
}
std::sort(scoredResults.begin(), scoredResults.end());
for (auto& result: scoredResults) {
SearchResult* out = response->add_result();
out->set_score(result.score);
out->set_url(result.result->url());
out->set_snippet(result.result->snippet());
}
}
static inline bool checkResponse(const SearchResultList& response, int expectedGoodCount) {
int goodCount = 0;
for (auto& result: response.result()) {
if (result.score() > 1001) {
++goodCount;
} else {
break;
}
}
return goodCount == expectedGoodCount;
}
};
// =======================================================================================
// Test case: Car Sales
//
// We have a parking lot full of cars and we want to know how much they are worth.
uint64_t carValue(const Car& car) {
// Do not think too hard about realism.
uint64_t result = 0;
result += car.seats() * 200;
result += car.doors() * 350;
for (auto& wheel: car.wheel()) {
result += wheel.diameter() * wheel.diameter();
result += wheel.snow_tires() ? 100 : 0;
}
result += car.length() * car.width() * car.height() / 50;
const Engine& engine = car.engine();
result += engine.horsepower() * 40;
if (engine.uses_electric()) {
if (engine.uses_gas()) {
// hybrid
result += 5000;
} else {
result += 3000;
}
}
result += car.has_power_windows() ? 100 : 0;
result += car.has_power_steering() ? 200 : 0;
result += car.has_cruise_control() ? 400 : 0;
result += car.has_nav_system() ? 2000 : 0;
result += car.cup_holders() * 25;
return result;
}
void randomCar(Car* car) {
// Do not think too hard about realism.
static const char* const MAKES[] = { "Toyota", "GM", "Ford", "Honda", "Tesla" };
static const char* const MODELS[] = { "Camry", "Prius", "Volt", "Accord", "Leaf", "Model S" };
car->set_make(MAKES[fastRand(sizeof(MAKES) / sizeof(MAKES[0]))]);
car->set_model(MODELS[fastRand(sizeof(MODELS) / sizeof(MODELS[0]))]);
car->set_color((Color)fastRand(Color_MAX));
car->set_seats(2 + fastRand(6));
car->set_doors(2 + fastRand(3));
for (uint i = 0; i < 4; i++) {
Wheel* wheel = car->add_wheel();
wheel->set_diameter(25 + fastRand(15));
wheel->set_air_pressure(30 + fastRandDouble(20));
wheel->set_snow_tires(fastRand(16) == 0);
}
car->set_length(170 + fastRand(150));
car->set_width(48 + fastRand(36));
car->set_height(54 + fastRand(48));
car->set_weight(car->length() * car->width() * car->height() / 200);
Engine* engine = car->mutable_engine();
engine->set_horsepower(100 * fastRand(400));
engine->set_cylinders(4 + 2 * fastRand(3));
engine->set_cc(800 + fastRand(10000));
car->set_fuel_capacity(10.0 + fastRandDouble(30.0));
car->set_fuel_level(fastRandDouble(car->fuel_capacity()));
car->set_has_power_windows(fastRand(2));
car->set_has_power_steering(fastRand(2));
car->set_has_cruise_control(fastRand(2));
car->set_cup_holders(fastRand(12));
car->set_has_nav_system(fastRand(2));
}
class CarSalesTestCase {
public:
typedef ParkingLot Request;
typedef TotalValue Response;
typedef uint64_t Expectation;
static uint64_t setupRequest(ParkingLot* request) {
uint count = fastRand(200);
uint64_t result = 0;
for (uint i = 0; i < count; i++) {
Car* car = request->add_car();
randomCar(car);
result += carValue(*car);
}
return result;
}
static void handleRequest(const ParkingLot& request, TotalValue* response) {
uint64_t result = 0;
for (auto& car: request.car()) {
result += carValue(car);
}
response->set_amount(result);
}
static inline bool checkResponse(const TotalValue& response, uint64_t expected) {
return response.amount() == expected;
}
};
// =======================================================================================
struct SingleUseMessages {
......@@ -629,10 +335,6 @@ struct BenchmarkMethods {
};
struct BenchmarkTypes {
typedef protobuf::ExpressionTestCase ExpressionTestCase;
typedef protobuf::CatRankTestCase CatRankTestCase;
typedef protobuf::CarSalesTestCase CarSalesTestCase;
typedef protobuf::SnappyCompressed SnappyCompressed;
typedef protobuf::Uncompressed Uncompressed;
......@@ -647,8 +349,3 @@ struct BenchmarkTypes {
} // namespace protobuf
} // namespace benchmark
} // namespace capnproto
int main(int argc, char* argv[]) {
return capnproto::benchmark::benchmarkMain<
capnproto::benchmark::protobuf::BenchmarkTypes>(argc, argv);
}
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. 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.
//
// 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 "eval.pb.h"
#include "protobuf-common.h"
namespace capnproto {
namespace benchmark {
namespace protobuf {
int32_t makeExpression(Expression* exp, uint depth) {
exp->set_op((Operation)(fastRand(Operation_MAX + 1)));
int32_t left, right;
if (fastRand(8) < depth) {
left = fastRand(128) + 1;
exp->set_left_value(left);
} else {
left = makeExpression(exp->mutable_left_expression(), depth + 1);
}
if (fastRand(8) < depth) {
right = fastRand(128) + 1;
exp->set_right_value(right);
} else {
right = makeExpression(exp->mutable_right_expression(), depth + 1);
}
switch (exp->op()) {
case Operation::ADD:
return left + right;
case Operation::SUBTRACT:
return left - right;
case Operation::MULTIPLY:
return left * right;
case Operation::DIVIDE:
return div(left, right);
case Operation::MODULUS:
return mod(left, right);
}
throw std::logic_error("Can't get here.");
}
int32_t evaluateExpression(const Expression& exp) {
uint32_t left, right;
if (exp.has_left_value()) {
left = exp.left_value();
} else {
left = evaluateExpression(exp.left_expression());
}
if (exp.has_right_value()) {
right = exp.right_value();
} else {
right = evaluateExpression(exp.right_expression());
}
switch (exp.op()) {
case Operation::ADD:
return left + right;
case Operation::SUBTRACT:
return left - right;
case Operation::MULTIPLY:
return left * right;
case Operation::DIVIDE:
return div(left, right);
case Operation::MODULUS:
return mod(left, right);
}
throw std::logic_error("Can't get here.");
}
class ExpressionTestCase {
public:
typedef Expression Request;
typedef EvaluationResult Response;
typedef int32_t Expectation;
static inline int32_t setupRequest(Expression* request) {
return makeExpression(request, 0);
}
static inline void handleRequest(const Expression& request, EvaluationResult* response) {
response->set_value(evaluateExpression(request));
}
static inline bool checkResponse(const EvaluationResult& response, int32_t expected) {
return response.value() == expected;
}
};
} // namespace protobuf
} // namespace benchmark
} // namespace capnproto
int main(int argc, char* argv[]) {
return capnproto::benchmark::benchmarkMain<
capnproto::benchmark::protobuf::BenchmarkTypes,
capnproto::benchmark::protobuf::ExpressionTestCase>(argc, argv);
}
......@@ -94,6 +94,19 @@ enum class TestCase {
CARSALES
};
const char* testCaseName(TestCase testCase) {
switch (testCase) {
case TestCase::EVAL:
return "eval";
case TestCase::CATRANK:
return "catrank";
case TestCase::CARSALES:
return "carsales";
}
// Can't get here.
return nullptr;
}
enum class Mode {
OBJECTS,
OBJECT_SIZE,
......@@ -114,73 +127,66 @@ enum class Compression {
TestResult runTest(Product product, TestCase testCase, Mode mode, Reuse reuse,
Compression compression, uint64_t iters) {
char* argv[7];
char* argv[6];
string progName;
switch (product) {
case Product::CAPNPROTO:
argv[0] = strdup("benchmark-capnproto");
progName = "capnproto-";
break;
case Product::PROTOBUF:
argv[0] = strdup("benchmark-protobuf");
progName = "protobuf-";
break;
case Product::NULLCASE:
argv[0] = strdup("benchmark-null");
progName = "null-";
break;
}
switch (testCase) {
case TestCase::EVAL:
argv[1] = strdup("eval");
break;
case TestCase::CATRANK:
argv[1] = strdup("catrank");
break;
case TestCase::CARSALES:
argv[1] = strdup("carsales");
break;
}
progName += testCaseName(testCase);
argv[0] = progName.c_str();
switch (mode) {
case Mode::OBJECTS:
argv[2] = strdup("object");
argv[1] = strdup("object");
break;
case Mode::OBJECT_SIZE:
argv[2] = strdup("object-size");
argv[1] = strdup("object-size");
break;
case Mode::BYTES:
argv[2] = strdup("bytes");
argv[1] = strdup("bytes");
break;
case Mode::PIPE_SYNC:
argv[2] = strdup("pipe");
argv[1] = strdup("pipe");
break;
case Mode::PIPE_ASYNC:
argv[2] = strdup("pipe-async");
argv[1] = strdup("pipe-async");
break;
}
switch (reuse) {
case Reuse::YES:
argv[3] = strdup("reuse");
argv[2] = strdup("reuse");
break;
case Reuse::NO:
argv[3] = strdup("no-reuse");
argv[2] = strdup("no-reuse");
break;
}
switch (compression) {
case Compression::SNAPPY:
argv[4] = strdup("snappy");
argv[3] = strdup("snappy");
break;
case Compression::NONE:
argv[4] = strdup("none");
argv[3] = strdup("none");
break;
}
char itersStr[64];
sprintf(itersStr, "%llu", (long long unsigned int)iters);
argv[5] = itersStr;
argv[4] = itersStr;
argv[6] = nullptr;
argv[5] = nullptr;
// Make pipe for child to write throughput.
int childPipe[2];
......@@ -202,7 +208,7 @@ TestResult runTest(Product product, TestCase testCase, Mode mode, Reuse reuse,
}
close(childPipe[1]);
for (int i = 0; i < 5; i++) {
for (int i = 1; i < 4; i++) {
free(argv[i]);
}
......@@ -308,10 +314,10 @@ void reportComparison(const char* name, const char* unit, double protobuf, doubl
cout << setw(14) << right << Gain(capnproto, protobuf) << endl;
}
size_t fileSize(const char* name) {
size_t fileSize(const std::string& name) {
struct stat stats;
if (stat(name, &stats) < 0) {
perror(name);
if (stat(name.c_str(), &stats) < 0) {
perror(name.c_str());
exit(1);
}
......@@ -454,12 +460,16 @@ int main(int argc, char* argv[]) {
(capnp.time.cpu() - capnpBase.time.cpu()) / 1000.0, iters);
reportComparison("binary size", "kB",
fileSize("benchmark-protobuf") / 1024.0, fileSize("benchmark-capnproto") / 1024.0, 1);
fileSize("protobuf-" + std::string(testCaseName(testCase))) / 1024.0,
fileSize("capnproto-" + std::string(testCaseName(testCase))) / 1024.0, 1);
reportComparison("generated code size", "kB",
fileSize("benchmark.pb.cc") / 1024.0 + fileSize("benchmark.pb.h") / 1024.0,
fileSize("benchmark.capnp.c++") / 1024.0 + fileSize("benchmark.capnp.h") / 1024.0, 1);
fileSize(std::string(testCaseName(testCase)) + ".pb.cc") / 1024.0
+ fileSize(std::string(testCaseName(testCase)) + ".pb.h") / 1024.0,
fileSize(std::string(testCaseName(testCase)) + ".capnp.c++") / 1024.0
+ fileSize(std::string(testCaseName(testCase)) + ".capnp.h") / 1024.0, 1);
reportComparison("generated obj size", "kB",
fileSize("benchmark.pb.o") / 1024.0, fileSize("benchmark.capnp.o") / 1024.0, 1);
fileSize(std::string(testCaseName(testCase)) + ".pb.o") / 1024.0,
fileSize(std::string(testCaseName(testCase)) + ".capnp.o") / 1024.0, 1);
return 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment