【问题标题】:How to be reasonably sure a code block has been JIT compiled?如何合理确定代码块已被 JIT 编译?
【发布时间】:2014-01-16 06:14:55
【问题描述】:

在对 java 代码进行性能测试时,您希望测试 JIT 编译的代码,而不是原始字节码。要使字节码被编译,您必须通过多次执行代码来触发编译,并为后台线程留出足够的 yield 时间来完成编译。

  • “非常有把握”代码将被 JIT 编译所需的代码路径的最少“预热”执行次数是多少?
  • “非常有把握”编译完成的主线程的最短休眠时间是多少(假设代码块很小)?

我正在寻找一个可以安全地应用于任何现代操作系统的阈值,例如用于开发环境的 Mac OS 或 Windows,以及用于 CI/生产的 Linux。

【问题讨论】:

  • 请注意,JVM 已针对“类 Java”和常见程序的典型字节码进行了优化。根据字节码的特性,它可能永远不会被编译。

标签: java testing bytecode performance-testing jit


【解决方案1】:

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

TL;DR 版本:没有可靠的方法来确定您是否达到“稳定状态”:

  • 您只能测量很长一段时间,以获得您的混凝土系统达到您可以声称“稳定”的状态所需的通常时间的大致估计。

  • 观察-XX:+PrintCompilation 是不可靠的,因为您可能正处于计数器仍在不断变化的阶段,而 JIT 正在等待编译下一批现在很热的方法。正因为如此,你很容易有许多热身高原。该方法甚至可以重新编译多次,具体取决于等待的分层编译器数量。

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

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

获取一个微基准测试工具,让您更轻松地完成任务!

【讨论】:

    【解决方案2】:

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

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

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

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

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

    javac 创建数组并使用dup 分配每个值,但我将数组引用存储在局部变量中并将其加载回操作数堆栈以分配每个值。该数组的大小比这更大,并且存在显着的性能差异。

    最后,我推荐this article,然后再编写基准测试。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-05-30
        • 1970-01-01
        • 1970-01-01
        • 2015-03-23
        • 2010-12-02
        相关资源
        最近更新 更多