如何合理地确定代码块是否已被JIT编译?

时间:2013-12-29 01:38:51

标签: java testing bytecode performance-testing jit

在进行java代码的性能测试时,您需要测试JIT编译代码,而不是原始字节码。要使字节码被编译,必须通过多次执行代码来触发编译,并且还允许后台线程有足够的产生时间来完成编译。

  • 代码路径的“预热”执行的最小数量是什么,需要“非常有信心”代码将被JIT编译?
  • 主线程的最小休眠时间是什么“非常有信心”编译完成(假设代码块很小)?

我正在寻找可以安全应用于任何现代操作系统的门槛,比如Mac OS或Windows用于开发环境,Linux用于CI /生产。

3 个答案:

答案 0 :(得分:13)

由于OP的意图实际上并未确定该块是否是JIT编译的,而是确保测量优化的代码,我认为OP需要观察some of these benchmarking talks

TL; DR版本:没有可靠的方法来判断你是否达到了稳定状态":

  • 您只能在很长一段时间内测量球场估计值,以确定您的具体系统达到某种状态所需的正常时间,并且可以声称“稳定”#。

  • 观察-XX:+PrintCompilation并不可靠,因为您可能处于计数器仍处于不稳定状态的阶段,JIT正等待编译下一批现在热门的方法。因此,你可以很容易地获得一些热身。该方法甚至可以多次重新编译,具体取决于分层编译器的数量。

  • 虽然有人可能会争论调用阈值,但这些事情也不可靠,因为可能涉及分层编译,方法可能会更快地在调用者中内联,概率计数器可能会错过更新等等。这是关于-XX:CompileThreshold=#的常识是不可靠的。

  • JIT编译不是您追求的唯一预热效果。自动GC启发式,调度程序启发式等也需要预热。

获取一个microbenchmark线束,让您更轻松地完成任务!

答案 1 :(得分:6)

首先,client or in server mode中的JVM运行结果很可能会有所不同。其次,这个数字在很大程度上取决于代码的复杂性,我担心你将不得不为每个测试用例进行探索性估计。通常,字节代码越复杂,可以对其应用的优化越多,因此您的代码必须相对更热才能使JVM深入到其工具箱中。 JVM可能会重新编译一段代码十几次。

此外,“真实世界”编译取决于运行字节代码的上下文。例如,当单态调用站点被提升为变形站点时,可能会发生编译,使得观察到的编译实际上代表 de - 优化。因此,在假设您的微型标记反映代码的实际性能时要小心。

我建议你使用CompilationMXBean代替建议的标志,它允许你检查JVM在编译时仍然花费的时间。如果时间太长,请重新运行测试,直到值稳定足够长。 (请耐心等待!)框架可以帮助您创建良好的基准。就个人而言,我喜欢caliper。但是,永远不要相信你的基准。

根据我的经验,当您模仿 javac 的习语时,自定义字节代码的效果最佳。提到我可以讲述的一个轶事,我曾经为Java源代码编写了自定义字节代码,相当于:

int[] array = {1, 2, 3};

javac 创建数组并使用dup来分配每个值,但我将数组引用存储在局部变量中,并将其加载回操作数堆栈以分配每个值。阵列的大小比那个大,并且有一个值得注意的性能差异。

最后,在编写基准之前,我建议this article

答案 2 :(得分:4)

不确定数字,但在进行速度测试时,我所做的是:

  • 使用-XX:-PrintCompilation flag
  • 运行
  • 预热JVM,直到不再生成编译调试消息,如果可能,时间变得一致