108 lines
2.5 KiB
C++

#ifndef SIGNALSMITH_STOPWATCH_UTIL_H
#define SIGNALSMITH_STOPWATCH_UTIL_H
#include <limits>
#include <cmath>
#include <atomic>
#include <algorithm>
#ifdef WINDOWS // completely untested!
# include <windows.h>
namespace signalsmith {
class Stopwatch {
using Time = __int64;
using Duration = Time;
inline Time now() {
LARGE_INTEGER result;
QueryPerformanceCounter(&result);
return result.QuadPart;
}
static double toSeconds(Duration t) {
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
return t/double(freq);
}
#else
# include <chrono>
namespace signalsmith {
class Stopwatch {
using Clock = std::conditional<std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock, std::chrono::steady_clock>::type;
using Time = Clock::time_point;
using Duration = std::chrono::duration<double>;
inline Time now() {
return Clock::now();
}
static double toSeconds(Duration duration) {
return duration.count();
}
#endif
std::atomic<Time> lapStart; // the atomic store/load should act as barriers for reordering operations
double lapBest, lapTotal, lapTotal2;
double lapOverhead = 0;
int lapCount = 0;
public:
Stopwatch(bool compensate=true) {
if (compensate) {
start();
const int repeats = 1000;
for (int i = 0; i < repeats; ++i) {
startLap();
lap();
}
lapOverhead = (double)lapTotal/lapCount;
}
start();
}
// Explicit because std::atomic<> can't be copied/moved
Stopwatch(const Stopwatch &other) : lapBest(other.lapBest), lapTotal(other.lapTotal), lapTotal2(other.lapTotal2), lapOverhead(other.lapOverhead), lapCount(other.lapCount) {
lapStart.store(other.lapStart.load());
}
void start() {
lapCount = 0;
lapTotal = lapTotal2 = 0;
lapBest = std::numeric_limits<double>::max();
startLap();
}
void startLap() {
lapStart.store(now());
}
double lap() {
double diff = toSeconds(now() - lapStart.load());
if (diff < lapBest) lapBest = diff;
lapCount++;
lapTotal += diff;
lapTotal2 += diff*diff;
startLap();
return diff;
}
double total() const {
return std::max(0.0, lapTotal - lapCount*lapOverhead);
}
double mean() const {
return total()/lapCount;
}
double var() const {
double m = (double)lapTotal/lapCount, m2 = (double)lapTotal2/lapCount;
return std::max(0.0, m2 - m*m);
}
double std() const {
return sqrt(var());
}
double best() const {
return std::max(0.0, lapBest - lapOverhead);
}
double optimistic(double deviations=1) const {
return std::max(best(), mean() - std()*deviations);
}
};
} //namespace
#endif // include guard