Search code examples
javajmh

JMH using java 17, no dead code elimination


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?


Solution

  • 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: