Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions include/benchmark/benchmark.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
#include <atomic>
#include <cassert>
#include <cstddef>
#include <functional>
#include <initializer_list>
#include <iosfwd>
#include <limits>
Expand Down Expand Up @@ -303,6 +304,10 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);

namespace benchmark {
class BenchmarkReporter;
class State;

// Define alias of Setup/Teardown callback function type
using callback_function = std::function<void(const benchmark::State&)>;

// Default number of minimum benchmark running time in seconds.
const char kDefaultMinTimeStr[] = "0.5s";
Expand Down Expand Up @@ -1157,10 +1162,10 @@ class BENCHMARK_EXPORT Benchmark {
//
// The callback will be passed a State object, which includes the number
// of threads, thread-index, benchmark arguments, etc.
//
// The callback must not be NULL or self-deleting.
Benchmark* Setup(void (*setup)(const benchmark::State&));
Benchmark* Teardown(void (*teardown)(const benchmark::State&));
Benchmark* Setup(callback_function&&);
Benchmark* Setup(const callback_function&);
Comment thread
dmah42 marked this conversation as resolved.
Benchmark* Teardown(callback_function&&);
Benchmark* Teardown(const callback_function&);

// Pass this benchmark object to *func, which can customize
// the benchmark by calling various methods like Arg, Args,
Expand Down Expand Up @@ -1309,7 +1314,6 @@ class BENCHMARK_EXPORT Benchmark {
std::vector<Statistics> statistics_;
std::vector<int> thread_counts_;

typedef void (*callback_function)(const benchmark::State&);
callback_function setup_;
callback_function teardown_;

Expand Down
7 changes: 3 additions & 4 deletions src/benchmark_api_internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx,
min_time_(benchmark_.min_time_),
min_warmup_time_(benchmark_.min_warmup_time_),
iterations_(benchmark_.iterations_),
threads_(thread_count) {
threads_(thread_count),
setup_(benchmark_.setup_),
teardown_(benchmark_.teardown_) {
name_.function_name = benchmark_.name_;

size_t arg_i = 0;
Expand Down Expand Up @@ -84,9 +86,6 @@ BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx,
if (!benchmark_.thread_counts_.empty()) {
name_.threads = StrFormat("threads:%d", threads_);
}

setup_ = benchmark_.setup_;
teardown_ = benchmark_.teardown_;
}

State BenchmarkInstance::Run(
Expand Down
5 changes: 2 additions & 3 deletions src/benchmark_api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ class BenchmarkInstance {
IterationCount iterations_;
int threads_; // Number of concurrent threads to us

typedef void (*callback_function)(const benchmark::State&);
callback_function setup_ = nullptr;
callback_function teardown_ = nullptr;
callback_function setup_;
callback_function teardown_;
};

bool FindBenchmarksInternal(const std::string& re,
Expand Down
20 changes: 15 additions & 5 deletions src/benchmark_register.cc
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,7 @@ Benchmark::Benchmark(const std::string& name)
use_real_time_(false),
use_manual_time_(false),
complexity_(oNone),
complexity_lambda_(nullptr),
setup_(nullptr),
teardown_(nullptr) {
complexity_lambda_(nullptr) {
ComputeStatistics("mean", StatisticsMean);
ComputeStatistics("median", StatisticsMedian);
ComputeStatistics("stddev", StatisticsStdDev);
Expand Down Expand Up @@ -337,13 +335,25 @@ Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) {
return this;
}

Benchmark* Benchmark::Setup(void (*setup)(const benchmark::State&)) {
Benchmark* Benchmark::Setup(callback_function&& setup) {
BM_CHECK(setup != nullptr);
setup_ = std::forward<callback_function>(setup);
return this;
}

Benchmark* Benchmark::Setup(const callback_function& setup) {
BM_CHECK(setup != nullptr);
setup_ = setup;
return this;
}

Benchmark* Benchmark::Teardown(void (*teardown)(const benchmark::State&)) {
Benchmark* Benchmark::Teardown(callback_function&& teardown) {
BM_CHECK(teardown != nullptr);
teardown_ = std::forward<callback_function>(teardown);
return this;
}

Benchmark* Benchmark::Teardown(const callback_function& teardown) {
BM_CHECK(teardown != nullptr);
teardown_ = teardown;
return this;
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS)
add_gtest(time_unit_gtest)
add_gtest(min_time_parse_gtest)
add_gtest(profiler_manager_gtest)
add_gtest(benchmark_setup_teardown_cb_types_gtest)
endif(BENCHMARK_ENABLE_GTEST_TESTS)

###############################################################################
Expand Down
126 changes: 126 additions & 0 deletions test/benchmark_setup_teardown_cb_types_gtest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include "benchmark/benchmark.h"
#include "gtest/gtest.h"

using benchmark::BenchmarkReporter;
using benchmark::callback_function;
using benchmark::ClearRegisteredBenchmarks;
using benchmark::RegisterBenchmark;
using benchmark::RunSpecifiedBenchmarks;
using benchmark::State;
using benchmark::internal::Benchmark;

static int functor_called = 0;
struct Functor {
void operator()(const benchmark::State& /*unused*/) { functor_called++; }
};

class NullReporter : public BenchmarkReporter {
public:
bool ReportContext(const Context& /*context*/) override { return true; }
void ReportRuns(const std::vector<Run>& /* report */) override {}
};

class BenchmarkTest : public testing::Test {
public:
Benchmark* bm;
NullReporter null_reporter;

int setup_calls;
int teardown_calls;

void SetUp() override {
setup_calls = 0;
teardown_calls = 0;
functor_called = 0;

bm = RegisterBenchmark("BM", [](State& st) {
for (auto _ : st) {
}
});
bm->Iterations(1);
}

void TearDown() override { ClearRegisteredBenchmarks(); }
};

// Test that Setup/Teardown can correctly take a lambda expressions
TEST_F(BenchmarkTest, LambdaTestCopy) {
auto setup_lambda = [this](const State&) { setup_calls++; };
auto teardown_lambda = [this](const State&) { teardown_calls++; };
bm->Setup(setup_lambda);
bm->Teardown(teardown_lambda);
RunSpecifiedBenchmarks(&null_reporter);
EXPECT_EQ(setup_calls, 1);
EXPECT_EQ(teardown_calls, 1);
}

// Test that Setup/Teardown can correctly take a lambda expressions
TEST_F(BenchmarkTest, LambdaTestMove) {
auto setup_lambda = [this](const State&) { setup_calls++; };
auto teardown_lambda = [this](const State&) { teardown_calls++; };
bm->Setup(std::move(setup_lambda));
bm->Teardown(std::move(teardown_lambda));
RunSpecifiedBenchmarks(&null_reporter);
EXPECT_EQ(setup_calls, 1);
EXPECT_EQ(teardown_calls, 1);
}

// Test that Setup/Teardown can correctly take std::function
TEST_F(BenchmarkTest, CallbackFunctionCopy) {
callback_function setup_lambda = [this](const State&) { setup_calls++; };
callback_function teardown_lambda = [this](const State&) {
teardown_calls++;
};
bm->Setup(setup_lambda);
bm->Teardown(teardown_lambda);
RunSpecifiedBenchmarks(&null_reporter);
EXPECT_EQ(setup_calls, 1);
EXPECT_EQ(teardown_calls, 1);
}

// Test that Setup/Teardown can correctly take std::function
TEST_F(BenchmarkTest, CallbackFunctionMove) {
callback_function setup_lambda = [this](const State&) { setup_calls++; };
callback_function teardown_lambda = [this](const State&) {
teardown_calls++;
};
bm->Setup(std::move(setup_lambda));
bm->Teardown(std::move(teardown_lambda));
RunSpecifiedBenchmarks(&null_reporter);
EXPECT_EQ(setup_calls, 1);
EXPECT_EQ(teardown_calls, 1);
}

// Test that Setup/Teardown can correctly take functors
TEST_F(BenchmarkTest, FunctorCopy) {
Functor func;
bm->Setup(func);
bm->Teardown(func);
RunSpecifiedBenchmarks(&null_reporter);
EXPECT_EQ(functor_called, 2);
}

// Test that Setup/Teardown can correctly take functors
TEST_F(BenchmarkTest, FunctorMove) {
Functor func1;
Functor func2;
bm->Setup(std::move(func1));
bm->Teardown(std::move(func2));
RunSpecifiedBenchmarks(&null_reporter);
EXPECT_EQ(functor_called, 2);
}

// Test that Setup/Teardown can not take nullptr
TEST_F(BenchmarkTest, NullptrTest) {
#if GTEST_HAS_DEATH_TEST
// Tests only runnable in debug mode (when BM_CHECK is enabled).
#ifndef NDEBUG
#ifndef TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS
EXPECT_DEATH(bm->Setup(nullptr), "setup != nullptr");
EXPECT_DEATH(bm->Teardown(nullptr), "teardown != nullptr");
#else
GTEST_SKIP() << "Test skipped because BM_CHECK is disabled";
#endif
#endif
#endif
}