JMH使用java17,无死码消除
JMH using java 17, no dead code elimination
我 运行 样本 JHM 基准,它假设显示死代码消除。为简洁起见,代码从 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); }
}
运行 使用 JDK 1.8.0_211,Java HotSpot(TM) 64 位服务器 VM,25.211-b12 产生以下结果:
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
但使用 java JDK 17.0.2, Java HotSpot(TM) 64-Bit Server VM, 17.0.2+8-LTS-86 结果没有符号死代码消除:
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
为什么 measureIncorrect()
方法没有使用 java 17 优化?
这些示例取决于 JDK 内部结构。
看起来自从 JDK 9 和 JDK-8152907 以来,Math.log
不再内化为 C2 中间表示。相反,直接调用快速 LIBM-backed 存根。对于实际使用结果的代码,这通常更快。请注意 measureCorrect
在 JDK 17 输出中如何更快。
但对于 JMH 示例,它限制了围绕 Math.log
的编译器优化,死代码/折叠示例无法正常工作。修复它以制作不依赖 JDK 内部结构且没有充分理由的样本,而是使用自定义的书面有效负载。
这是在 JMH 中完成的:
我 运行 样本 JHM 基准,它假设显示死代码消除。为简洁起见,代码从 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); }
}
运行 使用 JDK 1.8.0_211,Java HotSpot(TM) 64 位服务器 VM,25.211-b12 产生以下结果:
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
但使用 java JDK 17.0.2, Java HotSpot(TM) 64-Bit Server VM, 17.0.2+8-LTS-86 结果没有符号死代码消除:
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
为什么 measureIncorrect()
方法没有使用 java 17 优化?
这些示例取决于 JDK 内部结构。
看起来自从 JDK 9 和 JDK-8152907 以来,Math.log
不再内化为 C2 中间表示。相反,直接调用快速 LIBM-backed 存根。对于实际使用结果的代码,这通常更快。请注意 measureCorrect
在 JDK 17 输出中如何更快。
但对于 JMH 示例,它限制了围绕 Math.log
的编译器优化,死代码/折叠示例无法正常工作。修复它以制作不依赖 JDK 内部结构且没有充分理由的样本,而是使用自定义的书面有效负载。
这是在 JMH 中完成的: