如何用Java编写(并运行)正确的微基准测试?

我正在寻找一些代码示例和注释,以说明需要考虑的各种事情。

示例:基准测试应该测量时间/迭代还是迭代/时间,为什么?

相关:秒表基准测试是可接受的?


当前回答

Java基准测试的重要事项是:

Warm up the JIT first by running the code several times before timing it Make sure you run it for long enough to be able to measure the results in seconds or (better) tens of seconds While you can't call System.gc() between iterations, it's a good idea to run it between tests, so that each test will hopefully get a "clean" memory space to work with. (Yes, gc() is more of a hint than a guarantee, but it's very likely that it really will garbage collect in my experience.) I like to display iterations and time, and a score of time/iteration which can be scaled such that the "best" algorithm gets a score of 1.0 and others are scored in a relative fashion. This means you can run all algorithms for a longish time, varying both number of iterations and time, but still getting comparable results.

我正在写一篇关于。net基准测试框架设计的博客。我有一些以前的帖子,也许能给你一些想法——当然,不是每件事都合适,但其中一些可能是合适的。

其他回答

为了补充其他优秀的建议,我还会注意以下几点:

For some CPUs (e.g. Intel Core i5 range with TurboBoost), the temperature (and number of cores currently being used, as well as thier utilisation percent) affects the clock speed. Since CPUs are dynamically clocked, this can affect your results. For example, if you have a single-threaded application, the maximum clock speed (with TurboBoost) is higher than for an application using all cores. This can therefore interfere with comparisons of single and multi-threaded performance on some systems. Bear in mind that the temperature and volatages also affect how long Turbo frequency is maintained.

也许您可以直接控制的一个更根本的重要方面是:确保您在测量正确的东西!例如,如果您正在使用System.nanoTime()对特定代码进行基准测试,请将对赋值的调用放在有意义的位置,以避免测量您不感兴趣的内容。例如,不要做:

long startTime = System.nanoTime();
//code here...
System.out.println("Code took "+(System.nanoTime()-startTime)+"nano seconds");

问题是,当代码完成时,您不能立即得到结束时间。相反,试试下面的方法:

final long endTime, startTime = System.nanoTime();
//code here...
endTime = System.nanoTime();
System.out.println("Code took "+(endTime-startTime)+"nano seconds");

我知道这个问题已经被标记为已回答,但我想提到两个帮助我们编写微基准的库

来自谷歌的卡尺

入门教程

http://codingjunkie.net/micro-benchmarking-with-caliper/ http://vertexlabs.co.uk/blog/caliper

来自OpenJDK的JMH

入门教程

避免JVM上的基准测试陷阱 使用JMH进行Java微基准测试 JMH简介

还应该注意的是,在比较不同的实现时,分析微基准测试的结果可能也很重要。因此,应进行显著性检验。

这是因为在基准测试的大多数运行过程中,实现A可能比实现B更快,但A也可能有更高的差异,因此与B相比,A的测量性能收益将没有任何意义。

因此正确编写和运行微基准测试也很重要,但正确分析它也很重要。

Java基准测试的重要事项是:

Warm up the JIT first by running the code several times before timing it Make sure you run it for long enough to be able to measure the results in seconds or (better) tens of seconds While you can't call System.gc() between iterations, it's a good idea to run it between tests, so that each test will hopefully get a "clean" memory space to work with. (Yes, gc() is more of a hint than a guarantee, but it's very likely that it really will garbage collect in my experience.) I like to display iterations and time, and a score of time/iteration which can be scaled such that the "best" algorithm gets a score of 1.0 and others are scored in a relative fashion. This means you can run all algorithms for a longish time, varying both number of iterations and time, but still getting comparable results.

我正在写一篇关于。net基准测试框架设计的博客。我有一些以前的帖子,也许能给你一些想法——当然,不是每件事都合适,但其中一些可能是合适的。

基准应该测量时间/迭代还是迭代/时间,为什么?

这取决于你要测试什么。

如果您对延迟感兴趣,则使用时间/迭代,如果您对吞吐量感兴趣,则使用迭代/时间。