/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
DEFINE_bool(benchmark, false, "Run benchmarks.");
DEFINE_bool(json, false, "Output in JSON format.");
-DEFINE_string(bm_regex, "",
- "Only benchmarks whose names match this regex will be run.");
+DEFINE_string(
+ bm_regex,
+ "",
+ "Only benchmarks whose names match this regex will be run.");
-DEFINE_int64(bm_min_usec, 100,
- "Minimum # of microseconds we'll accept for each benchmark.");
+DEFINE_int64(
+ bm_min_usec,
+ 100,
+ "Minimum # of microseconds we'll accept for each benchmark.");
-DEFINE_int64(bm_min_iters, 1,
- "Minimum # of iterations we'll try for each benchmark.");
+DEFINE_int32(
+ bm_min_iters,
+ 1,
+ "Minimum # of iterations we'll try for each benchmark.");
-DEFINE_int32(bm_max_secs, 1,
- "Maximum # of seconds we'll spend on each benchmark.");
+DEFINE_int64(
+ bm_max_iters,
+ 1L << 30L,
+ "Maximum # of iterations we'll try for each benchmark.");
+DEFINE_int32(
+ bm_max_secs,
+ 1,
+ "Maximum # of seconds we'll spend on each benchmark.");
namespace folly {
#endif
}
-int getGlobalBenchmarkBaselineIndex() {
+size_t getGlobalBenchmarkBaselineIndex() {
const char *global = FB_STRINGIZE_X2(FB_FOLLY_GLOBAL_BENCHMARK_BASELINE);
auto it = std::find_if(
benchmarks().begin(),
}
);
CHECK(it != benchmarks().end());
- return it - benchmarks().begin();
+ return size_t(std::distance(benchmarks().begin(), it));
}
#undef FB_STRINGIZE_X2
benchmarks().emplace_back(file, name, std::move(fun));
}
-/**
- * Given a point, gives density at that point as a number 0.0 < x <=
- * 1.0. The result is 1.0 if all samples are equal to where, and
- * decreases near 0 if all points are far away from it. The density is
- * computed with the help of a radial basis function.
- */
-static double density(const double * begin, const double *const end,
- const double where, const double bandwidth) {
- assert(begin < end);
- assert(bandwidth > 0.0);
- double sum = 0.0;
- FOR_EACH_RANGE (i, begin, end) {
- auto d = (*i - where) / bandwidth;
- sum += exp(- d * d);
- }
- return sum / (end - begin);
-}
-
-/**
- * Computes mean and variance for a bunch of data points. Note that
- * mean is currently not being used.
- */
-static pair<double, double>
-meanVariance(const double * begin, const double *const end) {
- assert(begin < end);
- double sum = 0.0, sum2 = 0.0;
- FOR_EACH_RANGE (i, begin, end) {
- sum += *i;
- sum2 += *i * *i;
- }
- auto const n = end - begin;
- return make_pair(sum / n, sqrt((sum2 - sum * sum / n) / n));
-}
-
-/**
- * Computes the mode of a sample set through brute force. Assumes
- * input is sorted.
- */
-static double mode(const double * begin, const double *const end) {
- assert(begin < end);
- // Lower bound and upper bound for result and their respective
- // densities.
- auto
- result = 0.0,
- bestDensity = 0.0;
-
- // Get the variance so we pass it down to density()
- auto const sigma = meanVariance(begin, end).second;
- if (!sigma) {
- // No variance means constant signal
- return *begin;
- }
-
- FOR_EACH_RANGE (i, begin, end) {
- assert(i == begin || *i >= i[-1]);
- auto candidate = density(begin, end, *i, sigma * sqrt(2.0));
- if (candidate > bestDensity) {
- // Found a new best
- bestDensity = candidate;
- result = *i;
- } else {
- // Density is decreasing... we could break here if we definitely
- // knew this is unimodal.
- }
- }
-
- return result;
-}
-
/**
* Given a bunch of benchmark samples, estimate the actual run time.
*/
// Current state of the art: get the minimum. After some
// experimentation, it seems taking the minimum is the best.
-
return *min_element(begin, end);
-
- // What follows after estimates the time as the mode of the
- // distribution.
-
- // Select the awesomest (i.e. most frequent) result. We do this by
- // sorting and then computing the longest run length.
- sort(begin, end);
-
- // Eliminate outliers. A time much larger than the minimum time is
- // considered an outlier.
- while (end[-1] > 2.0 * *begin) {
- --end;
- if (begin == end) {
- LOG(INFO) << *begin;
- }
- assert(begin < end);
- }
-
- double result = 0;
-
- /* Code used just for comparison purposes */ {
- unsigned bestFrequency = 0;
- unsigned candidateFrequency = 1;
- double candidateValue = *begin;
- for (auto current = begin + 1; ; ++current) {
- if (current == end || *current != candidateValue) {
- // Done with the current run, see if it was best
- if (candidateFrequency > bestFrequency) {
- bestFrequency = candidateFrequency;
- result = candidateValue;
- }
- if (current == end) {
- break;
- }
- // Start a new run
- candidateValue = *current;
- candidateFrequency = 1;
- } else {
- // Cool, inside a run, increase the frequency
- ++candidateFrequency;
- }
- }
- }
-
- result = mode(begin, end);
-
- return result;
}
static double runBenchmarkGetNSPerIteration(const BenchmarkFun& fun,
static uint64_t resolutionInNs = 0;
if (!resolutionInNs) {
timespec ts;
- CHECK_EQ(0, clock_getres(detail::DEFAULT_CLOCK_ID, &ts));
+ CHECK_EQ(0, clock_getres(CLOCK_REALTIME, &ts));
CHECK_EQ(0, ts.tv_sec) << "Clock sucks.";
CHECK_LT(0, ts.tv_nsec) << "Clock too fast for its own good.";
CHECK_EQ(1, ts.tv_nsec) << "Clock too coarse, upgrade your kernel.";
size_t actualEpochs = 0;
for (; actualEpochs < epochs; ++actualEpochs) {
- for (unsigned int n = FLAGS_bm_min_iters; n < (1UL << 30); n *= 2) {
+ const auto maxIters = FLAGS_bm_max_iters;
+ for (unsigned int n = FLAGS_bm_min_iters; n < maxIters; n *= 2) {
auto const nsecsAndIter = fun(n);
if (nsecsAndIter.first < minNanoseconds) {
continue;
s.resize(columns - 29, ' ');
auto nsPerIter = get<2>(datum);
auto secPerIter = nsPerIter / 1E9;
- auto itersPerSec = 1 / secPerIter;
+ auto itersPerSec = (secPerIter == 0)
+ ? std::numeric_limits<double>::infinity()
+ : (1 / secPerIter);
if (!useBaseline) {
// Print without baseline
printf("%*s %9s %7s\n",
// PLEASE KEEP QUIET. MEASUREMENTS IN PROGRESS.
- unsigned int baselineIndex = getGlobalBenchmarkBaselineIndex();
+ size_t baselineIndex = getGlobalBenchmarkBaselineIndex();
auto const globalBaseline =
runBenchmarkGetNSPerIteration(get<2>(benchmarks()[baselineIndex]), 0);