X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FBenchmark.cpp;h=aada48b5e7f13262449e186294446711297100e8;hb=b0c9ca0f0ebd6dd13d0e4a4525c862358c92fee1;hp=627972ab132dc9968b5b45bab3b028455f6175bf;hpb=b05969e4b4474cadf1cb1f8ebc37567cc63c9b88;p=folly.git diff --git a/folly/Benchmark.cpp b/folly/Benchmark.cpp index 627972ab..aada48b5 100644 --- a/folly/Benchmark.cpp +++ b/folly/Benchmark.cpp @@ -1,5 +1,5 @@ /* - * 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. @@ -35,18 +35,30 @@ using namespace std; 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 { @@ -72,7 +84,7 @@ BENCHMARK(FB_FOLLY_GLOBAL_BENCHMARK_BASELINE) { #endif } -int getGlobalBenchmarkBaselineIndex() { +size_t getGlobalBenchmarkBaselineIndex() { const char *global = FB_STRINGIZE_X2(FB_FOLLY_GLOBAL_BENCHMARK_BASELINE); auto it = std::find_if( benchmarks().begin(), @@ -82,7 +94,7 @@ int getGlobalBenchmarkBaselineIndex() { } ); CHECK(it != benchmarks().end()); - return it - benchmarks().begin(); + return size_t(std::distance(benchmarks().begin(), it)); } #undef FB_STRINGIZE_X2 @@ -93,75 +105,6 @@ void detail::addBenchmarkImpl(const char* file, const char* name, 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 -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. */ @@ -170,55 +113,7 @@ static double estimateTime(double * begin, double * end) { // 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, @@ -229,7 +124,7 @@ 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."; @@ -255,7 +150,8 @@ static double runBenchmarkGetNSPerIteration(const BenchmarkFun& fun, 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; @@ -397,7 +293,9 @@ static void printBenchmarkResultsAsTable( s.resize(columns - 29, ' '); auto nsPerIter = get<2>(datum); auto secPerIter = nsPerIter / 1E9; - auto itersPerSec = 1 / secPerIter; + auto itersPerSec = (secPerIter == 0) + ? std::numeric_limits::infinity() + : (1 / secPerIter); if (!useBaseline) { // Print without baseline printf("%*s %9s %7s\n", @@ -450,7 +348,7 @@ void runBenchmarks() { // PLEASE KEEP QUIET. MEASUREMENTS IN PROGRESS. - unsigned int baselineIndex = getGlobalBenchmarkBaselineIndex(); + size_t baselineIndex = getGlobalBenchmarkBaselineIndex(); auto const globalBaseline = runBenchmarkGetNSPerIteration(get<2>(benchmarks()[baselineIndex]), 0);