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