blob: c6bcfc2d62416cee163969ba2ccb77a697b8bbbf [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <stdint.h>
#include <fbl/function.h>
#include <perftest/results.h>
// This is a library for writing performance tests. It supports
// performance tests that involve running an operation repeatedly,
// sequentially, and recording the times taken by each run of the
// operation. (It does not yet support other types of performance test,
// such as where we run an operation concurrently in multiple threads.)
//
// There are two ways to implement a test:
//
// 1) For tests that don't need to reuse any test fixtures across each run,
// use RegisterSimpleTest():
//
// bool TestFooOp() {
// FooOp(); // The operation that we are timing.
// return true; // Indicate success.
// }
// void RegisterTests() {
// perftest::RegisterSimpleTest<TestFooOp>("FooOp");
// }
// PERFTEST_CTOR(RegisterTests);
//
// 2) For tests that do need to reuse test fixtures across each run, use
// the more general RegisterTest():
//
// bool TestFooObjectOp(perftest::RepeatState* state) {
// FooObject obj; // Fixture that is reused across test runs.
// while (state->KeepRunning()) {
// obj.FooOp(); // The operation that we are timing.
// }
// return true; // Indicate success.
// }
// void RegisterTests() {
// perftest::RegisterTest("FooObjectOp", TestFooObjectOp);
// }
// PERFTEST_CTOR(RegisterTests);
//
// Test registration is done using function calls in order to make it easy
// to instantiate parameterized tests multiple times.
//
// Background: The "KeepRunning()" interface is based on the interface used
// by the gbenchmark library (https://github.com/google/benchmark).
namespace perftest {
// This object is passed to the test function. It controls the iteration
// of test runs and records the times taken by test runs.
//
// This is a pure virtual interface so that one can potentially use a test
// runner other than the one provided by this library.
class RepeatState {
public:
// KeepRunning() should be called by test functions using a "while"
// loop shown above. A call to KeepRunning() indicates the start or
// end of a test run, or both. KeepRunning() returns a bool indicating
// whether the caller should do another test run.
virtual bool KeepRunning() = 0;
};
typedef bool TestFunc(RepeatState* state);
typedef bool SimpleTestFunc();
void RegisterTest(const char* name, fbl::Function<TestFunc> test_func);
// Convenience routine for registering a perf test that is specified by a
// function. This is for tests that don't set up any fixtures that are
// shared across invocations of the function.
//
// This takes the function as a template parameter rather than as a value
// parameter in order to avoid the potential cost of an indirect function
// call.
template <SimpleTestFunc test_func>
void RegisterSimpleTest(const char* test_name) {
auto wrapper_func = [](RepeatState* state) {
while (state->KeepRunning()) {
if (!test_func()) {
return false;
}
}
return true;
};
RegisterTest(test_name, fbl::move(wrapper_func));
}
// Entry point for the perf test runner that a test executable should call
// from main(). This will run the registered perf tests and/or unit tests,
// based on the command line arguments. (See the "--help" output for more
// details.)
int PerfTestMain(int argc, char** argv);
} // namespace perftest
// This calls func() at startup time as a global constructor. This is
// useful for registering perf tests. This is similar to declaring func()
// with __attribute__((constructor)), but portable.
#define PERFTEST_CTOR(func) \
namespace { \
struct FuncCaller_##func { \
FuncCaller_##func() { func(); } \
} global; \
}