Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2009 The Go 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 package testing | |
6 | |
7 import ( | |
8 "flag"; | |
9 "fmt"; | |
10 "math"; | |
11 "os"; | |
12 "time"; | |
13 ) | |
14 | |
15 var matchBenchmarks = flag.String("benchmarks", "", "regular expression to selec t benchmarks to run") | |
16 | |
17 // An internal type but exported because it is cross-package; part of the implem entation | |
18 // of gotest. | |
19 type Benchmark struct { | |
20 Name string; | |
21 F func(b *B); | |
22 } | |
23 | |
24 // B is a type passed to Benchmark functions to manage benchmark | |
25 // timing and to specify the number of iterations to run. | |
26 type B struct { | |
27 N int; | |
28 benchmark Benchmark; | |
29 ns int64; | |
30 start int64; | |
31 } | |
32 | |
33 // StartTimer starts timing a test. This function is called automatically | |
34 // before a benchmark starts, but it can also used to resume timing after | |
35 // a call to StopTimer. | |
36 func (b *B) StartTimer() { b.start = time.Nanoseconds() } | |
37 | |
38 // StopTimer stops timing a test. This can be used to pause the timer | |
39 // while performing complex initialization that you don't | |
40 // want to measure. | |
41 func (b *B) StopTimer() { | |
42 if b.start > 0 { | |
43 b.ns += time.Nanoseconds() - b.start | |
44 } | |
45 b.start = 0; | |
46 } | |
47 | |
48 // ResetTimer stops the timer and sets the elapsed benchmark time to zero. | |
49 func (b *B) ResetTimer() { | |
50 b.start = 0; | |
51 b.ns = 0; | |
52 } | |
53 | |
54 func (b *B) nsPerOp() int64 { | |
55 if b.N <= 0 { | |
56 return 0 | |
57 } | |
58 return b.ns / int64(b.N); | |
59 } | |
60 | |
61 // runN runs a single benchmark for the specified number of iterations (n). | |
rsc
2009/11/18 07:16:49
can drop (n)
trevor.strohman
2009/11/18 16:54:51
Done.
| |
62 func (b *B) runN(n int) { | |
63 b.N = n; | |
64 b.ResetTimer(); | |
65 b.StartTimer(); | |
66 b.benchmark.F(b); | |
67 b.StopTimer(); | |
68 } | |
69 | |
70 func min(x, y int) int { | |
71 if x > y { | |
72 return y | |
73 } | |
74 return x; | |
75 } | |
76 | |
77 // roundDown10 rounds a number down to the nearest power of 10. | |
78 func roundDown10(n int) int { return int(math.Pow10(int(math.Log10(float64(n ))))) } | |
79 | |
80 // roundUp rounds x up to a number of the form [1eX, 2eX, 5eX]. | |
81 func roundUp(n int) int { | |
82 base := roundDown10(n); | |
83 if n < (2 * base) { | |
84 return 2 * base | |
85 } | |
86 if n < (5 * base) { | |
87 return 5 * base | |
88 } | |
89 return 10 * base; | |
90 } | |
91 | |
92 // run times the benchmark function. It gradually increases the number | |
93 // of benchmark iterations until the benchmark runs for a second in order | |
94 // to get a reasonable measurement. It prints timing information in this form | |
95 // testing.BenchmarkHello 100000 19 ns/op | |
96 func (b *B) run() { | |
97 // Run the benchmark for a single iteration in case it's expensive. | |
98 n := 1; | |
99 b.runN(n); | |
100 // Run the benchmark for at least a second. | |
101 for b.ns < 1e9 && n < 1e9 { | |
102 last := n; | |
103 // Predict iterations/sec. | |
104 if b.nsPerOp() == 0 { | |
105 n = 1e9 | |
106 } else { | |
107 n = 1e9 / int(b.nsPerOp()) | |
108 } | |
109 // Run more iterations than we think we'll need for a second (1. 5x). | |
110 // Don't grow too fast in case we had timing errors previously. | |
111 n = min(int(1.5*float(n)), 100*last); | |
112 // Round up to something easy to read. | |
113 n = roundUp(n); | |
114 b.runN(n); | |
115 } | |
116 fmt.Printf("%s\t%d\t%10d ns/op\n", b.benchmark.Name, b.N, b.nsPerOp()); | |
117 } | |
118 | |
119 // An internal function but exported because it is cross-package; part of the im plementation | |
120 // of gotest. | |
121 func RunBenchmarks(benchmarks []Benchmark) { | |
122 // If no flag was specified, don't run benchmarks. | |
123 if len(*matchBenchmarks) == 0 { | |
124 return | |
125 } | |
126 re, err := CompileRegexp(*matchBenchmarks); | |
127 if err != "" { | |
128 println("invalid regexp for -benchmarks:", err); | |
129 os.Exit(1); | |
130 } | |
131 for _, Benchmark := range benchmarks { | |
132 if !re.MatchString(Benchmark.Name) { | |
133 continue | |
134 } | |
135 b := &B{benchmark: Benchmark}; | |
136 b.run(); | |
137 } | |
138 } | |
OLD | NEW |