mirror of https://github.com/google/benchmark.git
Support multiple ranges in the benchmark (#257)
* Support multiple ranges in the benchmark google-benchmark library allows to provide up to two ranges to the benchmark method (range_x and range_y). However, in many cases it's not sufficient. The patch introduces multi-range features, so user can easily define multiple ranges by passing a vector of integers, and access values through the method range(i). * Remove redundant API Functions State::range_x() and State::range_y() have been removed. They should be replaced by State::range(0) and State::range(1). Functions Benchmark::ArgPair() and Benchmark::RangePair() have been removed. They should be replaced by Benchmark::Args() and Benchmark::Ranges().
This commit is contained in:
parent
7f1da4a68b
commit
dfe0260754
50
README.md
50
README.md
|
@ -40,13 +40,13 @@ measuring the speed of `memcpy()` calls of different lengths:
|
|||
|
||||
```c++
|
||||
static void BM_memcpy(benchmark::State& state) {
|
||||
char* src = new char[state.range_x()];
|
||||
char* dst = new char[state.range_x()];
|
||||
memset(src, 'x', state.range_x());
|
||||
char* src = new char[state.range(0)];
|
||||
char* dst = new char[state.range(0)];
|
||||
memset(src, 'x', state.range(0));
|
||||
while (state.KeepRunning())
|
||||
memcpy(dst, src, state.range_x());
|
||||
memcpy(dst, src, state.range(0));
|
||||
state.SetBytesProcessed(int64_t(state.iterations()) *
|
||||
int64_t(state.range_x()));
|
||||
int64_t(state.range(0)));
|
||||
delete[] src;
|
||||
delete[] dst;
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ BENCHMARK(BM_memcpy)->RangeMultiplier(2)->Range(8, 8<<10);
|
|||
```
|
||||
Now arguments generated are [ 8, 16, 32, 64, 128, 256, 512, 1024, 2k, 4k, 8k ].
|
||||
|
||||
You might have a benchmark that depends on two inputs. For example, the
|
||||
You might have a benchmark that depends on two or more inputs. For example, the
|
||||
following code defines a family of benchmarks for measuring the speed of set
|
||||
insertion.
|
||||
|
||||
|
@ -78,21 +78,21 @@ insertion.
|
|||
static void BM_SetInsert(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
state.PauseTiming();
|
||||
std::set<int> data = ConstructRandomSet(state.range_x());
|
||||
std::set<int> data = ConstructRandomSet(state.range(0));
|
||||
state.ResumeTiming();
|
||||
for (int j = 0; j < state.range_y(); ++j)
|
||||
for (int j = 0; j < state.range(1); ++j)
|
||||
data.insert(RandomNumber());
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SetInsert)
|
||||
->ArgPair(1<<10, 1)
|
||||
->ArgPair(1<<10, 8)
|
||||
->ArgPair(1<<10, 64)
|
||||
->ArgPair(1<<10, 512)
|
||||
->ArgPair(8<<10, 1)
|
||||
->ArgPair(8<<10, 8)
|
||||
->ArgPair(8<<10, 64)
|
||||
->ArgPair(8<<10, 512);
|
||||
->Args({1<<10, 1})
|
||||
->Args({1<<10, 8})
|
||||
->Args({1<<10, 64})
|
||||
->Args({1<<10, 512})
|
||||
->Args({8<<10, 1})
|
||||
->Args({8<<10, 8})
|
||||
->Args({8<<10, 64})
|
||||
->Args({8<<10, 512});
|
||||
```
|
||||
|
||||
The preceding code is quite repetitive, and can be replaced with the following
|
||||
|
@ -101,7 +101,7 @@ product of the two specified ranges and will generate a benchmark for each such
|
|||
pair.
|
||||
|
||||
```c++
|
||||
BENCHMARK(BM_SetInsert)->RangePair(1<<10, 8<<10, 1, 512);
|
||||
BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {1, 512}});
|
||||
```
|
||||
|
||||
For more complex patterns of inputs, passing a custom function to `Apply` allows
|
||||
|
@ -113,7 +113,7 @@ and a sparse range on the second.
|
|||
static void CustomArguments(benchmark::internal::Benchmark* b) {
|
||||
for (int i = 0; i <= 10; ++i)
|
||||
for (int j = 32; j <= 1024*1024; j *= 8)
|
||||
b->ArgPair(i, j);
|
||||
b->Args({i, j});
|
||||
}
|
||||
BENCHMARK(BM_SetInsert)->Apply(CustomArguments);
|
||||
```
|
||||
|
@ -125,12 +125,12 @@ running time and the normalized root-mean square error of string comparison.
|
|||
|
||||
```c++
|
||||
static void BM_StringCompare(benchmark::State& state) {
|
||||
std::string s1(state.range_x(), '-');
|
||||
std::string s2(state.range_x(), '-');
|
||||
std::string s1(state.range(0), '-');
|
||||
std::string s2(state.range(0), '-');
|
||||
while (state.KeepRunning()) {
|
||||
benchmark::DoNotOptimize(s1.compare(s2));
|
||||
}
|
||||
state.SetComplexityN(state.range_x());
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
BENCHMARK(BM_StringCompare)
|
||||
->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity(benchmark::oN);
|
||||
|
@ -162,14 +162,14 @@ template <class Q> int BM_Sequential(benchmark::State& state) {
|
|||
Q q;
|
||||
typename Q::value_type v;
|
||||
while (state.KeepRunning()) {
|
||||
for (int i = state.range_x(); i--; )
|
||||
for (int i = state.range(0); i--; )
|
||||
q.push(v);
|
||||
for (int e = state.range_x(); e--; )
|
||||
for (int e = state.range(0); e--; )
|
||||
q.Wait(&v);
|
||||
}
|
||||
// actually messages, not bytes:
|
||||
state.SetBytesProcessed(
|
||||
static_cast<int64_t>(state.iterations())*state.range_x());
|
||||
static_cast<int64_t>(state.iterations())*state.range(0));
|
||||
}
|
||||
BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue<int>)->Range(1<<0, 1<<10);
|
||||
```
|
||||
|
@ -284,7 +284,7 @@ can be reported back with `SetIterationTime`.
|
|||
|
||||
```c++
|
||||
static void BM_ManualTiming(benchmark::State& state) {
|
||||
int microseconds = state.range_x();
|
||||
int microseconds = state.range(0);
|
||||
std::chrono::duration<double, std::micro> sleep_duration {
|
||||
static_cast<double>(microseconds)
|
||||
};
|
||||
|
|
|
@ -38,12 +38,12 @@ int main(int argc, char** argv) {
|
|||
// of memcpy() calls of different lengths:
|
||||
|
||||
static void BM_memcpy(benchmark::State& state) {
|
||||
char* src = new char[state.range_x()]; char* dst = new char[state.range_x()];
|
||||
memset(src, 'x', state.range_x());
|
||||
char* src = new char[state.range(0)]; char* dst = new char[state.range(0)];
|
||||
memset(src, 'x', state.range(0));
|
||||
while (state.KeepRunning())
|
||||
memcpy(dst, src, state.range_x());
|
||||
memcpy(dst, src, state.range(0));
|
||||
state.SetBytesProcessed(int64_t(state.iterations()) *
|
||||
int64_t(state.range_x()));
|
||||
int64_t(state.range(0)));
|
||||
delete[] src; delete[] dst;
|
||||
}
|
||||
BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10);
|
||||
|
@ -60,27 +60,27 @@ BENCHMARK(BM_memcpy)->Range(8, 8<<10);
|
|||
static void BM_SetInsert(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
state.PauseTiming();
|
||||
set<int> data = ConstructRandomSet(state.range_x());
|
||||
set<int> data = ConstructRandomSet(state.range(0));
|
||||
state.ResumeTiming();
|
||||
for (int j = 0; j < state.range_y(); ++j)
|
||||
for (int j = 0; j < state.range(1); ++j)
|
||||
data.insert(RandomNumber());
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SetInsert)
|
||||
->ArgPair(1<<10, 1)
|
||||
->ArgPair(1<<10, 8)
|
||||
->ArgPair(1<<10, 64)
|
||||
->ArgPair(1<<10, 512)
|
||||
->ArgPair(8<<10, 1)
|
||||
->ArgPair(8<<10, 8)
|
||||
->ArgPair(8<<10, 64)
|
||||
->ArgPair(8<<10, 512);
|
||||
->Args({1<<10, 1})
|
||||
->Args({1<<10, 8})
|
||||
->Args({1<<10, 64})
|
||||
->Args({1<<10, 512})
|
||||
->Args({8<<10, 1})
|
||||
->Args({8<<10, 8})
|
||||
->Args({8<<10, 64})
|
||||
->Args({8<<10, 512});
|
||||
|
||||
// The preceding code is quite repetitive, and can be replaced with
|
||||
// the following short-hand. The following macro will pick a few
|
||||
// appropriate arguments in the product of the two specified ranges
|
||||
// and will generate a microbenchmark for each such pair.
|
||||
BENCHMARK(BM_SetInsert)->RangePair(1<<10, 8<<10, 1, 512);
|
||||
BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {1, 512}});
|
||||
|
||||
// For more complex patterns of inputs, passing a custom function
|
||||
// to Apply allows programmatic specification of an
|
||||
|
@ -90,7 +90,7 @@ BENCHMARK(BM_SetInsert)->RangePair(1<<10, 8<<10, 1, 512);
|
|||
static void CustomArguments(benchmark::internal::Benchmark* b) {
|
||||
for (int i = 0; i <= 10; ++i)
|
||||
for (int j = 32; j <= 1024*1024; j *= 8)
|
||||
b->ArgPair(i, j);
|
||||
b->Args({i, j});
|
||||
}
|
||||
BENCHMARK(BM_SetInsert)->Apply(CustomArguments);
|
||||
|
||||
|
@ -101,14 +101,14 @@ template <class Q> int BM_Sequential(benchmark::State& state) {
|
|||
Q q;
|
||||
typename Q::value_type v;
|
||||
while (state.KeepRunning()) {
|
||||
for (int i = state.range_x(); i--; )
|
||||
for (int i = state.range(0); i--; )
|
||||
q.push(v);
|
||||
for (int e = state.range_x(); e--; )
|
||||
for (int e = state.range(0); e--; )
|
||||
q.Wait(&v);
|
||||
}
|
||||
// actually messages, not bytes:
|
||||
state.SetBytesProcessed(
|
||||
static_cast<int64_t>(state.iterations())*state.range_x());
|
||||
static_cast<int64_t>(state.iterations())*state.range(0));
|
||||
}
|
||||
BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue<int>)->Range(1<<0, 1<<10);
|
||||
|
||||
|
@ -153,6 +153,8 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#if defined(BENCHMARK_HAS_CXX11)
|
||||
|
@ -268,7 +270,7 @@ typedef double(BigOFunc)(int);
|
|||
// benchmark to use.
|
||||
class State {
|
||||
public:
|
||||
State(size_t max_iters, bool has_x, int x, bool has_y, int y,
|
||||
State(size_t max_iters, const std::vector<int>& ranges,
|
||||
int thread_i, int n_threads);
|
||||
|
||||
// Returns true if the benchmark should continue through another iteration.
|
||||
|
@ -423,17 +425,9 @@ public:
|
|||
|
||||
// Range arguments for this run. CHECKs if the argument has been set.
|
||||
BENCHMARK_ALWAYS_INLINE
|
||||
int range_x() const {
|
||||
assert(has_range_x_);
|
||||
((void)has_range_x_); // Prevent unused warning.
|
||||
return range_x_;
|
||||
}
|
||||
|
||||
BENCHMARK_ALWAYS_INLINE
|
||||
int range_y() const {
|
||||
assert(has_range_y_);
|
||||
((void)has_range_y_); // Prevent unused warning.
|
||||
return range_y_;
|
||||
int range(std::size_t pos) const {
|
||||
assert(range_.size() > pos);
|
||||
return range_[pos];
|
||||
}
|
||||
|
||||
BENCHMARK_ALWAYS_INLINE
|
||||
|
@ -444,11 +438,7 @@ private:
|
|||
bool finished_;
|
||||
size_t total_iterations_;
|
||||
|
||||
bool has_range_x_;
|
||||
int range_x_;
|
||||
|
||||
bool has_range_y_;
|
||||
int range_y_;
|
||||
std::vector<int> range_;
|
||||
|
||||
size_t bytes_processed_;
|
||||
size_t items_processed_;
|
||||
|
@ -503,20 +493,18 @@ public:
|
|||
// REQUIRES: The function passed to the constructor must accept an arg1.
|
||||
Benchmark* DenseRange(int start, int limit, int step = 1);
|
||||
|
||||
// Run this benchmark once with "x,y" as the extra arguments passed
|
||||
// Run this benchmark once with "args" as the extra arguments passed
|
||||
// to the function.
|
||||
// REQUIRES: The function passed to the constructor must accept arg1,arg2.
|
||||
Benchmark* ArgPair(int x, int y);
|
||||
// REQUIRES: The function passed to the constructor must accept arg1, arg2 ...
|
||||
Benchmark* Args(const std::vector<int>& args);
|
||||
|
||||
// Pick a set of values A from the range [lo1..hi1] and a set
|
||||
// of values B from the range [lo2..hi2]. Run the benchmark for
|
||||
// every pair of values in the cartesian product of A and B
|
||||
// (i.e., for all combinations of the values in A and B).
|
||||
// REQUIRES: The function passed to the constructor must accept arg1,arg2.
|
||||
Benchmark* RangePair(int lo1, int hi1, int lo2, int hi2);
|
||||
// Run this benchmark once for a number of values picked from the
|
||||
// ranges [start..limit]. (starts and limits are always picked.)
|
||||
// REQUIRES: The function passed to the constructor must accept arg1, arg2 ...
|
||||
Benchmark* Ranges(const std::vector<std::pair<int, int> >& ranges);
|
||||
|
||||
// Pass this benchmark object to *func, which can customize
|
||||
// the benchmark by calling various methods like Arg, ArgPair,
|
||||
// the benchmark by calling various methods like Arg, Args,
|
||||
// Threads, etc.
|
||||
Benchmark* Apply(void (*func)(Benchmark* benchmark));
|
||||
|
||||
|
@ -725,11 +713,11 @@ protected:
|
|||
|
||||
// Old-style macros
|
||||
#define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a))
|
||||
#define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->ArgPair((a1), (a2))
|
||||
#define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->Args({(a1), (a2)})
|
||||
#define BENCHMARK_WITH_UNIT(n, t) BENCHMARK(n)->Unit((t))
|
||||
#define BENCHMARK_RANGE(n, lo, hi) BENCHMARK(n)->Range((lo), (hi))
|
||||
#define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \
|
||||
BENCHMARK(n)->RangePair((l1), (h1), (l2), (h2))
|
||||
BENCHMARK(n)->RangePair({{(l1), (h1)}, {(l2), (h2)}})
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
|
||||
|
|
145
src/benchmark.cc
145
src/benchmark.cc
|
@ -313,23 +313,20 @@ namespace internal {
|
|||
|
||||
// Information kept per benchmark we may want to run
|
||||
struct Benchmark::Instance {
|
||||
std::string name;
|
||||
Benchmark* benchmark;
|
||||
bool has_arg1;
|
||||
int arg1;
|
||||
bool has_arg2;
|
||||
int arg2;
|
||||
TimeUnit time_unit;
|
||||
int range_multiplier;
|
||||
bool use_real_time;
|
||||
bool use_manual_time;
|
||||
BigO complexity;
|
||||
BigOFunc* complexity_lambda;
|
||||
bool last_benchmark_instance;
|
||||
int repetitions;
|
||||
double min_time;
|
||||
int threads; // Number of concurrent threads to use
|
||||
bool multithreaded; // Is benchmark multi-threaded?
|
||||
std::string name;
|
||||
Benchmark* benchmark;
|
||||
std::vector<int> arg;
|
||||
TimeUnit time_unit;
|
||||
int range_multiplier;
|
||||
bool use_real_time;
|
||||
bool use_manual_time;
|
||||
BigO complexity;
|
||||
BigOFunc* complexity_lambda;
|
||||
bool last_benchmark_instance;
|
||||
int repetitions;
|
||||
double min_time;
|
||||
int threads; // Number of concurrent threads to use
|
||||
bool multithreaded; // Is benchmark multi-threaded?
|
||||
};
|
||||
|
||||
// Class for managing registered benchmarks. Note that each registered
|
||||
|
@ -362,8 +359,8 @@ public:
|
|||
void Unit(TimeUnit unit);
|
||||
void Range(int start, int limit);
|
||||
void DenseRange(int start, int limit, int step = 1);
|
||||
void ArgPair(int start, int limit);
|
||||
void RangePair(int lo1, int hi1, int lo2, int hi2);
|
||||
void Args(const std::vector<int>& args);
|
||||
void Ranges(const std::vector<std::pair<int, int>>& ranges);
|
||||
void RangeMultiplier(int multiplier);
|
||||
void MinTime(double n);
|
||||
void Repetitions(int n);
|
||||
|
@ -378,12 +375,13 @@ public:
|
|||
|
||||
static void AddRange(std::vector<int>* dst, int lo, int hi, int mult);
|
||||
|
||||
int ArgsCnt() const { return args_.empty() ? -1 : static_cast<int>(args_.front().size()); }
|
||||
|
||||
private:
|
||||
friend class BenchmarkFamilies;
|
||||
|
||||
std::string name_;
|
||||
int arg_count_;
|
||||
std::vector< std::pair<int, int> > args_; // Args for all benchmark runs
|
||||
std::vector< std::vector<int> > args_; // Args for all benchmark runs
|
||||
TimeUnit time_unit_;
|
||||
int range_multiplier_;
|
||||
double min_time_;
|
||||
|
@ -431,10 +429,10 @@ bool BenchmarkFamilies::FindBenchmarks(
|
|||
if (!bench_family) continue;
|
||||
BenchmarkImp* family = bench_family->imp_;
|
||||
|
||||
if (family->arg_count_ == -1) {
|
||||
family->arg_count_ = 0;
|
||||
family->args_.emplace_back(-1, -1);
|
||||
if (family->ArgsCnt() == -1) {
|
||||
family->Args({});
|
||||
}
|
||||
|
||||
for (auto const& args : family->args_) {
|
||||
const std::vector<int>* thread_counts =
|
||||
(family->thread_counts_.empty()
|
||||
|
@ -445,10 +443,7 @@ bool BenchmarkFamilies::FindBenchmarks(
|
|||
Benchmark::Instance instance;
|
||||
instance.name = family->name_;
|
||||
instance.benchmark = bench_family.get();
|
||||
instance.has_arg1 = family->arg_count_ >= 1;
|
||||
instance.arg1 = args.first;
|
||||
instance.has_arg2 = family->arg_count_ == 2;
|
||||
instance.arg2 = args.second;
|
||||
instance.arg = args;
|
||||
instance.time_unit = family->time_unit_;
|
||||
instance.range_multiplier = family->range_multiplier_;
|
||||
instance.min_time = family->min_time_;
|
||||
|
@ -461,12 +456,10 @@ bool BenchmarkFamilies::FindBenchmarks(
|
|||
instance.multithreaded = !(family->thread_counts_.empty());
|
||||
|
||||
// Add arguments to instance name
|
||||
if (family->arg_count_ >= 1) {
|
||||
AppendHumanReadable(instance.arg1, &instance.name);
|
||||
}
|
||||
if (family->arg_count_ >= 2) {
|
||||
AppendHumanReadable(instance.arg2, &instance.name);
|
||||
for (auto const& arg : args) {
|
||||
AppendHumanReadable(arg, &instance.name);
|
||||
}
|
||||
|
||||
if (!IsZero(family->min_time_)) {
|
||||
instance.name += StringPrintF("/min_time:%0.3f", family->min_time_);
|
||||
}
|
||||
|
@ -495,7 +488,7 @@ bool BenchmarkFamilies::FindBenchmarks(
|
|||
}
|
||||
|
||||
BenchmarkImp::BenchmarkImp(const char* name)
|
||||
: name_(name), arg_count_(-1), time_unit_(kNanosecond),
|
||||
: name_(name), time_unit_(kNanosecond),
|
||||
range_multiplier_(kRangeMultiplier), min_time_(0.0), repetitions_(0),
|
||||
use_real_time_(false), use_manual_time_(false),
|
||||
complexity_(oNone) {
|
||||
|
@ -505,9 +498,8 @@ BenchmarkImp::~BenchmarkImp() {
|
|||
}
|
||||
|
||||
void BenchmarkImp::Arg(int x) {
|
||||
CHECK(arg_count_ == -1 || arg_count_ == 1);
|
||||
arg_count_ = 1;
|
||||
args_.emplace_back(x, -1);
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
args_.push_back({x});
|
||||
}
|
||||
|
||||
void BenchmarkImp::Unit(TimeUnit unit) {
|
||||
|
@ -515,42 +507,54 @@ void BenchmarkImp::Unit(TimeUnit unit) {
|
|||
}
|
||||
|
||||
void BenchmarkImp::Range(int start, int limit) {
|
||||
CHECK(arg_count_ == -1 || arg_count_ == 1);
|
||||
arg_count_ = 1;
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
std::vector<int> arglist;
|
||||
AddRange(&arglist, start, limit, range_multiplier_);
|
||||
|
||||
for (int i : arglist) {
|
||||
args_.emplace_back(i, -1);
|
||||
args_.push_back({i});
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkImp::DenseRange(int start, int limit, int step) {
|
||||
CHECK(arg_count_ == -1 || arg_count_ == 1);
|
||||
arg_count_ = 1;
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
CHECK_GE(start, 0);
|
||||
CHECK_LE(start, limit);
|
||||
for (int arg = start; arg <= limit; arg += step) {
|
||||
args_.emplace_back(arg, -1);
|
||||
for (int arg = start; arg <= limit; arg+= step) {
|
||||
args_.push_back({arg});
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkImp::ArgPair(int x, int y) {
|
||||
CHECK(arg_count_ == -1 || arg_count_ == 2);
|
||||
arg_count_ = 2;
|
||||
args_.emplace_back(x, y);
|
||||
void BenchmarkImp::Args(const std::vector<int>& args)
|
||||
{
|
||||
args_.push_back(args);
|
||||
}
|
||||
|
||||
void BenchmarkImp::RangePair(int lo1, int hi1, int lo2, int hi2) {
|
||||
CHECK(arg_count_ == -1 || arg_count_ == 2);
|
||||
arg_count_ = 2;
|
||||
std::vector<int> arglist1, arglist2;
|
||||
AddRange(&arglist1, lo1, hi1, range_multiplier_);
|
||||
AddRange(&arglist2, lo2, hi2, range_multiplier_);
|
||||
void BenchmarkImp::Ranges(const std::vector<std::pair<int, int>>& ranges) {
|
||||
std::vector<std::vector<int>> arglists(ranges.size());
|
||||
int total = 1;
|
||||
for (std::size_t i = 0; i < ranges.size(); i++) {
|
||||
AddRange(&arglists[i], ranges[i].first, ranges[i].second, range_multiplier_);
|
||||
total *= arglists[i].size();
|
||||
}
|
||||
|
||||
for (int i : arglist1) {
|
||||
for (int j : arglist2) {
|
||||
args_.emplace_back(i, j);
|
||||
std::vector<std::size_t> ctr(total, 0);
|
||||
|
||||
for (int i = 0; i < total; i++) {
|
||||
std::vector<int> tmp;
|
||||
|
||||
for (std::size_t j = 0; j < arglists.size(); j++) {
|
||||
tmp.push_back(arglists[j][ctr[j]]);
|
||||
}
|
||||
|
||||
args_.push_back(tmp);
|
||||
|
||||
for (std::size_t j = 0; j < arglists.size(); j++) {
|
||||
if (ctr[j] + 1 < arglists[j].size()) {
|
||||
++ctr[j];
|
||||
break;
|
||||
}
|
||||
ctr[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -648,6 +652,7 @@ Benchmark::Benchmark(Benchmark const& other)
|
|||
}
|
||||
|
||||
Benchmark* Benchmark::Arg(int x) {
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == 1);
|
||||
imp_->Arg(x);
|
||||
return this;
|
||||
}
|
||||
|
@ -658,22 +663,27 @@ Benchmark* Benchmark::Unit(TimeUnit unit) {
|
|||
}
|
||||
|
||||
Benchmark* Benchmark::Range(int start, int limit) {
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == 1);
|
||||
imp_->Range(start, limit);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Ranges(const std::vector<std::pair<int, int>>& ranges)
|
||||
{
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == static_cast<int>(ranges.size()));
|
||||
imp_->Ranges(ranges);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::DenseRange(int start, int limit, int step) {
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == 1);
|
||||
imp_->DenseRange(start, limit, step);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ArgPair(int x, int y) {
|
||||
imp_->ArgPair(x, y);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::RangePair(int lo1, int hi1, int lo2, int hi2) {
|
||||
imp_->RangePair(lo1, hi1, lo2, hi2);
|
||||
Benchmark* Benchmark::Args(const std::vector<int>& args) {
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == static_cast<int>(args.size()));
|
||||
imp_->Args(args);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -751,7 +761,7 @@ namespace {
|
|||
void RunInThread(const benchmark::internal::Benchmark::Instance* b,
|
||||
size_t iters, int thread_id,
|
||||
ThreadStats* total) EXCLUDES(GetBenchmarkLock()) {
|
||||
State st(iters, b->has_arg1, b->arg1, b->has_arg2, b->arg2, thread_id, b->threads);
|
||||
State st(iters, b->arg, thread_id, b->threads);
|
||||
b->benchmark->Run(st);
|
||||
CHECK(st.iterations() == st.max_iterations) <<
|
||||
"Benchmark returned before State::KeepRunning() returned false!";
|
||||
|
@ -925,11 +935,10 @@ RunBenchmark(const benchmark::internal::Benchmark::Instance& b,
|
|||
|
||||
} // namespace
|
||||
|
||||
State::State(size_t max_iters, bool has_x, int x, bool has_y, int y,
|
||||
State::State(size_t max_iters, const std::vector<int>& ranges,
|
||||
int thread_i, int n_threads)
|
||||
: started_(false), finished_(false), total_iterations_(0),
|
||||
has_range_x_(has_x), range_x_(x),
|
||||
has_range_y_(has_y), range_y_(y),
|
||||
range_(ranges),
|
||||
bytes_processed_(0), items_processed_(0),
|
||||
complexity_n_(0),
|
||||
error_occurred_(false),
|
||||
|
|
|
@ -51,6 +51,9 @@ add_test(register_benchmark_test register_benchmark_test --benchmark_min_time=0.
|
|||
compile_benchmark_test(map_test)
|
||||
add_test(map_test map_test --benchmark_min_time=0.01)
|
||||
|
||||
compile_benchmark_test(multiple_ranges_test)
|
||||
add_test(multiple_ranges_test multiple_ranges_test --benchmark_min_time=0.01)
|
||||
|
||||
compile_benchmark_test(reporter_output_test)
|
||||
add_test(reporter_output_test reporter_output_test --benchmark_min_time=0.01)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ BENCHMARK(BM_empty)->ThreadPerCpu();
|
|||
|
||||
void BM_spin_empty(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
for (int x = 0; x < state.range_x(); ++x) {
|
||||
for (int x = 0; x < state.range(0); ++x) {
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,11 @@ BASIC_BENCHMARK_TEST(BM_spin_empty);
|
|||
BASIC_BENCHMARK_TEST(BM_spin_empty)->ThreadPerCpu();
|
||||
|
||||
void BM_spin_pause_before(benchmark::State& state) {
|
||||
for (int i = 0; i < state.range_x(); ++i) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
while(state.KeepRunning()) {
|
||||
for (int i = 0; i < state.range_x(); ++i) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,11 @@ BASIC_BENCHMARK_TEST(BM_spin_pause_before)->ThreadPerCpu();
|
|||
void BM_spin_pause_during(benchmark::State& state) {
|
||||
while(state.KeepRunning()) {
|
||||
state.PauseTiming();
|
||||
for (int i = 0; i < state.range_x(); ++i) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
state.ResumeTiming();
|
||||
for (int i = 0; i < state.range_x(); ++i) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
|
@ -64,11 +64,11 @@ BENCHMARK(BM_pause_during)->UseRealTime()->ThreadPerCpu();
|
|||
|
||||
void BM_spin_pause_after(benchmark::State& state) {
|
||||
while(state.KeepRunning()) {
|
||||
for (int i = 0; i < state.range_x(); ++i) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < state.range_x(); ++i) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
|
@ -77,15 +77,15 @@ BASIC_BENCHMARK_TEST(BM_spin_pause_after)->ThreadPerCpu();
|
|||
|
||||
|
||||
void BM_spin_pause_before_and_after(benchmark::State& state) {
|
||||
for (int i = 0; i < state.range_x(); ++i) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
while(state.KeepRunning()) {
|
||||
for (int i = 0; i < state.range_x(); ++i) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < state.range_x(); ++i) {
|
||||
for (int i = 0; i < state.range(0); ++i) {
|
||||
benchmark::DoNotOptimize(i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ BENCHMARK(BM_Factorial)->UseRealTime();
|
|||
static void BM_CalculatePiRange(benchmark::State& state) {
|
||||
double pi = 0.0;
|
||||
while (state.KeepRunning())
|
||||
pi = CalculatePi(state.range_x());
|
||||
pi = CalculatePi(state.range(0));
|
||||
std::stringstream ss;
|
||||
ss << pi;
|
||||
state.SetLabel(ss.str());
|
||||
|
@ -87,25 +87,25 @@ BENCHMARK(BM_CalculatePi)->ThreadPerCpu();
|
|||
static void BM_SetInsert(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
state.PauseTiming();
|
||||
std::set<int> data = ConstructRandomSet(state.range_x());
|
||||
std::set<int> data = ConstructRandomSet(state.range(0));
|
||||
state.ResumeTiming();
|
||||
for (int j = 0; j < state.range_y(); ++j)
|
||||
for (int j = 0; j < state.range(1); ++j)
|
||||
data.insert(rand());
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * state.range_y());
|
||||
state.SetBytesProcessed(state.iterations() * state.range_y() * sizeof(int));
|
||||
state.SetItemsProcessed(state.iterations() * state.range(1));
|
||||
state.SetBytesProcessed(state.iterations() * state.range(1) * sizeof(int));
|
||||
}
|
||||
BENCHMARK(BM_SetInsert)->RangePair(1<<10,8<<10, 1,10);
|
||||
BENCHMARK(BM_SetInsert)->Ranges({{1<<10,8<<10}, {1,10}});
|
||||
|
||||
template<typename Container, typename ValueType = typename Container::value_type>
|
||||
static void BM_Sequential(benchmark::State& state) {
|
||||
ValueType v = 42;
|
||||
while (state.KeepRunning()) {
|
||||
Container c;
|
||||
for (int i = state.range_x(); --i; )
|
||||
for (int i = state.range(0); --i; )
|
||||
c.push_back(v);
|
||||
}
|
||||
const size_t items_processed = state.iterations() * state.range_x();
|
||||
const size_t items_processed = state.iterations() * state.range(0);
|
||||
state.SetItemsProcessed(items_processed);
|
||||
state.SetBytesProcessed(items_processed * sizeof(v));
|
||||
}
|
||||
|
@ -117,8 +117,8 @@ BENCHMARK_TEMPLATE(BM_Sequential, std::vector<int>, int)->Arg(512);
|
|||
#endif
|
||||
|
||||
static void BM_StringCompare(benchmark::State& state) {
|
||||
std::string s1(state.range_x(), '-');
|
||||
std::string s2(state.range_x(), '-');
|
||||
std::string s1(state.range(0), '-');
|
||||
std::string s2(state.range(0), '-');
|
||||
while (state.KeepRunning())
|
||||
benchmark::DoNotOptimize(s1.compare(s2));
|
||||
}
|
||||
|
@ -147,14 +147,14 @@ BENCHMARK(BM_SetupTeardown)->ThreadPerCpu();
|
|||
static void BM_LongTest(benchmark::State& state) {
|
||||
double tracker = 0.0;
|
||||
while (state.KeepRunning()) {
|
||||
for (int i = 0; i < state.range_x(); ++i)
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
benchmark::DoNotOptimize(tracker += i);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_LongTest)->Range(1<<16,1<<28);
|
||||
|
||||
static void BM_ParallelMemset(benchmark::State& state) {
|
||||
int size = state.range_x() / sizeof(int);
|
||||
int size = state.range(0) / sizeof(int);
|
||||
int thread_size = size / state.threads;
|
||||
int from = thread_size * state.thread_index;
|
||||
int to = from + thread_size;
|
||||
|
@ -179,7 +179,7 @@ BENCHMARK(BM_ParallelMemset)->Arg(10 << 20)->ThreadRange(1, 4);
|
|||
|
||||
static void BM_ManualTiming(benchmark::State& state) {
|
||||
size_t slept_for = 0;
|
||||
int microseconds = state.range_x();
|
||||
int microseconds = state.range(0);
|
||||
std::chrono::duration<double, std::micro> sleep_duration {
|
||||
static_cast<double>(microseconds)
|
||||
};
|
||||
|
|
|
@ -161,7 +161,7 @@ int AddComplexityTest(std::vector<TestCase>* console_out, std::vector<TestCase>*
|
|||
void BM_Complexity_O1(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
}
|
||||
state.SetComplexityN(state.range_x());
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
BENCHMARK(BM_Complexity_O1) -> Range(1, 1<<18) -> Complexity(benchmark::o1);
|
||||
BENCHMARK(BM_Complexity_O1) -> Range(1, 1<<18) -> Complexity();
|
||||
|
@ -198,12 +198,12 @@ std::vector<int> ConstructRandomVector(int size) {
|
|||
}
|
||||
|
||||
void BM_Complexity_O_N(benchmark::State& state) {
|
||||
auto v = ConstructRandomVector(state.range_x());
|
||||
const int item_not_in_vector = state.range_x()*2; // Test worst case scenario (item not in vector)
|
||||
auto v = ConstructRandomVector(state.range(0));
|
||||
const int item_not_in_vector = state.range(0)*2; // Test worst case scenario (item not in vector)
|
||||
while (state.KeepRunning()) {
|
||||
benchmark::DoNotOptimize(std::find(v.begin(), v.end(), item_not_in_vector));
|
||||
}
|
||||
state.SetComplexityN(state.range_x());
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
BENCHMARK(BM_Complexity_O_N) -> RangeMultiplier(2) -> Range(1<<10, 1<<16) -> Complexity(benchmark::oN);
|
||||
BENCHMARK(BM_Complexity_O_N) -> RangeMultiplier(2) -> Range(1<<10, 1<<16) -> Complexity([](int n) -> double{return n; });
|
||||
|
@ -227,11 +227,11 @@ ADD_COMPLEXITY_CASES(&ConsoleOutputTests, &JSONOutputTests, &CSVOutputTests,
|
|||
// ========================================================================= //
|
||||
|
||||
static void BM_Complexity_O_N_log_N(benchmark::State& state) {
|
||||
auto v = ConstructRandomVector(state.range_x());
|
||||
auto v = ConstructRandomVector(state.range(0));
|
||||
while (state.KeepRunning()) {
|
||||
std::sort(v.begin(), v.end());
|
||||
}
|
||||
state.SetComplexityN(state.range_x());
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
BENCHMARK(BM_Complexity_O_N_log_N) -> RangeMultiplier(2) -> Range(1<<10, 1<<16) -> Complexity(benchmark::oNLogN);
|
||||
BENCHMARK(BM_Complexity_O_N_log_N) -> RangeMultiplier(2) -> Range(1<<10, 1<<16) -> Complexity([](int n) {return n * std::log2(n); });
|
||||
|
|
|
@ -44,7 +44,7 @@ BENCHMARK_DEFINE_F(MyFixture, Bar)(benchmark::State& st) {
|
|||
assert(data.get() != nullptr);
|
||||
assert(*data == 42);
|
||||
}
|
||||
st.SetItemsProcessed(st.range_x());
|
||||
st.SetItemsProcessed(st.range(0));
|
||||
}
|
||||
BENCHMARK_REGISTER_F(MyFixture, Bar)->Arg(42);
|
||||
BENCHMARK_REGISTER_F(MyFixture, Bar)->Arg(42)->ThreadPerCpu();
|
||||
|
|
|
@ -17,7 +17,7 @@ std::map<int, int> ConstructRandomMap(int size) {
|
|||
|
||||
// Basic version.
|
||||
static void BM_MapLookup(benchmark::State& state) {
|
||||
const int size = state.range_x();
|
||||
const int size = state.range(0);
|
||||
while (state.KeepRunning()) {
|
||||
state.PauseTiming();
|
||||
std::map<int, int> m = ConstructRandomMap(size);
|
||||
|
@ -34,7 +34,7 @@ BENCHMARK(BM_MapLookup)->Range(1 << 3, 1 << 12);
|
|||
class MapFixture : public ::benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& st) {
|
||||
m = ConstructRandomMap(st.range_x());
|
||||
m = ConstructRandomMap(st.range(0));
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State&) {
|
||||
|
@ -45,7 +45,7 @@ class MapFixture : public ::benchmark::Fixture {
|
|||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(MapFixture, Lookup)(benchmark::State& state) {
|
||||
const int size = state.range_x();
|
||||
const int size = state.range(0);
|
||||
while (state.KeepRunning()) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
benchmark::DoNotOptimize(m.find(rand() % size));
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
class MultipleRangesFixture : public ::benchmark::Fixture {
|
||||
public:
|
||||
MultipleRangesFixture() {
|
||||
expectedValues = {
|
||||
{1, 3, 5}, {1, 3, 8}, {1, 3, 15}, {2, 3, 5}, {2, 3, 8}, {2, 3, 15},
|
||||
{1, 4, 5}, {1, 4, 8}, {1, 4, 15}, {2, 4, 5}, {2, 4, 8}, {2, 4, 15},
|
||||
{1, 7, 5}, {1, 7, 8}, {1, 7, 15}, {2, 7, 5}, {2, 7, 8}, {2, 7, 15},
|
||||
{7, 6, 3}
|
||||
};
|
||||
}
|
||||
|
||||
void SetUp(const ::benchmark::State& state) {
|
||||
std::vector<int> ranges = {state.range(0), state.range(1), state.range(2)};
|
||||
|
||||
assert(expectedValues.find(ranges) != expectedValues.end());
|
||||
|
||||
actualValues.insert(ranges);
|
||||
}
|
||||
|
||||
virtual ~MultipleRangesFixture() {
|
||||
assert(actualValues.size() == expectedValues.size());
|
||||
}
|
||||
|
||||
std::set<std::vector<int>> expectedValues;
|
||||
std::set<std::vector<int>> actualValues;
|
||||
};
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(MultipleRangesFixture, Empty)(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
int product = state.range(0) * state.range(1) * state.range(2);
|
||||
for (int x = 0; x < product; x++) {
|
||||
benchmark::DoNotOptimize(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(MultipleRangesFixture, Empty)->RangeMultiplier(2)->Ranges({{1, 2}, {3, 7}, {5, 15}})->Args({7, 6, 3});
|
||||
|
||||
BENCHMARK_MAIN()
|
|
@ -9,7 +9,7 @@ void BM_basic(benchmark::State& state) {
|
|||
}
|
||||
|
||||
void BM_basic_slow(benchmark::State& state) {
|
||||
std::chrono::milliseconds sleep_duration(state.range_x());
|
||||
std::chrono::milliseconds sleep_duration(state.range(0));
|
||||
while (state.KeepRunning()) {
|
||||
std::this_thread::sleep_for(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(sleep_duration)
|
||||
|
@ -25,8 +25,8 @@ BENCHMARK(BM_basic_slow)->Arg(1000)->Unit(benchmark::kMillisecond);
|
|||
BENCHMARK(BM_basic)->Range(1, 8);
|
||||
BENCHMARK(BM_basic)->RangeMultiplier(2)->Range(1, 8);
|
||||
BENCHMARK(BM_basic)->DenseRange(10, 15);
|
||||
BENCHMARK(BM_basic)->ArgPair(42, 42);
|
||||
BENCHMARK(BM_basic)->RangePair(64, 512, 64, 512);
|
||||
BENCHMARK(BM_basic)->Args({42, 42});
|
||||
BENCHMARK(BM_basic)->Ranges({{64, 512}, {64, 512}});
|
||||
BENCHMARK(BM_basic)->MinTime(0.7);
|
||||
BENCHMARK(BM_basic)->UseRealTime();
|
||||
BENCHMARK(BM_basic)->ThreadRange(2, 4);
|
||||
|
|
|
@ -185,7 +185,7 @@ ADD_CASES(&CSVOutputTests, {
|
|||
void BM_Complexity_O1(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
}
|
||||
state.SetComplexityN(state.range_x());
|
||||
state.SetComplexityN(state.range(0));
|
||||
}
|
||||
BENCHMARK(BM_Complexity_O1)->Range(1, 1<<18)->Complexity(benchmark::o1);
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ ADD_CASES("BM_error_before_running",
|
|||
void BM_error_during_running(benchmark::State& state) {
|
||||
int first_iter = true;
|
||||
while (state.KeepRunning()) {
|
||||
if (state.range_x() == 1 && state.thread_index <= (state.threads / 2)) {
|
||||
if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) {
|
||||
assert(first_iter);
|
||||
first_iter = false;
|
||||
state.SkipWithError("error message");
|
||||
|
@ -116,7 +116,7 @@ ADD_CASES(
|
|||
void BM_error_while_paused(benchmark::State& state) {
|
||||
bool first_iter = true;
|
||||
while (state.KeepRunning()) {
|
||||
if (state.range_x() == 1 && state.thread_index <= (state.threads / 2)) {
|
||||
if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) {
|
||||
assert(first_iter);
|
||||
first_iter = false;
|
||||
state.PauseTiming();
|
||||
|
|
Loading…
Reference in New Issue