• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2009 The RE2 Authors.  All Rights Reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <algorithm>
9 #include <chrono>
10 
11 #include "util/benchmark.h"
12 #include "util/flags.h"
13 #include "re2/re2.h"
14 
15 #ifdef _WIN32
16 #define snprintf _snprintf
17 #endif
18 
19 using ::testing::Benchmark;
20 
21 static Benchmark* benchmarks[10000];
22 static int nbenchmarks;
23 
Register()24 void Benchmark::Register() {
25   lo_ = std::max(1, lo_);
26   hi_ = std::max(lo_, hi_);
27   benchmarks[nbenchmarks++] = this;
28 }
29 
nsec()30 static int64_t nsec() {
31   return std::chrono::duration_cast<std::chrono::nanoseconds>(
32              std::chrono::steady_clock::now().time_since_epoch())
33       .count();
34 }
35 
36 static int64_t t0;
37 static int64_t ns;
38 static int64_t bytes;
39 static int64_t items;
40 
StartBenchmarkTiming()41 void StartBenchmarkTiming() {
42   if (t0 == 0) {
43     t0 = nsec();
44   }
45 }
46 
StopBenchmarkTiming()47 void StopBenchmarkTiming() {
48   if (t0 != 0) {
49     ns += nsec() - t0;
50     t0 = 0;
51   }
52 }
53 
SetBenchmarkBytesProcessed(int64_t b)54 void SetBenchmarkBytesProcessed(int64_t b) { bytes = b; }
55 
SetBenchmarkItemsProcessed(int64_t i)56 void SetBenchmarkItemsProcessed(int64_t i) { items = i; }
57 
RunFunc(Benchmark * b,int iters,int arg)58 static void RunFunc(Benchmark* b, int iters, int arg) {
59   t0 = nsec();
60   ns = 0;
61   bytes = 0;
62   items = 0;
63   b->func()(iters, arg);
64   StopBenchmarkTiming();
65 }
66 
round(int n)67 static int round(int n) {
68   int base = 1;
69   while (base * 10 < n) base *= 10;
70   if (n < 2 * base) return 2 * base;
71   if (n < 5 * base) return 5 * base;
72   return 10 * base;
73 }
74 
RunBench(Benchmark * b,int arg)75 static void RunBench(Benchmark* b, int arg) {
76   int iters, last;
77 
78   // Run once just in case it's expensive.
79   iters = 1;
80   RunFunc(b, iters, arg);
81   while (ns < (int)1e9 && iters < (int)1e9) {
82     last = iters;
83     if (ns / iters == 0) {
84       iters = (int)1e9;
85     } else {
86       iters = (int)1e9 / static_cast<int>(ns / iters);
87     }
88     iters = std::max(last + 1, std::min(iters + iters / 2, 100 * last));
89     iters = round(iters);
90     RunFunc(b, iters, arg);
91   }
92 
93   char mb[100];
94   char suf[100];
95   mb[0] = '\0';
96   suf[0] = '\0';
97   if (ns > 0 && bytes > 0)
98     snprintf(mb, sizeof mb, "\t%7.2f MB/s",
99              ((double)bytes / 1e6) / ((double)ns / 1e9));
100   if (b->has_arg()) {
101     if (arg >= (1 << 20)) {
102       snprintf(suf, sizeof suf, "/%dM", arg / (1 << 20));
103     } else if (arg >= (1 << 10)) {
104       snprintf(suf, sizeof suf, "/%dK", arg / (1 << 10));
105     } else {
106       snprintf(suf, sizeof suf, "/%d", arg);
107     }
108   }
109   printf("%s%s\t%8d\t%10lld ns/op%s\n", b->name(), suf, iters,
110          (long long)ns / iters, mb);
111   fflush(stdout);
112 }
113 
WantBench(const char * name,int argc,const char ** argv)114 static bool WantBench(const char* name, int argc, const char** argv) {
115   if (argc == 1) return true;
116   for (int i = 1; i < argc; i++) {
117     if (RE2::PartialMatch(name, argv[i]))
118       return true;
119   }
120   return false;
121 }
122 
main(int argc,const char ** argv)123 int main(int argc, const char** argv) {
124   for (int i = 0; i < nbenchmarks; i++) {
125     Benchmark* b = benchmarks[i];
126     if (!WantBench(b->name(), argc, argv))
127       continue;
128     for (int arg = b->lo(); arg <= b->hi(); arg <<= 1)
129       RunBench(b, arg);
130   }
131 }
132