Commit f8b5d71d authored by Kenton Varda's avatar Kenton Varda

Fancy benchmark harness.

parent 50c229bb
......@@ -122,7 +122,7 @@ int32_t makeExpression(Expression::Builder exp, int depth) {
// TODO: Operation_MAX or something.
exp.setOp((Operation)(rand() % (int)Operation::MODULUS + 1));
int left, right;
uint32_t left, right;
if (rand() % 8 < depth) {
exp.setLeftIsValue(true);
......@@ -156,7 +156,7 @@ int32_t makeExpression(Expression::Builder exp, int depth) {
}
int32_t evaluateExpression(Expression::Reader exp) {
int left, right;
int32_t left, right;
if (exp.getLeftIsValue()) {
left = exp.getLeftValue();
......@@ -379,24 +379,79 @@ struct NoScratch {
public:
inline MessageBuilder(ScratchSpace& scratch): MallocMessageBuilder() {}
};
class ObjectSizeCounter {
public:
ObjectSizeCounter(uint64_t iters): counter(0) {}
template <typename RequestBuilder, typename ResponseBuilder>
void add(RequestBuilder& request, ResponseBuilder& response) {
for (auto segment: request.getSegmentsForOutput()) {
counter += segment.size() * sizeof(word);
}
for (auto segment: response.getSegmentsForOutput()) {
counter += segment.size() * sizeof(word);
}
}
uint64_t get() { return counter; }
private:
uint64_t counter;
};
};
template <typename Compression, size_t size>
constexpr size_t SCRATCH_SIZE = 128 * 1024;
word scratchSpace[4 * SCRATCH_SIZE];
int scratchCounter = 0;
template <typename Compression>
struct UseScratch {
struct ScratchSpace {
word words[size];
word* words;
ScratchSpace() {
CAPNPROTO_ASSERT(scratchCounter < 4, "Too many scratch spaces needed at once.");
words = scratchSpace + scratchCounter++ * SCRATCH_SIZE;
}
~ScratchSpace() {
--scratchCounter;
}
};
class MessageReader: public Compression::MessageReader {
public:
inline MessageReader(int fd, ScratchSpace& scratch)
: Compression::MessageReader(fd, ReaderOptions(), arrayPtr(scratch.words, size)) {}
: Compression::MessageReader(fd, ReaderOptions(), arrayPtr(scratch.words, SCRATCH_SIZE)) {}
};
class MessageBuilder: public MallocMessageBuilder {
public:
inline MessageBuilder(ScratchSpace& scratch)
: MallocMessageBuilder(arrayPtr(scratch.words, size)) {}
: MallocMessageBuilder(arrayPtr(scratch.words, SCRATCH_SIZE)) {}
};
class ObjectSizeCounter {
public:
ObjectSizeCounter(uint64_t iters): iters(iters), maxSize(0) {}
template <typename RequestBuilder, typename ResponseBuilder>
void add(RequestBuilder& request, ResponseBuilder& response) {
size_t counter = 0;
for (auto segment: request.getSegmentsForOutput()) {
counter += segment.size() * sizeof(word);
}
for (auto segment: response.getSegmentsForOutput()) {
counter += segment.size() * sizeof(word);
}
maxSize = std::max(counter, maxSize);
}
uint64_t get() { return iters * maxSize; }
private:
uint64_t iters;
size_t maxSize;
};
};
......@@ -490,10 +545,12 @@ uint64_t server(int inputFd, int outputFd, uint64_t iters) {
}
template <typename TestCase, typename ReuseStrategy, typename Compression>
uint64_t passByObject(uint64_t iters) {
uint64_t passByObject(uint64_t iters, bool countObjectSize) {
typename ReuseStrategy::ScratchSpace requestScratch;
typename ReuseStrategy::ScratchSpace responseScratch;
typename ReuseStrategy::ObjectSizeCounter counter(iters);
for (; iters > 0; --iters) {
typename ReuseStrategy::MessageBuilder requestMessage(requestScratch);
auto request = requestMessage.template initRoot<typename TestCase::Request>();
......@@ -506,9 +563,13 @@ uint64_t passByObject(uint64_t iters) {
if (!TestCase::checkResponse(response.asReader(), expected)) {
throw std::logic_error("Incorrect response.");
}
if (countObjectSize) {
counter.add(requestMessage, responseMessage);
}
}
return 0;
return counter.get();
}
template <typename TestCase, typename ReuseStrategy, typename Compression>
......@@ -592,7 +653,9 @@ uint64_t doBenchmark(const std::string& mode, uint64_t iters) {
return server<TestCase, ReuseStrategy, Compression>(
STDIN_FILENO, STDOUT_FILENO, iters);
} else if (mode == "object") {
return passByObject<TestCase, ReuseStrategy, Compression>(iters);
return passByObject<TestCase, ReuseStrategy, Compression>(iters, false);
} else if (mode == "object-size") {
return passByObject<TestCase, ReuseStrategy, Compression>(iters, true);
} else if (mode == "bytes") {
return passByBytes<TestCase, ReuseStrategy, Compression>(iters);
} else if (mode == "pipe") {
......@@ -610,7 +673,7 @@ uint64_t doBenchmark(const std::string& mode, uint64_t iters) {
template <typename TestCase, typename Compression>
uint64_t doBenchmark2(const std::string& mode, const std::string& reuse, uint64_t iters) {
if (reuse == "reuse") {
return doBenchmark<TestCase, UseScratch<Compression, 1024>, Compression>(mode, iters);
return doBenchmark<TestCase, UseScratch<Compression>, Compression>(mode, iters);
} else if (reuse == "no-reuse") {
return doBenchmark<TestCase, NoScratch<Compression>, Compression>(mode, iters);
} else {
......@@ -634,15 +697,14 @@ uint64_t doBenchmark3(const std::string& mode, const std::string& reuse,
int main(int argc, char* argv[]) {
if (argc != 6) {
std::cerr << "USAGE: " << argv[0] << " MODE REUSE COMPRESSION ITERATION_COUNT" << std::endl;
std::cerr << "USAGE: " << argv[0]
<< " TEST_CASE MODE REUSE COMPRESSION ITERATION_COUNT" << std::endl;
return 1;
}
uint64_t iters = strtoull(argv[5], nullptr, 0);
srand(123);
std::cerr << "Doing " << iters << " iterations..." << std::endl;
uint64_t throughput;
std::string testcase = argv[1];
......@@ -655,7 +717,7 @@ int main(int argc, char* argv[]) {
return 1;
}
std::cerr << "Average messages size = " << (throughput / iters) << std::endl;
std::cout << throughput << std::endl;
return 0;
}
......
This diff is collapsed.
......@@ -121,7 +121,7 @@ inline int32_t mod(int32_t a, int32_t b) {
int32_t makeExpression(Expression* exp, int depth) {
exp->set_op((Operation)(rand() % Operation_MAX + 1));
int left, right;
int32_t left, right;
if (rand() % 8 < depth) {
left = rand() % 128 + 1;
......@@ -153,7 +153,7 @@ int32_t makeExpression(Expression* exp, int depth) {
}
int32_t evaluateExpression(const Expression& exp) {
int left, right;
uint32_t left, right;
if (exp.has_left_value()) {
left = exp.left_value();
......@@ -566,7 +566,9 @@ uint64_t server(int inputFd, int outputFd, uint64_t iters) {
}
template <typename TestCase, typename ReuseStrategy, typename Compression>
uint64_t passByObject(uint64_t iters) {
uint64_t passByObject(uint64_t iters, bool countObjectSize) {
uint64_t throughput = 0;
REUSABLE(Request) reusableRequest;
REUSABLE(Response) reusableResponse;
......@@ -581,9 +583,14 @@ uint64_t passByObject(uint64_t iters) {
throw std::logic_error("Incorrect response.");
}
ReuseStrategy::doneWith(response);
if (countObjectSize) {
throughput += request.SpaceUsed();
throughput += response.SpaceUsed();
}
}
return 0;
return throughput;
}
template <typename TestCase, typename ReuseStrategy, typename Compression>
......@@ -679,7 +686,9 @@ uint64_t doBenchmark(const std::string& mode, uint64_t iters) {
return server<TestCase, ReuseStrategy, Compression>(
STDIN_FILENO, STDOUT_FILENO, iters);
} else if (mode == "object") {
return passByObject<TestCase, ReuseStrategy, Compression>(iters);
return passByObject<TestCase, ReuseStrategy, Compression>(iters, false);
} else if (mode == "object-size") {
return passByObject<TestCase, ReuseStrategy, Compression>(iters, true);
} else if (mode == "bytes") {
return passByBytes<TestCase, ReuseStrategy, Compression>(iters);
} else if (mode == "pipe") {
......@@ -729,8 +738,6 @@ int main(int argc, char* argv[]) {
uint64_t iters = strtoull(argv[5], nullptr, 0);
srand(123);
std::cerr << "Doing " << iters << " iterations..." << std::endl;
uint64_t throughput;
std::string testcase = argv[1];
......@@ -743,7 +750,7 @@ int main(int argc, char* argv[]) {
return 1;
}
std::cerr << "Average messages size = " << (throughput / iters) << std::endl;
std::cout << throughput << std::endl;
return 0;
}
......
This diff is collapsed.
......@@ -204,7 +204,16 @@ MallocMessageBuilder::MallocMessageBuilder(
ownFirstSegment(false), firstSegment(firstSegment.begin()) {}
MallocMessageBuilder::~MallocMessageBuilder() {
if (ownFirstSegment) free(firstSegment);
if (ownFirstSegment) {
free(firstSegment);
} else {
ArrayPtr<const ArrayPtr<const word>> segments = getSegmentsForOutput();
if (segments.size() > 0) {
CAPNPROTO_ASSERT(segments[0].begin() == firstSegment,
"First segment in getSegmentsForOutput() is not the first segment allocated?");
memset(firstSegment, 0, segments[0].size() * sizeof(word));
}
}
if (moreSegments != nullptr) {
for (void* ptr: moreSegments->segments) {
free(ptr);
......@@ -218,7 +227,6 @@ ArrayPtr<word> MallocMessageBuilder::allocateSegment(uint minimumSize) {
firstSegment = nullptr;
ownFirstSegment = true;
if (result.size() >= minimumSize) {
memset(result.begin(), 0, result.size() * sizeof(word));
return result;
}
// If the provided first segment wasn't big enough, we discard it and proceed to allocate
......
......@@ -268,6 +268,9 @@ public:
// This version always returns the given array for the first segment, and then proceeds with the
// allocation strategy. This is useful for optimization when building lots of small messages in
// a tight loop: you can reuse the space for the first segment.
//
// firstSegment MUST be zero-initialized. MallocMessageBuilder's destructor will write new zeros
// over any space that was used so that it can be reused.
CAPNPROTO_DISALLOW_COPY(MallocMessageBuilder);
virtual ~MallocMessageBuilder();
......
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