如何停止 JVM 跳过循环

问题描述

我有自己的测试类,它应该在 JVM 不删除任何内容的情况下进行计时。一些示例测试时间为 100,000,000 次,将 Java 从 StrictMath.sin() 调用的本机与我自己的进行比较:

30 度
sineNative(): 18,342,858 ns (#1),1,574,331 ns (#10)
sinCosTanNew6(): 13,751,140 ns (#1),569,848 ns (#10)

60 度
sineNative(): 2,520,327,020 ns (#1),2,108,337 ns (#10)
sinCosTanNew6(): 12,935,959 ns (#1),565,365 ns (#10)

从 30 到 60 个本地时间猛增 * 137,而我的是 ~ 恒定的。此外,即使在 repsDone 返回 == reps 时,某些时间也是不可能的低。我希望他们应该 > 1*reps。

中央处理器:G3258 @ 4GHz
操作系统:Windows 7 HB SP1
构建路径:jre1.8.0_211
代表:

public final class MathTest {
    private static int sysReps = 1_000_000;
    private static double value = 0;
    private static final double DRAD_ANGLE_30 = 0.52359877559829887307710723054658d;
    private static final double DRAD_ANGLE_60 = 1.0471975511965977461542144610932d;
    private static double sineNative(double angle ) {
        int reps = sysReps * 100;
            //int repsDone = 0;
        value = 0;
        long startTime,endTime,timeDif;
        startTime = System.nanoTime();
        for (int index = reps - 1; index >= 0; index--) {
            value = Math.sin(angle);
                //repsDone++;
        }
        endTime = System.nanoTime();
        timeDif = endTime - startTime;
        System.out.println("sineNative(): " + timeDif + "ns for " + reps + " sine " + value + " of angle " + angle);
            //System.out.println("reps done: "+repsDone);
        return value;
    }
    private static void testSines() {
        sineNative(DRAD_ANGLE_30);
        //sinCosTanNew6(IBIT_ANGLE_30);
    }
        /* Warm Up */
    private static void repeatAll(int reps) {
        for (int index = reps - 1; index >= 0; index--) {
            testSines();
        }
    }
    public static void main(String[] args) {
        repeatAll(10);
    }
}

我尝试在循环中添加 angle++ 并将时间乘以更合理的水平,但这与数学混淆。我需要一种方法来诱使它运行所有代码 x 次。单次通过时间非常不稳定,调用 nanotime() 需要时间,所以我需要一个大数的平均值。

解决方法

问题在于您从不使用/引用 sineNative 返回的结果。 JIT 编译器足够聪明,可以计算出您从不使用返回值,因此它最终什么也不做。解决此问题的一个非常简单的方法是为您的返回值添加一个虚拟检查。 (例如 if (Math.sin(angle) > 1) { System.out.println("Impossible!"); })

如果您正在编写这样的基准测试,那么使用 JMH (https://github.com/openjdk/jmh) 之类的东西会很有用,它会自动为您的返回变量创建一个黑洞,以便 JIT 编译器不会优化该值。 (参见示例 https://github.com/openjdk/jmh/blob/master/jmh-samples/src/main/java/org/openjdk/jmh/samples/JMHSample_09_Blackholes.java