JIT( just in time)可以说是编程语言为了达到第一宇宙速度的二级助推火箭,可以大幅优化long run程序的运行速度,Ruby最为一直被人诟病运行速度慢的语言,想要达到Ruby 3x3的承诺,想不通过JIT是相当困难的。但是JIT的开发可不是像我们随便开发一个Web应用那么简单,它就会开发火箭一样需要耗费大量的人力物力和才能到达比较不错的程度,像JVM的Hotspot和NASA开发土星五火箭一样,不知砸了多少钱。 话说回来Ruby的JIT也不是完全不可能,我们一穷二白的时候不是也在大漠中发射了长征5嘛。
Ruby JIT的方案
那么接下来就是聊聊小米加步枪外加大佬资助下的JIT们
- OMR JIT :是改版Ruby VM + Eclipse OMR JIT的结合产物(OMR 是基于OpenJDK 的JVM核心表现层抽象以用于跨语言使用通用的GC JIT的能力)。
- LLRB:基于LLVM 的 JIT编译器
- RTL-MJIT:RTL(Register Transfer Language) 寄存器转换语言 使用寄存器式虚拟机,代替YARV 的栈式虚拟机。
- YARV-MJIT : 是基于RTL-MJIT现有的基础上继续改造,使用原生的YARV。
其实除上面这四种JIT之外,之前还出现过这样的那样的,Ruby JIT不过最终都淹没在了历史的长河中。其中上面种方法本来,还是有可行性的,直到Matz钦点了MJIT之后,他两我估计是没什么戏了。所以我们主要就来说说下面两张方案
OMR没戏的原因是 Eclipse OMR 是开源基金会组织的,要知道Ruby社区一向对这种开源基金会不来电。
至于LLRB : 连作者自己都感觉就是玩票的项目,(还有一个原因是Matz觉得LLVM不成熟,所以基于LLVM的东西想进入Ruby trunk也没戏。
RTL-MJIT
RTL的作者是来自RedHat的编程大神,有近二十年开发GCC的经历(所以不用我多说你也猜到了RTL-MJIT可定跑不了要靠GCC)"RTL"以下简称,比较激进的一点就是使用寄存器式的VM代替原来YARV的栈式VM。
MJIT除此之外RTL有以下几个特性
- 使用Method JIT,进行优化
- 使用pthread 独立线程运行JIT
- 如果被优化的方法发生了改变,可以使用优化还原『deoptimistic』方法
优点:速度快,是目前优化速度最快的JIT,并且内存占用也比较少
缺点: 结构复杂,需要整体替换Ruby现有的YARV,所以需要做的工序非常多,目前还无法跑同Ruby spec的所以测试。
Ruby VM
栈式虚拟机 使用的是,零地址指令(操作地址隐含在栈中) 外加 『求值栈』和PC (程序计数器)来执行程序代码
优点:实现简单 ,由于指令中不必显式指定源与目标,VM可以设计得很简单,不必考虑为临时变量分配空间的问题,求值过程中的临时数据存储都让求值栈包办就行。
缺点:因为相比于RTL stack based 需要使用的指令比较多,程序移动的频率也较高,所以速度相比于RTL慢
寄存器式虚拟机
优点:相较于其他的JIT)而对于VM来说,源架构的求值栈或者寄存器都可能是用实际机器的内存来模拟的,所以性能特性与实际硬件又有点不同。一般认为基于寄存器的架构对VM来说也是更快的,原因是:虽然零地址指令更紧凑,但完成操作需要更多的load/store指令,也意味着更多的指令分派(instruction dispatch)次数与内存访问次数;访问内存是执行速度的一个重要瓶颈,二地址或三地址指令虽然每条指令占的空间较多,但总体来说可以用更少的指令完成操作,指令分派与内存访问次数都较少
Method JIT
JIT的优化方式分为Trace-based 和 Method-based JIT, 他们两个的区别就是 Method-based是按照方法为最小单位进行优化的,也就是会将一整个方法编译成native code 。Trace-based 则按照一次调用的执行路径进行优化,这个路径有可能跨越多个方法,最终会被优化成Native code 『有可能好几个方法的jit-ed Code 最后就是一个常数)
Benchmark
RTL-benchmarkYARV-MJIT
YARV-MJIT是基于RTL-MJIT现有的基础上进行改造,使用原生的YARV VM,取代激进的RTL,并且去掉了一下还不成熟的优化方法(test 跑不过),虽然它不是最好的,但是是目前最快最可行的方案。
YARV-MJITYARV-MJIT的method JIT 的优化阈值默认设置为5,也就是一个方法被反复调用5次后,JIT线程就会启动优化,将它通过GCC编译成so文件,然后等待下次直接运行native code
还有一点非常有意思的是,YARV JIT compiler是通过一个ERB模板去生成Ruby代码,再生成C代码,最后生成JIT优化过的C代码。
Ruby 2.6的MJIT
这次Ruby2.6 中合并的MJIT 其实是,使用YARV的编译器,以及基于RTL的MJIT基础架构,所以可以说MJIT是现在最可行的原型方案,之后还是有很多优化要在,并且也有希望在Ruby3x3中直接引入RTL来大幅提升运行速度,还有一个点要说的是,目前MJIT对应Rails来说还起不到什么优化作用。
Benchmark:
Optcarrot FPS总结
我们回顾了过去出现过的的Ruby JIT的几种方案,同时也审视了现行Ruby2.6的MJIT的优势与不足,还展望了 Ruby3x3中可能引入的RTL-JIT方案,最后总结就是『革命尚未成功,同志们还需努力』。
网友评论