JIT编译器可以做AOT编译器不能做的事情?

时间:2018-09-25 20:58:55

标签: optimization compiler-construction compiler-optimization jit

即时(JIT)编译器可以基于提前(AOT)编译器不可用的运行时信息来优化程序。

此运行时信息最明显的示例是目标平台,例如程序运行所在的确切CPU,或可能可用的任何加速器(如GPU)。这就是OpenCL JIT编译的意义。

但是假设我们提前知道目标平台是什么:我们知道哪些SIMD扩展将可用,等等。AIT编译器无法利用JIT编译器利用其他哪些运行时信息?

一个HotSpot风格的JIT编译器会自动优化程序的热点...但是AOT编译器不能仅仅优化整个程序,热点和所有内容吗?

我想要一些JIT编译器可以执行而AOT编译器无法执行的特定优化的示例。如果您可以提供任何证据证明此类优化在“现实世界”方案中的有效性,则可以加分。

3 个答案:

答案 0 :(得分:2)

  

JIT编译器可以做AOT编译器不能做的事情吗?

理论上;没什么,因为如果愿意,AOT编译器可以在结果代码中插入JIT编译器(和/或可以生成自修改代码,生成123个备用版本,并根据运行时信息选择要使用的版本,... )。

在实践中; AOT编译器受到编译器设计人员希望处理的复杂程度,编译语言以及编译器使用方式的限制。例如,某些编译器(英特尔的ICC)将生成代码的多个版本,并(在运行时)根据运行的CPU来决定使用哪个版本,但是大多数编译器并非旨在执行此操作。许多语言没有提供任何控制“局部性”的方法(并减少了TLB丢失和缓存丢失的机会);通常,编译器的使用方式会产生阻碍优化的障碍(例如,以后链接在一起的单独的“编译单元” /目标文件,可能包括动态链接),在这种情况下,AOT编译器不可能对整个程序进行优化,而只能可能孤立地优化零件)。所有这些都是实现细节,而不是AOT的限制。

换句话说;实际上,“ AOT与JIT”是对实现的比较,而不是对“ AOT与JIT”本身的真正比较;实际上,由于实现细节,AOT的性能很差,而JIT的性能则明显差于性能,因为JIT本身是不好的(昂贵的优化根本不可行,因为它们是在运行时完成的); JIT看起来“几乎一样好”的唯一原因是它几乎“几乎一样好”。

答案 1 :(得分:2)

JIT可以基于运行时信息进行优化,这会导致在编译时无法证明的更严格的边界条件。例子:

  • 它可以看到内存位置没有别名(因为所采用的代码路径从不别名),因此将变量保存在寄存器中;
  • 它可以消除对永远不会发生的条件的测试(例如,基于参数的当前值);
  • 它可以访问整个程序,并可以在合适的地方内联代码;
  • 它可以在运行时根据特定的使用模式执行分支预测,从而达到最佳状态。

内联原则上也对现代编译器/链接器的链接时间优化开放,但如果在整个代码中应用以防万一,可能会导致代码膨胀。在运行时可以在必要时应用它。

如果程序被编译两次,并且之间进行测试,则可以使用普通编译器来改进分支预测。在第一次运行中,对代码进行检测,以便其生成概要分析数据,该数据将在生产编译运行中用于优化分支预测。如果测试运行不是典型的(并且并非总是容易得出典型的测试数据,或者使用模式可能会在程序的整个生命周期内变化),则预测也不会达到最佳。

此外,使用静态编译进行链接时间和运行时数据优化都需要在构建过程中付出巨大的努力(某种程度上,我还没有看到它们在我一生工作过的大约10个地方的生产中使用) ;使用JIT时,它们默认为打开状态。

答案 2 :(得分:0)

一个优点是JIT编译器可以连续分析代码并优化输出,例如对齐/取消对齐某些代码块,取消优化某些功能,对分支进行重新排序以减少错误预测...

当然,AoT编译器也可以进行配置文件引导的优化,但是它们受限于开发人员和测试人员执行的测试用例,可能无法反映实际输入的动态性质

例如,当Android在奇巧(Kitkat)中引入ART时,它已经从AoT退回到了牛轧糖和更高版本中的混合方法,其中应用程序的某些部分可以在不进行优化的情况下快速提前编译,然后在运行之后配置文件结果将在手机充电时再次用于优化应用程序

  

Android 7.0 Nougat向ART引入了具有代码概要分析功能的JIT编译器,从而使其能够在运行Android应用程序时不断提高其性能。 JIT编译器是对ART当前最新的Ahead of Time编译器的补充,有助于提高运行时性能。[9]

     

https://en.wikipedia.org/wiki/Android_Runtime

一些相关问题: