JMH - 为什么 JIT 不消除我的死代码
JMH - why JIT does not eliminate my dead-code
我写了两个基准来证明 JIT 可能是编写好的基准的问题(请跳过我在这里不使用 @State):
@Fork(value = 1)
@Warmup(iterations = 2, time = 10)
@Measurement(iterations = 3, time = 2)
@BenchmarkMode(Mode.AverageTime)
public class DeadCodeTraps {
@Benchmark
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public static void summaryStatistics_standardDeviationForFourNumbers() {
final SummaryStatistics summaryStatistics = new SummaryStatistics();
summaryStatistics.addValue(10.0);
summaryStatistics.addValue(20.0);
summaryStatistics.addValue(30.0);
summaryStatistics.addValue(40.0);
summaryStatistics.getStandardDeviation();
}
@Benchmark
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public static void summaryStatistics_standardDeviationForTenNumbers() {
final SummaryStatistics summaryStatistics = new SummaryStatistics();
summaryStatistics.addValue(10.0);
summaryStatistics.addValue(20.0);
summaryStatistics.addValue(30.0);
summaryStatistics.addValue(40.0);
summaryStatistics.addValue(50.0);
summaryStatistics.addValue(60.0);
summaryStatistics.addValue(70.0);
summaryStatistics.addValue(80.0);
summaryStatistics.addValue(90.0);
summaryStatistics.addValue(100.0);
summaryStatistics.getStandardDeviation();
}
}
我以为JIT会消除死代码,所以会同时执行两个方法。但最后,我有:
summaryStatistics_standardDeviationForFourNumbers 0.158 ± 0.046
DeadCodeTraps.summaryStatistics_standardDeviationForTenNumbers 0.359 ± 0.294
为什么JIT不优化呢? summaryStatistics.getStandardDeviation();
的结果不会在方法之外的任何地方使用,也不会由它返回。
(我正在使用 OpenJDK build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4)
如果您谈论的是 Apache Commons Math SummaryStatistics
class,那么它是一个巨大的 class。它的构造肯定不会被内联。要了解原因,运行 和 -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -XX:-BackgroundCompilation
死代码消除发生在内联之后。
未使用的对象将反向传播,但非内联构造函数将打破链条,因为 JIT 优化器无法再确保没有副作用。
也就是说,你希望淘汰的代码太大了
我写了两个基准来证明 JIT 可能是编写好的基准的问题(请跳过我在这里不使用 @State):
@Fork(value = 1)
@Warmup(iterations = 2, time = 10)
@Measurement(iterations = 3, time = 2)
@BenchmarkMode(Mode.AverageTime)
public class DeadCodeTraps {
@Benchmark
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public static void summaryStatistics_standardDeviationForFourNumbers() {
final SummaryStatistics summaryStatistics = new SummaryStatistics();
summaryStatistics.addValue(10.0);
summaryStatistics.addValue(20.0);
summaryStatistics.addValue(30.0);
summaryStatistics.addValue(40.0);
summaryStatistics.getStandardDeviation();
}
@Benchmark
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public static void summaryStatistics_standardDeviationForTenNumbers() {
final SummaryStatistics summaryStatistics = new SummaryStatistics();
summaryStatistics.addValue(10.0);
summaryStatistics.addValue(20.0);
summaryStatistics.addValue(30.0);
summaryStatistics.addValue(40.0);
summaryStatistics.addValue(50.0);
summaryStatistics.addValue(60.0);
summaryStatistics.addValue(70.0);
summaryStatistics.addValue(80.0);
summaryStatistics.addValue(90.0);
summaryStatistics.addValue(100.0);
summaryStatistics.getStandardDeviation();
}
}
我以为JIT会消除死代码,所以会同时执行两个方法。但最后,我有:
summaryStatistics_standardDeviationForFourNumbers 0.158 ± 0.046 DeadCodeTraps.summaryStatistics_standardDeviationForTenNumbers 0.359 ± 0.294
为什么JIT不优化呢? summaryStatistics.getStandardDeviation();
的结果不会在方法之外的任何地方使用,也不会由它返回。
(我正在使用 OpenJDK build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4)
如果您谈论的是 Apache Commons Math SummaryStatistics
class,那么它是一个巨大的 class。它的构造肯定不会被内联。要了解原因,运行 和 -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -XX:-BackgroundCompilation
死代码消除发生在内联之后。 未使用的对象将反向传播,但非内联构造函数将打破链条,因为 JIT 优化器无法再确保没有副作用。
也就是说,你希望淘汰的代码太大了