如何在Java中编写正确的微基准测试?

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

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

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

相关:秒表基准测试可以接受吗?


答案 1

关于编写 Java HotSpot 创建者微基准测试的提示:

规则 0:阅读一篇关于JVM和微基准测试的知名论文。一个很好的是Brian Goetz,2005年。不要对微观基准期望太高;它们仅测量有限范围的 JVM 性能特征。

规则 1:始终包括一个预热阶段,该阶段将一直运行测试内核,足以在定时阶段之前触发所有初始化和编译。(在预热阶段,迭代次数越少即可。经验法则是数万次内部循环迭代。

规则 2:始终使用 、 等运行,以便您可以验证编译器和 JVM 的其他部分在计时阶段没有执行意外工作。-XX:+PrintCompilation-verbose:gc

第2.1条规则:在计时和预热阶段的开始和结束时打印消息,以便验证在计时阶段没有来自规则 2 的输出。

规则 3:请注意 and 和 之间的区别,OSR 和常规编译。该标志报告带有 at 符号的 OSR 编译,以表示非初始入口点,例如:。首选服务器而不是客户端,常规而不是OSR,如果你追求最佳性能。-client-server-XX:+PrintCompilationTrouble$1::run @ 2 (41 bytes)

规则 4:请注意初始化效果。不要在计时阶段首次打印,因为打印会加载并初始化类。不要在预热阶段(或最终报告阶段)之外加载新类,除非您专门测试类加载(在这种情况下,仅加载测试类)。规则2是您抵御此类影响的第一道防线。

规则 5:请注意去优化和重新编译的影响。不要在计时阶段第一次采用任何代码路径,因为编译器可能会基于早期的乐观假设(即根本不会使用该路径)而垃圾并重新编译代码。规则2是您抵御此类影响的第一道防线。

规则6:使用适当的工具来阅读编译器的思想,并期望对它生成的代码感到惊讶。在形成关于什么使事情更快或更慢的理论之前,自己检查代码。

规则7:减少测量中的噪声。在安静的计算机上运行基准测试,并运行多次,丢弃异常值。用于使用应用程序序列化编译器,并考虑设置以防止编译器与自身并行运行。尽量减少GC开销,设置(足够大)等于并使用UseEpsilonGC(如果可用)。-Xbatch-XX:CICompilerCount=1XmxXms

规则8:使用一个库作为基准测试,因为它可能更有效,并且已经为此唯一目的进行了调试。例如JMHCaliperBill and Paul的Java优秀UCSD基准测试


推荐