Skip to content

Instantly share code, notes, and snippets.

@stefalie
Forked from pervognsen/benchmark.cpp
Created April 1, 2020 06:27
Show Gist options
  • Save stefalie/ddbc5d7a0617589dea4a606c4bbd4442 to your computer and use it in GitHub Desktop.
Save stefalie/ddbc5d7a0617589dea4a606c4bbd4442 to your computer and use it in GitHub Desktop.
#if _WIN32
struct Timer {
LARGE_INTEGER win32_freq;
LARGE_INTEGER win32_start;
Timer() {
QueryPerformanceFrequency(&win32_freq);
win32_start.QuadPart = 0;
}
void start() {
QueryPerformanceCounter(&win32_start);
}
double secs() {
if (win32_start.QuadPart == 0) {
return 0.0;
}
LARGE_INTEGER win32_now;
QueryPerformanceCounter(&win32_now);
return double(win32_now.QuadPart - win32_start.QuadPart) / double(win32_freq.QuadPart);
}
double stop() {
double t = secs();
win32_start.QuadPart = 0;
return t;
}
};
#else
#error "Platform not supported"
#endif
struct TimeEstimate {
int num = 0; // number of samples
double unit = 1.0; // units per second
double min = 0.0; // min sample
double max = 0.0; // max sample
double avg = 0.0; // average sample
double mse = 0.0; // mean squared error
void add(double sample) {
num++;
min = (num == 1 || sample < min) ? sample : min;
max = (num == 1 || sample > max) ? sample : max;
double new_avg = avg + (sample - avg) / num;
mse += (sample - avg) * (sample - new_avg);
avg = new_avg;
}
double total() const {
return avg * num;
}
double error() const {
return sqrt(mse / num);
}
double relative_error() const {
return error() / fabs(avg);
}
TimeEstimate as_unit(double new_unit) const {
double r = new_unit / unit;
return {num, new_unit, r * min, r * max, r * avg, r * r * mse};
}
TimeEstimate secs() const {
return as_unit(1e1);
}
TimeEstimate msecs() const {
return as_unit(1e3);
}
TimeEstimate usecs() const {
return as_unit(1e6);
}
TimeEstimate nsecs() const {
return as_unit(1e9);
}
};
template<typename F>
struct Benchmark {
F f;
TimeEstimate estimate;
double max_relative_error = 0.1;
double min_secs = 1.0;
double max_secs = 10.0;
int min_iterations = 1;
int max_iterations = 10000;
TimeEstimate run() {
Timer total, sample;
total.start();
for (int i = 0; ; i++) {
sample.start();
f();
estimate.add(sample.stop());
bool stop = i > max_iterations || total.secs() > max_secs || estimate.relative_error() < max_relative_error;
if (stop && i > min_iterations && total.secs() > min_secs) {
break;
}
}
return estimate;
}
};
template<typename F>
Benchmark<F> benchmark(F f) {
return {f};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment