blob: 06e6e56f63eb64d524aaff328799b7b4c2730726 [file] [log] [blame]
Jesse Wilsonf062bf42010-01-13 17:12:18 -08001/*
2 * Copyright (C) 2009 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package tutorial;
18
19import com.google.caliper.Param;
20import com.google.caliper.SimpleBenchmark;
21
22/**
23 * Caliper tutorial. To run the example benchmarks in this file:
24 * {@code CLASSPATH=... [caliper_home]/caliper tutorial.Tutorial.Benchmark1}
25 *
26 * @author Kevin Bourrillion
27 */
28public class Tutorial {
29
30 /*
31 * We begin the Caliper tutorial with the simplest benchmark you can write.
32 * We'd like to know how efficient the method System.nanoTime() is.
33 *
34 * Notice:
35 *
36 * - We write a class that extends com.google.caliper.SimpleBenchmark.
37 * - It contains a public instance method whose name begins with 'time' and
38 * and which accepts a single 'int reps' parameter.
39 * - The body of the method simply executes the code we wish to measure,
40 * 'reps' times.
41 *
42 * Example run:
43 *
44 * $ CLASSPATH=build/classes/test caliper tutorial.Tutorial.Benchmark1
45 * [real-time results appear on this line]
46 *
47 * Summary report for tutorial.Tutorial$Benchmark1:
48 *
49 * Benchmark ns
50 * --------- ---
51 * NanoTime 233
52 */
53 public static class Benchmark1 extends SimpleBenchmark {
54 public void timeNanoTime(int reps) {
55 for (int i = 0; i < reps; i++) {
56 System.nanoTime();
57 }
58 }
59 }
60
61 /*
62 * Now let's compare two things: nanoTime() versus currentTimeMillis().
63 * Notice:
64 *
65 * - We simply add another method, following the same rules as the first.
66 *
67 * Example run output:
68 *
69 * Benchmark ns
70 * ----------------- ---
71 * NanoTime 248
72 * CurrentTimeMillis 118
73 */
74 public static class Benchmark2 extends SimpleBenchmark {
75 public void timeNanoTime(int reps) {
76 for (int i = 0; i < reps; i++) {
77 System.nanoTime();
78 }
79 }
80 public void timeCurrentTimeMillis(int reps) {
81 for (int i = 0; i < reps; i++) {
82 System.currentTimeMillis();
83 }
84 }
85 }
86
87 /*
88 * Let's try iterating over a large array. This seems simple enough, but
89 * there is a problem!
90 */
91 public static class Benchmark3 extends SimpleBenchmark {
92 private final int[] array = new int[1000000];
93
94 @SuppressWarnings("UnusedDeclaration") // IDEA tries to warn us!
95 public void timeArrayIteration_BAD(int reps) {
96 for (int i = 0; i < reps; i++) {
97 for (int ignoreMe : array) {}
98 }
99 }
100 }
101
102 /*
103 * Caliper reported that the benchmark above ran in 4 nanoseconds.
104 *
105 * Wait, what?
106 *
107 * How can it possibly iterate over a million zeroes in 4 ns!?
108 *
109 * It is very important to sanity-check benchmark results with common sense!
110 * In this case, we're indeed getting a bogus result. The problem is that the
111 * Java Virtual Machine is too smart: it detected the fact that the loop was
112 * producing no actual result, so it simply compiled it right out. The method
113 * never looped at all. To fix this, we need to use a dummy result value.
114 *
115 * Notice:
116 *
117 * - We simply change the 'time' method from 'void' to any return type we
118 * wish. Then we return a value that can't be known without actually
119 * performing the work, and thus we defeat the runtime optimizations.
120 * - We're no longer timing *just* the code we want to be testing - our
121 * result will now be inflated by the (small) cost of addition. This is an
122 * unfortunate fact of life with microbenchmarking. In fact, we were
123 * already inflated by the cost of an int comparison, "i < reps" as it was.
124 *
125 * With this change, Caliper should report a much more realistic value, more
126 * on the order of an entire millisecond.
127 */
128 public static class Benchmark4 extends SimpleBenchmark {
129 private final int[] array = new int[1000000];
130
131 public int timeArrayIteration_fixed(int reps) {
132 int dummy = 0;
133 for (int i = 0; i < reps; i++) {
134 for (int doNotIgnoreMe : array) {
135 dummy += doNotIgnoreMe;
136 }
137 }
138 return dummy; // framework ignores this, but it has served its purpose!
139 }
140 }
141
142 /*
143 * Now we'd like to know how various other *sizes* of arrays perform. We
144 * don't want to have to cut and paste the whole benchmark just to provide a
145 * different size. What we need is a parameter!
146 *
147 * When you run this benchmark the same way you ran the previous ones, you'll
148 * now get an error: "No values provided for benchmark parameter 'size'".
149 * You can provide the value requested at the command line like this:
150 *
151 * [caliper_home]/caliper tutorial.Tutorial.Benchmark5 -Dsize=100}
152 *
153 * You'll see output like this:
154 *
155 * Benchmark size ns
156 * -------------- ---- ---
157 * ArrayIteration 100 51
158 *
159 * Now that we've parameterized our benchmark, things are starting to get fun.
160 * Try passing '-Dsize=10,100,1000' and see what happens!
161 *
162 * Benchmark size ns
163 * -------------- ---- -----------------------------------
164 * ArrayIteration 10 7 |
165 * ArrayIteration 100 49 ||||
166 * ArrayIteration 1000 477 ||||||||||||||||||||||||||||||
167 *
168 */
169 public static class Benchmark5 extends SimpleBenchmark {
170 @Param int size; // set automatically by framework
171
172 private int[] array; // set by us, in setUp()
173
174 @Override protected void setUp() {
175 // @Param values are guaranteed to have been injected by now
176 array = new int[size];
177 }
178
179 public int timeArrayIteration(int reps) {
180 int dummy = 0;
181 for (int i = 0; i < reps; i++) {
182 for (int doNotIgnoreMe : array) {
183 dummy += doNotIgnoreMe;
184 }
185 }
186 return dummy;
187 }
188 }
189}