-
-
Save stefalie/ddbc5d7a0617589dea4a606c4bbd4442 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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