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