Added test file and Complexity() interface

This commit is contained in:
Ismael 2016-05-18 19:59:34 +02:00
parent 0a60062b3e
commit 27f0baa190
4 changed files with 144 additions and 2 deletions

View File

@ -231,6 +231,20 @@ enum TimeUnit {
kMillisecond
};
// BigO is passed to a benchmark in order to specify the asymptotic computational
// complexity for the benchmark.
enum BigO {
O_None,
O_1,
O_N,
O_M_plus_N,
O_N_Squared,
O_N_Cubed,
O_log_N,
O_N_log_N,
O_Auto
};
// State is passed to a running Benchmark and contains state for the
// benchmark to use.
class State {
@ -465,6 +479,10 @@ public:
// to control how many iterations are run, and in the printing of items/second
// or MB/second values.
Benchmark* UseManualTime();
// Set the asymptotic computational complexity for the benchmark. This option
// called the asymptotic computational complexity will be shown on the output.
Benchmark* Complexity(BigO complexity);
// Support for running multiple copies of the same benchmark concurrently
// in multiple threads. This may be useful when measuring the scaling

View File

@ -290,6 +290,7 @@ struct Benchmark::Instance {
int range_multiplier;
bool use_real_time;
bool use_manual_time;
BigO complexity;
double min_time;
int threads; // Number of concurrent threads to use
bool multithreaded; // Is benchmark multi-threaded?
@ -331,6 +332,7 @@ public:
void MinTime(double n);
void UseRealTime();
void UseManualTime();
void Complexity(BigO complexity);
void Threads(int t);
void ThreadRange(int min_threads, int max_threads);
void ThreadPerCpu();
@ -349,6 +351,7 @@ private:
double min_time_;
bool use_real_time_;
bool use_manual_time_;
BigO complexity_;
std::vector<int> thread_counts_;
BenchmarkImp& operator=(BenchmarkImp const&);
@ -411,6 +414,7 @@ bool BenchmarkFamilies::FindBenchmarks(
instance.min_time = family->min_time_;
instance.use_real_time = family->use_real_time_;
instance.use_manual_time = family->use_manual_time_;
instance.complexity = family->complexity_;
instance.threads = num_threads;
instance.multithreaded = !(family->thread_counts_.empty());
@ -447,7 +451,8 @@ bool BenchmarkFamilies::FindBenchmarks(
BenchmarkImp::BenchmarkImp(const char* name)
: name_(name), arg_count_(-1), time_unit_(kNanosecond),
range_multiplier_(kRangeMultiplier), min_time_(0.0),
use_real_time_(false), use_manual_time_(false) {
use_real_time_(false), use_manual_time_(false),
complexity_(O_None) {
}
BenchmarkImp::~BenchmarkImp() {
@ -523,6 +528,10 @@ void BenchmarkImp::UseManualTime() {
use_manual_time_ = true;
}
void BenchmarkImp::Complexity(BigO complexity){
complexity_ = complexity;
}
void BenchmarkImp::Threads(int t) {
CHECK_GT(t, 0);
thread_counts_.push_back(t);
@ -636,6 +645,11 @@ Benchmark* Benchmark::UseManualTime() {
return this;
}
Benchmark* Benchmark::Complexity(BigO complexity) {
imp_->Complexity(complexity);
return this;
}
Benchmark* Benchmark::Threads(int t) {
imp_->Threads(t);
return this;

View File

@ -47,6 +47,9 @@ set_target_properties(cxx03_test
PROPERTIES COMPILE_FLAGS "${CXX03_FLAGS}")
add_test(cxx03 cxx03_test --benchmark_min_time=0.01)
compile_benchmark_test(complexity_test)
add_test(complexity_benchmark complexity_test --benchmark_min_time=0.01)
# Add the coverage command(s)
if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
@ -66,7 +69,7 @@ if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage")
COMMAND ${LCOV} -q -a before.lcov -a after.lcov --output-file final.lcov
COMMAND ${LCOV} -q -r final.lcov "'${CMAKE_SOURCE_DIR}/test/*'" -o final.lcov
COMMAND ${GENHTML} final.lcov -o lcov --demangle-cpp --sort -p "${CMAKE_BINARY_DIR}" -t benchmark
DEPENDS filter_test benchmark_test options_test basic_test fixture_test cxx03_test
DEPENDS filter_test benchmark_test options_test basic_test fixture_test cxx03_test complexity_test
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Running LCOV"
)

107
test/complexity_test.cc Normal file
View File

@ -0,0 +1,107 @@
#include "benchmark/benchmark_api.h"
#include <string>
#include <vector>
#include <map>
#include <algorithm>
std::vector<int> ConstructRandomVector(int size) {
std::vector<int> v;
v.reserve(size);
for (int i = 0; i < size; ++i) {
v.push_back(rand() % size);
}
return v;
}
std::map<int, int> ConstructRandomMap(int size) {
std::map<int, int> m;
for (int i = 0; i < size; ++i) {
m.insert(std::make_pair(rand() % size, rand() % size));
}
return m;
}
void BM_Complexity_O1(benchmark::State& state) {
while (state.KeepRunning()) {
}
}
BENCHMARK(BM_Complexity_O1) -> Range(1, 1<<17) -> Complexity(benchmark::O_1);
static void BM_Complexity_O_N(benchmark::State& state) {
auto v = ConstructRandomVector(state.range_x());
const int itemNotInVector = state.range_x()*2; // Test worst case scenario (item not in vector)
while (state.KeepRunning()) {
benchmark::DoNotOptimize(std::find(v.begin(), v.end(), itemNotInVector));
}
}
BENCHMARK(BM_Complexity_O_N) -> Range(1, 1<<10) -> Complexity(benchmark::O_N);
BENCHMARK(BM_Complexity_O_N) -> Range(1, 1<<10) -> Complexity(benchmark::O_Auto);
static void BM_Complexity_O_M_plus_N(benchmark::State& state) {
std::string s1(state.range_x(), '-');
std::string s2(state.range_x(), '-');
while (state.KeepRunning())
benchmark::DoNotOptimize(s1.compare(s2));
}
BENCHMARK(BM_Complexity_O_M_plus_N)
->RangeMultiplier(2)->Range(1<<10, 1<<18) -> Complexity(benchmark::O_M_plus_N);
static void BM_Complexity_O_N_Squared(benchmark::State& state) {
std::string s1(state.range_x(), '-');
std::string s2(state.range_x(), '-');
while (state.KeepRunning())
for(char& c1 : s1) {
for(char& c2 : s2) {
benchmark::DoNotOptimize(c1 = 'a');
benchmark::DoNotOptimize(c2 = 'b');
}
}
}
BENCHMARK(BM_Complexity_O_N_Squared) -> Range(1, 1<<8) -> Complexity(benchmark::O_N_Squared);
static void BM_Complexity_O_N_Cubed(benchmark::State& state) {
std::string s1(state.range_x(), '-');
std::string s2(state.range_x(), '-');
std::string s3(state.range_x(), '-');
while (state.KeepRunning())
for(char& c1 : s1) {
for(char& c2 : s2) {
for(char& c3 : s3) {
benchmark::DoNotOptimize(c1 = 'a');
benchmark::DoNotOptimize(c2 = 'b');
benchmark::DoNotOptimize(c3 = 'c');
}
}
}
}
BENCHMARK(BM_Complexity_O_N_Cubed) -> DenseRange(1, 8) -> Complexity(benchmark::O_N_Cubed);
static void BM_Complexity_O_log_N(benchmark::State& state) {
auto m = ConstructRandomMap(state.range_x());
const int itemNotInVector = state.range_x()*2; // Test worst case scenario (item not in vector)
while (state.KeepRunning()) {
benchmark::DoNotOptimize(m.find(itemNotInVector));
}
}
BENCHMARK(BM_Complexity_O_log_N) -> Range(1, 1<<10) -> Complexity(benchmark::O_log_N);
static void BM_Complexity_O_N_log_N(benchmark::State& state) {
auto v = ConstructRandomVector(state.range_x());
while (state.KeepRunning()) {
std::sort(v.begin(), v.end());
}
}
BENCHMARK(BM_Complexity_O_N_log_N) -> Range(1, 1<<16) -> Complexity(benchmark::O_N_log_N);
BENCHMARK(BM_Complexity_O_N_log_N) -> Range(1, 1<<16) -> Complexity(benchmark::O_Auto);
// Test benchmark with no range. Complexity is always calculated as O(1).
void BM_Extreme_Cases(benchmark::State& state) {
while (state.KeepRunning()) {
}
}
BENCHMARK(BM_Extreme_Cases);
BENCHMARK(BM_Extreme_Cases)->Arg(42);
BENCHMARK_MAIN()