Reputation: 924
I run sample JHM benchmark which suppose to show dead code elimination. Code is rewritten for conciseness from jhm github sample.
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(1)
public class Sample08DeadCode {
private double x = Math.PI;
@Benchmark
public void benchmark() {}
@Benchmark
public void measureIncorrect() { Math.log(x); }
@Benchmark
public double measureCorrect() { return Math.log(x); }
}
Run using JDK 1.8.0_211, Java HotSpot(TM) 64-Bit Server VM, 25.211-b12 produces following results:
Benchmark Mode Cnt Score Error Units
Sample08DeadCode.benchmark avgt 5 0,229 ± 0,018 ns/op
Sample08DeadCode.measureCorrect avgt 5 12,013 ± 0,047 ns/op
Sample08DeadCode.measureIncorrect avgt 5 0,228 ± 0,016 ns/op
but using java JDK 17.0.2, Java HotSpot(TM) 64-Bit Server VM, 17.0.2+8-LTS-86 the results have no sign of dead code elimination:
Benchmark Mode Cnt Score Error Units
Sample08DeadCode.benchmark avgt 5 0,341 ± 0,004 ns/op
Sample08DeadCode.measureCorrect avgt 5 6,244 ± 0,072 ns/op
Sample08DeadCode.measureIncorrect avgt 5 6,263 ± 0,094 ns/op
Why does the measureIncorrect()
method is not optimized using java 17?
Upvotes: 9
Views: 712
Reputation: 18857
Those samples depend on JDK internals.
Looks like since JDK 9 and JDK-8152907, Math.log
is no longer intrinsified into C2 intermediate representation. Instead, a direct call to a quick LIBM-backed stub is made. This is usually faster for the code that actually uses the result. Notice how measureCorrect
is faster in JDK 17 output in your case.
But for JMH samples, it limits the the compiler optimizations around the Math.log
, and dead code / folding samples do not work properly. The fix it to make samples that do not rely on JDK internals without a good reason, and instead use a custom written payload.
This is being done in JMH here:
Upvotes: 11