// Copyright 2009 The RE2 Authors. All Rights Reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include #include #include #include #include #include "util/benchmark.h" #include "util/flags.h" #include "re2/re2.h" #ifdef _WIN32 #define snprintf _snprintf #endif using ::testing::Benchmark; static Benchmark* benchmarks[10000]; static int nbenchmarks; void Benchmark::Register() { lo_ = std::max(1, lo_); hi_ = std::max(lo_, hi_); benchmarks[nbenchmarks++] = this; } static int64_t nsec() { return std::chrono::duration_cast( std::chrono::steady_clock::now().time_since_epoch()) .count(); } static int64_t t0; static int64_t ns; static int64_t bytes; static int64_t items; void StartBenchmarkTiming() { if (t0 == 0) { t0 = nsec(); } } void StopBenchmarkTiming() { if (t0 != 0) { ns += nsec() - t0; t0 = 0; } } void SetBenchmarkBytesProcessed(int64_t b) { bytes = b; } void SetBenchmarkItemsProcessed(int64_t i) { items = i; } static void RunFunc(Benchmark* b, int iters, int arg) { t0 = nsec(); ns = 0; bytes = 0; items = 0; b->func()(iters, arg); StopBenchmarkTiming(); } static int round(int n) { int base = 1; while (base * 10 < n) base *= 10; if (n < 2 * base) return 2 * base; if (n < 5 * base) return 5 * base; return 10 * base; } static void RunBench(Benchmark* b, int arg) { int iters, last; // Run once just in case it's expensive. iters = 1; RunFunc(b, iters, arg); while (ns < (int)1e9 && iters < (int)1e9) { last = iters; if (ns / iters == 0) { iters = (int)1e9; } else { iters = (int)1e9 / static_cast(ns / iters); } iters = std::max(last + 1, std::min(iters + iters / 2, 100 * last)); iters = round(iters); RunFunc(b, iters, arg); } char mb[100]; char suf[100]; mb[0] = '\0'; suf[0] = '\0'; if (ns > 0 && bytes > 0) snprintf(mb, sizeof mb, "\t%7.2f MB/s", ((double)bytes / 1e6) / ((double)ns / 1e9)); if (b->has_arg()) { if (arg >= (1 << 20)) { snprintf(suf, sizeof suf, "/%dM", arg / (1 << 20)); } else if (arg >= (1 << 10)) { snprintf(suf, sizeof suf, "/%dK", arg / (1 << 10)); } else { snprintf(suf, sizeof suf, "/%d", arg); } } printf("%s%s\t%8d\t%10lld ns/op%s\n", b->name(), suf, iters, (long long)ns / iters, mb); fflush(stdout); } static bool WantBench(const char* name, int argc, const char** argv) { if (argc == 1) return true; for (int i = 1; i < argc; i++) { if (RE2::PartialMatch(name, argv[i])) return true; } return false; } int main(int argc, const char** argv) { for (int i = 0; i < nbenchmarks; i++) { Benchmark* b = benchmarks[i]; if (!WantBench(b->name(), argc, argv)) continue; for (int arg = b->lo(); arg <= b->hi(); arg <<= 1) RunBench(b, arg); } }