用java创建快速/可靠的基准测试?

我正在尝试使用java创建基准测试。 目前我有以下简单的方法:

public static long runTest(int times){
    long start = System.nanoTime();     
    String str = "str";
    for(int i=0; i<times; i++){
        str = "str"+i;
    }       
    return System.nanoTime()-start;     
}

我目前在多次发生的另一个循环中多次使用此循环,并获取运行此方法所需的最小/最大/平均时间。 然后我在另一个线程上开始一些活动并再次测试。 基本上我只是想得到一致的结果......如果我有runTest循环1000万次,这似乎是相当一致的:

Number of times ran: 5
The max time was: 1231419504 (102.85% of the average)
The min time was: 1177508466 (98.35% of the average)
The average time was: 1197291937
The difference between the max and min is: 4.58%

Activated thread activity.

Number of times ran: 5
The max time was: 3872724739 (100.82% of the average)
The min time was: 3804827995 (99.05% of the average)
The average time was: 3841216849
The difference between the max and min is: 1.78%

Running with thread activity took 320.83% as much time as running without.

但是这似乎有点多,而且需要一些时间......如果我在runTest循环中尝试一个较小的数字(100000)......它开始变得非常不一致:

    Number of times ran: 5
    The max time was: 34726168 (143.01% of the average)
    The min time was: 20889055 (86.02% of the average)
    The average time was: 24283026
    The difference between the max and min is: 66.24%

    Activated thread activity.

    Number of times ran: 5
    The max time was: 143950627 (148.83% of the average)
    The min time was: 64780554 (66.98% of the average)
    The average time was: 96719589
    The difference between the max and min is: 122.21%

    Running with thread activity took 398.3% as much time as running without.

有没有一种方法可以做这样的基准测试,既稳定又高效/快速?

顺便说一下,我没有测试开始和结束时间之间的代码。 我以某种方式测试CPU负载(请参阅我如何开始一些线程活动并重新测试)。 所以我认为我正在寻找一些东西来替代我在“runTest”中获得的代码,该代码将产生更快更一致的结果。

谢谢


简而言之:

(Micro-)基准测试非常复杂,因此请使用基准测试框架http://www.ellipticgroup.com/misc/projectLibrary.zip这样的工具 - 并且仍然对结果持怀疑态度(“将微观信任置于微观层面,基准“,Cliff博士点击)。

详细:

有很多因素可以强烈影响结果:

  • System.nanoTime的准确性和精确性:在最糟糕的情况下,与System.currentTimeMillis一样糟糕。
  • 代码热身和类加载
  • 混合模式:只有在经常调用代码块(1500或1000次)之后,JVM才会进行JIT编译(请参阅Edwin Buck的答案)
  • 动态优化:去优化,堆栈替换,死代码消除(您应该使用您在循环中计算的结果,例如打印它)
  • 资源回收:Garbace收集(请参阅Michael Borgwardt的回答)和对象定稿
  • 缓存:I / O和CPU
  • 整个操作系统:屏幕保护程序,电源管理,其他进程(索引器,病毒扫描等)
  • Brent Boyer的文章“Robust Java benchmarking,Part 1:Issues”(http://www.ibm.com/developerworks/java/library/j-benchmark1/index.html)是对所有这些问题的一个很好的描述,并且是/是你可以对它们做(例如使用JVM选项或事先调用ProcessIdleTask)。

    你将无法消除所有这些因素,因此统计数据是一个好主意。 但:

  • 不要计算最大值和最小值之间的差值,你应该努力计算标准偏差(结果{1,100次2,3}不同于{501次1次,501次3次})。
  • 通过产生置信区间(例如通过自举)来考虑可靠性。
  • 上述基准框架(http://www.ellipticgroup.com/misc/projectLibrary.zip)使用这些技术。 您可以在Brent Boyer的文章“鲁棒的Java基准测试,第2部分:统计和解决方案”(https://www.ibm.com/developerworks/java/library/j-benchmark2/)中阅读关于它们的内容。


    您的代码最终会主要测试垃圾回收性能,因为在循环中追加到String最终会创建并立即丢弃大量日益增多的String对象。

    这是内在地导致大量变化的测量的因素,并受到多线程活动的影响。

    我建议你在循环中做一些其他更具可预测性能的事情,比如数学计算。


    在1000万次运行中,几率是好的,HotSpot编译器检测到“大量使用”的代码并将其编译到机器本机代码中。

    JVM字节码被解释,这导致它容易受到发生在JVM中的其他后台进程的更多中断(如垃圾收集)。

    一般来说,这些基准充满了不成立的假设。 如果没有大量证据证明初始测量(时间)不是真正衡量您的任务和可能的其他背景任务,您无法相信微观基准测试能够证明其证明的内容。 如果你不试图控制后台任务,那么测量就没那么有用了。

    链接地址: http://www.djcxy.com/p/86535.html

    上一篇: Create quick/reliable benchmark with java?

    下一篇: System.currentTimeMillis vs System.nanoTime