X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FBenchmark.h;h=025c795ca54c02a003361ec6b676413951b9e651;hb=cd1bdc912603c0358ba733d379a74ae90ab3a437;hp=e954798790510b26f203f96229464fe5fd518a54;hpb=fa172175980b13569ba42008202a857af6e959dd;p=folly.git diff --git a/folly/Benchmark.h b/folly/Benchmark.h index e9547987..025c795c 100644 --- a/folly/Benchmark.h +++ b/folly/Benchmark.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Facebook, Inc. + * Copyright 2012-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,16 +21,16 @@ #include #include #include -#include #include -#include -#include +#include #include -#include #include #include +#include +#include + DECLARE_bool(benchmark); namespace folly { @@ -53,7 +53,21 @@ inline bool runBenchmarksOnFlag() { namespace detail { -typedef std::pair TimeIterPair; +using TimeIterPair = + std::pair; +using BenchmarkFun = std::function; + +struct BenchmarkRegistration { + std::string file; + std::string name; + BenchmarkFun func; +}; + +struct BenchmarkResult { + std::string file; + std::string name; + double timeInNs; +}; /** * Adds a benchmark wrapped in a std::function. Only used @@ -63,85 +77,51 @@ void addBenchmarkImpl(const char* file, const char* name, std::function); -/** - * Takes the difference between two timespec values. end is assumed to - * occur after start. - */ -inline uint64_t timespecDiff(timespec end, timespec start) { - if (end.tv_sec == start.tv_sec) { - assert(end.tv_nsec >= start.tv_nsec); - return uint64_t(end.tv_nsec - start.tv_nsec); - } - assert(end.tv_sec > start.tv_sec); - auto diff = uint64_t(end.tv_sec - start.tv_sec); - assert(diff < std::numeric_limits::max() / 1000000000ULL); - return diff * 1000000000ULL + end.tv_nsec - start.tv_nsec; -} - -/** - * Takes the difference between two sets of timespec values. The first - * two come from a high-resolution clock whereas the other two come - * from a low-resolution clock. The crux of the matter is that - * high-res values may be bogus as documented in - * http://linux.die.net/man/3/clock_gettime. The trouble is when the - * running process migrates from one CPU to another, which is more - * likely for long-running processes. Therefore we watch for high - * differences between the two timings. - * - * This function is subject to further improvements. - */ -inline uint64_t timespecDiff(timespec end, timespec start, - timespec endCoarse, timespec startCoarse) { - auto fine = timespecDiff(end, start); - auto coarse = timespecDiff(endCoarse, startCoarse); - if (coarse - fine >= 1000000) { - // The fine time is in all likelihood bogus - return coarse; - } - return fine; -} - } // namespace detail /** * Supporting type for BENCHMARK_SUSPEND defined below. */ struct BenchmarkSuspender { + using Clock = std::chrono::high_resolution_clock; + using TimePoint = Clock::time_point; + using Duration = Clock::duration; + BenchmarkSuspender() { - CHECK_EQ(0, clock_gettime(CLOCK_REALTIME, &start)); + start = Clock::now(); } BenchmarkSuspender(const BenchmarkSuspender &) = delete; BenchmarkSuspender(BenchmarkSuspender && rhs) noexcept { start = rhs.start; - rhs.start = {0, 0}; + rhs.start = {}; } BenchmarkSuspender& operator=(const BenchmarkSuspender &) = delete; BenchmarkSuspender& operator=(BenchmarkSuspender && rhs) { - if (start.tv_nsec > 0 || start.tv_sec > 0) { + if (start != TimePoint{}) { tally(); } start = rhs.start; - rhs.start = {0, 0}; + rhs.start = {}; return *this; } ~BenchmarkSuspender() { - if (start.tv_nsec > 0 || start.tv_sec > 0) { + if (start != TimePoint{}) { tally(); } } void dismiss() { - assert(start.tv_nsec > 0 || start.tv_sec > 0); + assert(start != TimePoint{}); tally(); - start = {0, 0}; + start = {}; } void rehire() { - assert(start.tv_nsec == 0 || start.tv_sec == 0); - CHECK_EQ(0, clock_gettime(CLOCK_REALTIME, &start)); + assert(start == TimePoint{}); + start = Clock::now(); } template @@ -160,20 +140,18 @@ struct BenchmarkSuspender { } /** - * Accumulates nanoseconds spent outside benchmark. + * Accumulates time spent outside benchmark. */ - typedef uint64_t NanosecondsSpent; - static NanosecondsSpent nsSpent; + static Duration timeSpent; -private: + private: void tally() { - timespec end; - CHECK_EQ(0, clock_gettime(CLOCK_REALTIME, &end)); - nsSpent += detail::timespecDiff(end, start); + auto end = Clock::now(); + timeSpent += end - start; start = end; } - timespec start; + TimePoint start; }; /** @@ -190,22 +168,17 @@ typename std::enable_if< >::type addBenchmark(const char* file, const char* name, Lambda&& lambda) { auto execute = [=](unsigned int times) { - BenchmarkSuspender::nsSpent = 0; - timespec start, end; + BenchmarkSuspender::timeSpent = {}; unsigned int niter; // CORE MEASUREMENT STARTS - auto const r1 = clock_gettime(CLOCK_REALTIME, &start); + auto start = std::chrono::high_resolution_clock::now(); niter = lambda(times); - auto const r2 = clock_gettime(CLOCK_REALTIME, &end); + auto end = std::chrono::high_resolution_clock::now(); // CORE MEASUREMENT ENDS - CHECK_EQ(0, r1); - CHECK_EQ(0, r2); - return detail::TimeIterPair( - detail::timespecDiff(end, start) - BenchmarkSuspender::nsSpent, - niter); + (end - start) - BenchmarkSuspender::timeSpent, niter); }; detail::addBenchmarkImpl(file, name, @@ -277,7 +250,7 @@ struct DoNotOptimizeAwayNeedsIndirect { constexpr static bool value = !folly::IsTriviallyCopyable::value || sizeof(Decayed) > sizeof(long) || std::is_pointer::value; }; -} // detail namespace +} // namespace detail template auto doNotOptimizeAway(const T& datum) -> typename std::enable_if< @@ -320,6 +293,20 @@ auto makeUnpredictable(T& datum) -> typename std::enable_if< #endif +struct dynamic; + +void benchmarkResultsToDynamic( + const std::vector& data, + dynamic&); + +void benchmarkResultsFromDynamic( + const dynamic&, + std::vector&); + +void printResultComparison( + const std::vector& base, + const std::vector& test); + } // namespace folly /**