下面的benchmark中有许多Dead-Code Elimination, 编译器能够发现那些冗余计算并且消除他们. 但是如果被消除的部分是我们的基准测试部分, 则会引发问题.幸运的的是, JMH提供了一些基础服务来解决这些问题:带有返回结果的基准测试会强制JMH不进行Dead-Code Elimination
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public class JMHSample_08_DeadCode { private double x = Math.PI; @Benchmark public void baseline () { } @Benchmark public void measureWrong () { Math.log(x); } @Benchmark public double measureRight () { return Math.log(x); } public static void main (String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(JMHSample_08_DeadCode.class.getSimpleName()) .warmupIterations(5 ) .measurementIterations(5 ) .forks(1 ) .build(); new Runner(opt).run(); } }
运行结果为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # Warmup: 5 iterations, 1 s each # Measurement: 5 iterations, 1 s each # Timeout: 10 min per iteration # Threads: 1 thread, will synchronize iterations # Benchmark mode: Average time, time/op # Benchmark: JMH.JMHSample_08_DeadCode.measureWrong # Run progress: 66.67 % complete, ETA 00 :00 :10 # Fork: 1 of 1 # Warmup Iteration 1 : 0.281 ns/op # Warmup Iteration 2 : 0.281 ns/op # Warmup Iteration 3 : 0.278 ns/op # Warmup Iteration 4 : 0.280 ns/op # Warmup Iteration 5 : 0.278 ns/op Iteration 1 : 0.278 ns/op Iteration 2 : 0.278 ns/op Iteration 3 : 0.278 ns/op Iteration 4 : 0.277 ns/op Iteration 5 : 0.278 ns/op Result "measureWrong" : 0.278 ±(99.9 %) 0.002 ns/op [Average] (min, avg, max) = (0.277 , 0.278 , 0.278 ), stdev = 0.001 CI (99.9 %): [0.276 , 0.280 ] (assumes normal distribution) # Run complete. Total time: 00 :00 :31 Benchmark Mode Cnt Score Error Units JMH.JMHSample_08_DeadCode.baseline avgt 5 0.279 ± 0.004 ns/op JMH.JMHSample_08_DeadCode.measureRight avgt 5 21.067 ± 0.288 ns/op JMH.JMHSample_08_DeadCode.measureWrong avgt 5 0.278 ± 0.002 ns/op
我们可以看到baseline和measureWrong的测试结果是相近的