Skip to content

Commit c515d26

Browse files
committed
bench: switch to std::chrono for time measurements
std::chrono removes portability issues. Rather than storing doubles, store the untouched time_points. Then convert to nanoseconds for display. This allows for maximum precision, while keeping results comparable between differing hardware/operating systems. Also, display full nanosecond counts rather than sub-second floats.
1 parent 57ee739 commit c515d26

File tree

3 files changed

+31
-29
lines changed

3 files changed

+31
-29
lines changed

src/bench/bench.cpp

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,22 @@
88
#include <assert.h>
99
#include <iostream>
1010
#include <iomanip>
11-
#include <sys/time.h>
1211

1312
benchmark::BenchRunner::BenchmarkMap &benchmark::BenchRunner::benchmarks() {
1413
static std::map<std::string, benchmark::BenchFunction> benchmarks_map;
1514
return benchmarks_map;
1615
}
1716

18-
static double gettimedouble(void) {
19-
struct timeval tv;
20-
gettimeofday(&tv, nullptr);
21-
return tv.tv_usec * 0.000001 + tv.tv_sec;
22-
}
23-
2417
benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
2518
{
2619
benchmarks().insert(std::make_pair(name, func));
2720
}
2821

2922
void
30-
benchmark::BenchRunner::RunAll(double elapsedTimeForOne)
23+
benchmark::BenchRunner::RunAll(benchmark::duration elapsedTimeForOne)
3124
{
3225
perf_init();
33-
std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << ","
26+
std::cout << "#Benchmark" << "," << "count" << "," << "min(ns)" << "," << "max(ns)" << "," << "average(ns)" << ","
3427
<< "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";
3528

3629
for (const auto &p: benchmarks()) {
@@ -46,16 +39,17 @@ bool benchmark::State::KeepRunning()
4639
++count;
4740
return true;
4841
}
49-
double now;
42+
time_point now;
43+
5044
uint64_t nowCycles;
5145
if (count == 0) {
52-
lastTime = beginTime = now = gettimedouble();
46+
lastTime = beginTime = now = clock::now();
5347
lastCycles = beginCycles = nowCycles = perf_cpucycles();
5448
}
5549
else {
56-
now = gettimedouble();
57-
double elapsed = now - lastTime;
58-
double elapsedOne = elapsed / (countMask + 1);
50+
now = clock::now();
51+
auto elapsed = now - lastTime;
52+
auto elapsedOne = elapsed / (countMask + 1);
5953
if (elapsedOne < minTime) minTime = elapsedOne;
6054
if (elapsedOne > maxTime) maxTime = elapsedOne;
6155

@@ -70,8 +64,8 @@ bool benchmark::State::KeepRunning()
7064
// The restart avoids including the overhead of this code in the measurement.
7165
countMask = ((countMask<<3)|7) & ((1LL<<60)-1);
7266
count = 0;
73-
minTime = std::numeric_limits<double>::max();
74-
maxTime = std::numeric_limits<double>::min();
67+
minTime = duration::max();
68+
maxTime = duration::zero();
7569
minCycles = std::numeric_limits<uint64_t>::max();
7670
maxCycles = std::numeric_limits<uint64_t>::min();
7771
return true;
@@ -94,9 +88,13 @@ bool benchmark::State::KeepRunning()
9488
assert(count != 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
9589

9690
// Output results
97-
double average = (now-beginTime)/count;
91+
// Duration casts are only necessary here because hardware with sub-nanosecond clocks
92+
// will lose precision.
93+
int64_t min_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(minTime).count();
94+
int64_t max_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(maxTime).count();
95+
int64_t avg_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>((now-beginTime)/count).count();
9896
int64_t averageCycles = (nowCycles-beginCycles)/count;
99-
std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << ","
97+
std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << min_elapsed << "," << max_elapsed << "," << avg_elapsed << ","
10098
<< minCycles << "," << maxCycles << "," << averageCycles << "\n";
10199
std::cout.copyfmt(std::ios(nullptr));
102100

src/bench/bench.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <limits>
1010
#include <map>
1111
#include <string>
12+
#include <chrono>
1213

1314
#include <boost/preprocessor/cat.hpp>
1415
#include <boost/preprocessor/stringize.hpp>
@@ -37,21 +38,25 @@ BENCHMARK(CODE_TO_TIME);
3738

3839
namespace benchmark {
3940

41+
using clock = std::chrono::high_resolution_clock;
42+
using time_point = clock::time_point;
43+
using duration = clock::duration;
44+
4045
class State {
4146
std::string name;
42-
double maxElapsed;
43-
double beginTime;
44-
double lastTime, minTime, maxTime;
47+
duration maxElapsed;
48+
time_point beginTime, lastTime;
49+
duration minTime, maxTime;
4550
uint64_t count;
4651
uint64_t countMask;
4752
uint64_t beginCycles;
4853
uint64_t lastCycles;
4954
uint64_t minCycles;
5055
uint64_t maxCycles;
5156
public:
52-
State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
53-
minTime = std::numeric_limits<double>::max();
54-
maxTime = std::numeric_limits<double>::min();
57+
State(std::string _name, duration _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
58+
minTime = duration::max();
59+
maxTime = duration::zero();
5560
minCycles = std::numeric_limits<uint64_t>::max();
5661
maxCycles = std::numeric_limits<uint64_t>::min();
5762
countMask = 1;
@@ -69,7 +74,7 @@ namespace benchmark {
6974
public:
7075
BenchRunner(std::string name, BenchFunction func);
7176

72-
static void RunAll(double elapsedTimeForOne=1.0);
77+
static void RunAll(duration elapsedTimeForOne = std::chrono::seconds(1));
7378
};
7479
}
7580

src/bench/rollingbloom.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
#include "bench.h"
88
#include "bloom.h"
9-
#include "utiltime.h"
109

1110
static void RollingBloom(benchmark::State& state)
1211
{
@@ -23,10 +22,10 @@ static void RollingBloom(benchmark::State& state)
2322
data[2] = count >> 16;
2423
data[3] = count >> 24;
2524
if (countnow == nEntriesPerGeneration) {
26-
int64_t b = GetTimeMicros();
25+
auto b = benchmark::clock::now();
2726
filter.insert(data);
28-
int64_t e = GetTimeMicros();
29-
std::cout << "RollingBloom-refresh,1," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "\n";
27+
auto total = std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark::clock::now() - b).count();
28+
std::cout << "RollingBloom-refresh,1," << total << "," << total << "," << total << "\n";
3029
countnow = 0;
3130
} else {
3231
filter.insert(data);

0 commit comments

Comments
 (0)