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

使用java创建快速/可靠的基准测试?,java,benchmarking,Java,Benchmarking,我试图用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; } 但

我试图用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;     
}
但这似乎有点多,需要一些时间。。。如果我在运行测试循环中尝试一个较低的数字(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”中的代码,从而产生更快、更一致的结果


感谢

您的代码最终主要测试垃圾收集性能,因为在循环中添加字符串最终会创建并立即丢弃大量越来越大的字符串对象

这是一种固有的导致测量值差异很大的因素,并且受到多线程活动的强烈影响


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

在1000万次运行中,热点编译器很有可能检测到一段“大量使用”的代码,并将其编译成机器本机代码

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

一般来说,这些基准充满了不成立的假设。如果没有大量证据证明最初的测量(时间)并没有实际测量你的任务,可能还有其他一些背景任务,你就无法相信微观基准真的证明了它要证明的东西。如果您不尝试控制后台任务,那么度量就没那么有用了。

简而言之:

(微观)基准测试非常复杂,因此请使用基准测试框架之类的工具,并且仍然对结果持怀疑态度(“将微观信任置于微观基准中”,Cliff博士)

详细内容:

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

  • System.nanoTime的准确性和精度:在最坏的情况下,它与System.currentTimeMillis的精度一样差
  • 代码预热和类加载
  • 混合模式:JVM JIT编译(参见Edwin Buck的回答)仅在代码块被足够频繁地调用(1500或1000次)之后
  • 动态优化:去优化、堆栈替换、死代码消除(您应该使用在循环中计算的结果,例如打印)
  • 资源回收:garbace收集(参见Michael Borgwardt的答案)和对象终结
  • 缓存:I/O和CPU
  • 您的操作系统总体上:屏幕保护程序、电源管理、其他进程(索引器、病毒扫描等)
Brent Boyer的文章“Robust Java benchmarking,第1部分:问题”(Robust Java benchmarking,Part 1:Issues)很好地描述了所有这些问题,以及您是否可以/可以针对这些问题采取哪些措施(例如,预先使用JVM选项或调用ProcessIdleTask)

你无法消除所有这些因素,所以做统计是个好主意。但是:

  • 不要计算最大值和最小值之间的差值,而应该努力计算标准偏差(结果{1,1000乘以2,3}与{501乘以1,501乘以3}不同)
  • 通过产生置信区间(例如通过自举)来考虑可靠性

上述基准测试框架()使用了这些技术。您可以在Brent Boyer的文章“健壮的Java基准测试,第2部分:统计数据和解决方案”(robustJava benchmarking,Part 2:Statistics and solutions)中阅读到它们

那可能是jit编译热路径。。。?也许可以尝试禁用jit(在Sun VM上有这样做的选项)?注意:一个伟大的库提供了上面所有的基准信息和更多信息。你不必自己实现所有这些。@Rom1,不确定你的意思@Benjamin,从我所能告诉你的,这更多的是关于基准代码的,我希望用更一致的东西来代替它。我尝试循环使用temp*I%10000(其中temp是一个初始化为10000的int),但仍然得到非常不一致的结果。
    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.