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 "util/util.h"
6 #include "util/flags.h"
7 #include "util/benchmark.h"
8 #include "re2/re2.h"
9 
10 DEFINE_string(test_tmpdir, "/var/tmp", "temp directory");
11 
12 using testing::Benchmark;
13 using namespace re2;
14 
15 static Benchmark* benchmarks[10000];
16 static int nbenchmarks;
17 
Register()18 void Benchmark::Register() {
19 	benchmarks[nbenchmarks] = this;
20 	if(lo < 1)
21 		lo = 1;
22 	if(hi < lo)
23 		hi = lo;
24 	nbenchmarks++;
25 }
26 
nsec()27 static int64 nsec() {
28 	struct timeval tv;
29 	if(gettimeofday(&tv, 0) < 0)
30 		return -1;
31 	return (int64)tv.tv_sec*1000*1000*1000 + tv.tv_usec*1000;
32 }
33 
34 static int64 bytes;
35 static int64 ns;
36 static int64 t0;
37 static int64 items;
38 
SetBenchmarkBytesProcessed(long long x)39 void SetBenchmarkBytesProcessed(long long x) {
40 	bytes = x;
41 }
42 
StopBenchmarkTiming()43 void StopBenchmarkTiming() {
44 	if(t0 != 0)
45 		ns += nsec() - t0;
46 	t0 = 0;
47 }
48 
StartBenchmarkTiming()49 void StartBenchmarkTiming() {
50 	if(t0 == 0)
51 		t0 = nsec();
52 }
53 
SetBenchmarkItemsProcessed(int n)54 void SetBenchmarkItemsProcessed(int n) {
55 	items = n;
56 }
57 
BenchmarkMemoryUsage()58 void BenchmarkMemoryUsage() {
59 	// TODO(rsc): Implement.
60 }
61 
NumCPUs()62 int NumCPUs() {
63 	return 1;
64 }
65 
runN(Benchmark * b,int n,int siz)66 static void runN(Benchmark *b, int n, int siz) {
67 	bytes = 0;
68 	items = 0;
69 	ns = 0;
70 	t0 = nsec();
71 	if(b->fn)
72 		b->fn(n);
73 	else if(b->fnr)
74 		b->fnr(n, siz);
75 	else {
76 		fprintf(stderr, "%s: missing function\n", b->name);
77 		exit(2);
78 	}
79 	if(t0 != 0)
80 		ns += nsec() - t0;
81 }
82 
round(int n)83 static int round(int n) {
84 	int base = 1;
85 
86 	while(base*10 < n)
87 		base *= 10;
88 	if(n < 2*base)
89 		return 2*base;
90 	if(n < 5*base)
91 		return 5*base;
92 	return 10*base;
93 }
94 
RunBench(Benchmark * b,int nthread,int siz)95 void RunBench(Benchmark* b, int nthread, int siz) {
96 	int n, last;
97 
98 	// TODO(rsc): Threaded benchmarks.
99 	if(nthread != 1)
100 		return;
101 
102 	// run once in case it's expensive
103 	n = 1;
104 	runN(b, n, siz);
105 	while(ns < (int)1e9 && n < (int)1e9) {
106 		last = n;
107 		if(ns/n == 0)
108 			n = 1e9;
109 		else
110 			n = 1e9 / (ns/n);
111 
112 		n = max(last+1, min(n+n/2, 100*last));
113 		n = round(n);
114 		runN(b, n, siz);
115 	}
116 
117 	char mb[100];
118 	char suf[100];
119 	mb[0] = '\0';
120 	suf[0] = '\0';
121 	if(ns > 0 && bytes > 0)
122 		snprintf(mb, sizeof mb, "\t%7.2f MB/s", ((double)bytes/1e6)/((double)ns/1e9));
123 	if(b->fnr || b->lo != b->hi) {
124 		if(siz >= (1<<20))
125 			snprintf(suf, sizeof suf, "/%dM", siz/(1<<20));
126 		else if(siz >= (1<<10))
127 			snprintf(suf, sizeof suf, "/%dK", siz/(1<<10));
128 		else
129 			snprintf(suf, sizeof suf, "/%d", siz);
130 	}
131 	printf("%s%s\t%8lld\t%10lld ns/op%s\n", b->name, suf, (long long)n, (long long)ns/n, mb);
132 	fflush(stdout);
133 }
134 
match(const char * name,int argc,const char ** argv)135 static int match(const char* name, int argc, const char** argv) {
136 	if(argc == 1)
137 		return 1;
138 	for(int i = 1; i < argc; i++)
139 		if(RE2::PartialMatch(name, argv[i]))
140 			return 1;
141 	return 0;
142 }
143 
main(int argc,const char ** argv)144 int main(int argc, const char** argv) {
145 	for(int i = 0; i < nbenchmarks; i++) {
146 		Benchmark* b = benchmarks[i];
147 		if(match(b->name, argc, argv))
148 			for(int j = b->threadlo; j <= b->threadhi; j++)
149 				for(int k = max(b->lo, 1); k <= max(b->hi, 1); k<<=1)
150 					RunBench(b, j, k);
151 	}
152 }
153 
154