Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bench: use std::chrono rather than gettimeofday #11562

Merged
merged 2 commits into from Nov 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 16 additions & 18 deletions src/bench/bench.cpp
Expand Up @@ -8,29 +8,22 @@
#include <assert.h>
#include <iostream>
#include <iomanip>
#include <sys/time.h>

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

static double gettimedouble(void) {
struct timeval tv;
gettimeofday(&tv, nullptr);
return tv.tv_usec * 0.000001 + tv.tv_sec;
}

benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
{
benchmarks().insert(std::make_pair(name, func));
}

void
benchmark::BenchRunner::RunAll(double elapsedTimeForOne)
benchmark::BenchRunner::RunAll(benchmark::duration elapsedTimeForOne)
{
perf_init();
std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << ","
std::cout << "#Benchmark" << "," << "count" << "," << "min(ns)" << "," << "max(ns)" << "," << "average(ns)" << ","
<< "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";

for (const auto &p: benchmarks()) {
Expand All @@ -46,16 +39,17 @@ bool benchmark::State::KeepRunning()
++count;
return true;
}
double now;
time_point now;

uint64_t nowCycles;
if (count == 0) {
lastTime = beginTime = now = gettimedouble();
lastTime = beginTime = now = clock::now();
lastCycles = beginCycles = nowCycles = perf_cpucycles();
}
else {
now = gettimedouble();
double elapsed = now - lastTime;
double elapsedOne = elapsed / (countMask + 1);
now = clock::now();
auto elapsed = now - lastTime;
auto elapsedOne = elapsed / (countMask + 1);
if (elapsedOne < minTime) minTime = elapsedOne;
if (elapsedOne > maxTime) maxTime = elapsedOne;

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

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

Expand Down
26 changes: 19 additions & 7 deletions src/bench/bench.h
Expand Up @@ -9,6 +9,7 @@
#include <limits>
#include <map>
#include <string>
#include <chrono>

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
Expand Down Expand Up @@ -36,22 +37,33 @@ BENCHMARK(CODE_TO_TIME);
*/

namespace benchmark {
// On many systems, the high_resolution_clock offers no better resolution than the steady_clock.
// If that's the case, prefer the steady_clock.
struct best_clock {
using hi_res_clock = std::chrono::high_resolution_clock;
using steady_clock = std::chrono::steady_clock;
static constexpr bool steady_is_high_res = std::ratio_less_equal<steady_clock::period, hi_res_clock::period>::value;
using type = std::conditional<steady_is_high_res, steady_clock, hi_res_clock>::type;
};
using clock = best_clock::type;
using time_point = clock::time_point;
using duration = clock::duration;

class State {
std::string name;
double maxElapsed;
double beginTime;
double lastTime, minTime, maxTime;
duration maxElapsed;
time_point beginTime, lastTime;
duration minTime, maxTime;
uint64_t count;
uint64_t countMask;
uint64_t beginCycles;
uint64_t lastCycles;
uint64_t minCycles;
uint64_t maxCycles;
public:
State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
minTime = std::numeric_limits<double>::max();
maxTime = std::numeric_limits<double>::min();
State(std::string _name, duration _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
minTime = duration::max();
maxTime = duration::zero();
minCycles = std::numeric_limits<uint64_t>::max();
maxCycles = std::numeric_limits<uint64_t>::min();
countMask = 1;
Expand All @@ -69,7 +81,7 @@ namespace benchmark {
public:
BenchRunner(std::string name, BenchFunction func);

static void RunAll(double elapsedTimeForOne=1.0);
static void RunAll(duration elapsedTimeForOne = std::chrono::seconds(1));
};
}

Expand Down
7 changes: 3 additions & 4 deletions src/bench/rollingbloom.cpp
Expand Up @@ -6,7 +6,6 @@

#include "bench.h"
#include "bloom.h"
#include "utiltime.h"

static void RollingBloom(benchmark::State& state)
{
Expand All @@ -23,10 +22,10 @@ static void RollingBloom(benchmark::State& state)
data[2] = count >> 16;
data[3] = count >> 24;
if (countnow == nEntriesPerGeneration) {
int64_t b = GetTimeMicros();
auto b = benchmark::clock::now();
filter.insert(data);
int64_t e = GetTimeMicros();
std::cout << "RollingBloom-refresh,1," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "\n";
auto total = std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark::clock::now() - b).count();
std::cout << "RollingBloom-refresh,1," << total << "," << total << "," << total << "\n";
countnow = 0;
} else {
filter.insert(data);
Expand Down