Tho*_*day 21 c++ optimization performance jit
是否有人使用JIT技巧来提高静态编译语言(如C++)的运行时性能?看起来热点分析和基于运行时期间观察的分支预测可以提高任何代码的性能,但也许有一些基本的战略原因,为什么在运行时进行这样的观察和实现更改只能在虚拟机中实现.我清楚地记得听到C++编译器编写者嘀咕着"你也可以为用C++编写的程序做到这一点",同时听动态语言爱好者谈论收集统计数据和重新安排代码,但我的网络搜索支持这种记忆的证据已经枯竭了.
小智 33
配置文件引导优化与运行时优化不同.优化仍然是基于分析信息离线完成的,但是一旦二进制文件出厂,就没有持续优化,因此如果配置文件引导优化阶段的使用模式不能准确反映实际使用情况,那么结果将是不完美,程序也不会适应不同的使用模式.
您可能很有兴趣寻找有关HP Dynamo的信息,尽管该系统专注于本机二进制 - >本机二进制转换,尽管由于C++几乎完全编译为本机代码,我认为这正是您所寻找的.
您可能还想看看LLVM,它是一个支持JIT编译和运行时优化的编译器框架和中间表示,虽然我不确定是否有任何基于LLVM的运行时可以编译C++并执行+运行时优化它.
Nil*_*nck 10
在过去的几年里,我做了很多这样的优化.这是我实现的图形渲染API.由于API定义了数千种不同的绘图模式,因为通用功能是减慢速度的方法.
我最终编写了我自己的小Jit编译器,用于特定于域的语言(非常接近asm,但是引入了一些高级控制结构和局部变量).
我得到的性能提升在10到60之间(取决于编译代码的复杂性),因此额外的工作得到了很大的回报.
在PC上,我不会开始编写自己的jit-compiler,而是使用LIBJIT或LLVM进行jit编译.在我的情况下是不可能的,因为我正在研究LIBJIT/LLVM不支持的非主流嵌入式处理器,所以我不得不发明自己的.
小智 8
答案更有可能:没有人比C++的PGO更多,因为它的好处可能不明显.
让我详细说明:JIT引擎/运行时从开发人员的角度来看既有瑕疵又有弊端:他们在运行时有更多的信息,但分析的时间却很少.一些优化非常昂贵,如果没有对开始时间产生巨大影响,你很可能会看到:循环展开,自动矢量化(在大多数情况下也基于循环展开),指令选择(使用SSE4.1 for使用SSE4.1的CPU结合指令调度和重新排序(使用更好的超标量CPU).这种优化与C代码(可从C++访问)相结合.
用于高级编译的单个完整编译器体系结构(据我所知)是使用分层编译的Java Hotspot编译和体系结构(Java Azul的系统,当时流行的JaegerMonkey JS引擎).
但是运行时最大的优化之一是:
多态内联缓存(意味着如果你运行带有某些类型的第一个循环,第二次,循环的代码将是来自前一个循环的专用类型,并且JIT将放置一个后卫并将默认分支作为内联类型,并基于它,使用基于SSA -form引擎的这种专门形式将应用常量折叠/传播,内联,死代码消除优化,并取决于JIT的 "高级" ,将做一个改进或改进的CPU寄存器分配.)正如您可能注意到的那样,JIT(热点)将主要改进分支代码,并且运行时信息将比C++代码更好,但是静态编译器,在它的旁边做分析,指令重新排序,对于简单的循环,可能会好一点性能.此外,通常,C++代码,需要快速的区域往往不是OOP,因此JIT优化的信息不会带来如此惊人的改进.
的另一个优点即时编译器是JIT能跨组件,因此,如果想要做内联它有更多的信息.
让我详细说明一下:假设你有一个基类A,你只有一个实现它,即另一个包/ assembly/gem/etc中的B. 并动态加载.
该JIT,因为它看到,B是A的唯一实现,它可以无处不取代它的内部表示A和B代码调用,并且该方法的调用不会做调度(旁观虚函数表),但会直接调用.这些直接电话也可以内联.例如,这个B有一个方法:getLength()返回2,所有的调用getLength()可以全部减少到常数2.最后,C++代码将无法跳过另一个dll的B虚拟调用.
C++的某些实现不支持优化更多.cpp文件(即使在今天最近版本的GCC中存在-lto标志,这使得这成为可能).但是如果你是一个关心速度的C++开发人员,你可能会把所有敏感类放在同一个静态库中,甚至放在同一个文件中,这样编译器就可以很好地内联它,使JIT拥有它的额外信息. ,由开发者自己提供,所以没有性能损失.