| /* | |
| * Copyright (C) 2009 Google Inc. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package tutorial; | |
| import com.google.caliper.BeforeExperiment; | |
| import com.google.caliper.Benchmark; | |
| import com.google.caliper.Param; | |
| /** | |
| * Caliper tutorial. To run the example benchmarks in this file: | |
| * {@code CLASSPATH=... [caliper_home]/caliper tutorial.Tutorial.Benchmark1} | |
| */ | |
| public class Tutorial { | |
| /* | |
| * We begin the Caliper tutorial with the simplest benchmark you can write. | |
| * We'd like to know how efficient the method System.nanoTime() is. | |
| * | |
| * Notice: | |
| * | |
| * - We write a class that extends com.google.caliper.Benchmark. | |
| * - It contains a public instance method whose name begins with 'time' and | |
| * which accepts a single 'int reps' parameter. | |
| * - The body of the method simply executes the code we wish to measure, | |
| * 'reps' times. | |
| * | |
| * Example run: | |
| * | |
| * $ CLASSPATH=build/classes/test caliper tutorial.Tutorial.Benchmark1 | |
| * [real-time results appear on this line] | |
| * | |
| * Summary report for tutorial.Tutorial$Benchmark1: | |
| * | |
| * Benchmark ns | |
| * --------- --- | |
| * NanoTime 233 | |
| */ | |
| public static class Benchmark1 { | |
| @Benchmark void timeNanoTime(int reps) { | |
| for (int i = 0; i < reps; i++) { | |
| System.nanoTime(); | |
| } | |
| } | |
| } | |
| /* | |
| * Now let's compare two things: nanoTime() versus currentTimeMillis(). | |
| * Notice: | |
| * | |
| * - We simply add another method, following the same rules as the first. | |
| * | |
| * Example run output: | |
| * | |
| * Benchmark ns | |
| * ----------------- --- | |
| * NanoTime 248 | |
| * CurrentTimeMillis 118 | |
| */ | |
| public static class Benchmark2 { | |
| @Benchmark void timeNanoTime(int reps) { | |
| for (int i = 0; i < reps; i++) { | |
| System.nanoTime(); | |
| } | |
| } | |
| @Benchmark void timeCurrentTimeMillis(int reps) { | |
| for (int i = 0; i < reps; i++) { | |
| System.currentTimeMillis(); | |
| } | |
| } | |
| } | |
| /* | |
| * Let's try iterating over a large array. This seems simple enough, but | |
| * there is a problem! | |
| */ | |
| public static class Benchmark3 { | |
| private final int[] array = new int[1000000]; | |
| @SuppressWarnings("UnusedDeclaration") // IDEA tries to warn us! | |
| @Benchmark void timeArrayIteration_BAD(int reps) { | |
| for (int i = 0; i < reps; i++) { | |
| for (int ignoreMe : array) {} | |
| } | |
| } | |
| } | |
| /* | |
| * Caliper reported that the benchmark above ran in 4 nanoseconds. | |
| * | |
| * Wait, what? | |
| * | |
| * How can it possibly iterate over a million zeroes in 4 ns!? | |
| * | |
| * It is very important to sanity-check benchmark results with common sense! | |
| * In this case, we're indeed getting a bogus result. The problem is that the | |
| * Java Virtual Machine is too smart: it detected the fact that the loop was | |
| * producing no actual result, so it simply compiled it right out. The method | |
| * never looped at all. To fix this, we need to use a dummy result value. | |
| * | |
| * Notice: | |
| * | |
| * - We simply change the 'time' method from 'void' to any return type we | |
| * wish. Then we return a value that can't be known without actually | |
| * performing the work, and thus we defeat the runtime optimizations. | |
| * - We're no longer timing *just* the code we want to be testing - our | |
| * result will now be inflated by the (small) cost of addition. This is an | |
| * unfortunate fact of life with microbenchmarking. In fact, we were | |
| * already inflated by the cost of an int comparison, "i < reps" as it was. | |
| * | |
| * With this change, Caliper should report a much more realistic value, more | |
| * on the order of an entire millisecond. | |
| */ | |
| public static class Benchmark4 { | |
| private final int[] array = new int[1000000]; | |
| @Benchmark int timeArrayIteration_fixed(int reps) { | |
| int dummy = 0; | |
| for (int i = 0; i < reps; i++) { | |
| for (int doNotIgnoreMe : array) { | |
| dummy += doNotIgnoreMe; | |
| } | |
| } | |
| return dummy; // framework ignores this, but it has served its purpose! | |
| } | |
| } | |
| /* | |
| * Now we'd like to know how various other *sizes* of arrays perform. We | |
| * don't want to have to cut and paste the whole benchmark just to provide a | |
| * different size. What we need is a parameter! | |
| * | |
| * When you run this benchmark the same way you ran the previous ones, you'll | |
| * now get an error: "No values provided for benchmark parameter 'size'". | |
| * You can provide the value requested at the command line like this: | |
| * | |
| * [caliper_home]/caliper tutorial.Tutorial.Benchmark5 -Dsize=100} | |
| * | |
| * You'll see output like this: | |
| * | |
| * Benchmark size ns | |
| * -------------- ---- --- | |
| * ArrayIteration 100 51 | |
| * | |
| * Now that we've parameterized our benchmark, things are starting to get fun. | |
| * Try passing '-Dsize=10,100,1000' and see what happens! | |
| * | |
| * Benchmark size ns | |
| * -------------- ---- ----------------------------------- | |
| * ArrayIteration 10 7 | | |
| * ArrayIteration 100 49 |||| | |
| * ArrayIteration 1000 477 |||||||||||||||||||||||||||||| | |
| * | |
| */ | |
| public static class Benchmark5 { | |
| @Param int size; // set automatically by framework | |
| private int[] array; // set by us, in setUp() | |
| @BeforeExperiment void setUp() { | |
| // @Param values are guaranteed to have been injected by now | |
| array = new int[size]; | |
| } | |
| @Benchmark int timeArrayIteration(int reps) { | |
| int dummy = 0; | |
| for (int i = 0; i < reps; i++) { | |
| for (int doNotIgnoreMe : array) { | |
| dummy += doNotIgnoreMe; | |
| } | |
| } | |
| return dummy; | |
| } | |
| } | |
| } |