The method JIT compiler for Ruby 2.6

Last updated 1 year ago by Takashi Kokubun

ruby

What's "MJIT"?

Let me share the summary about recent JIT topics on Ruby. Those who read the above articles may want to skip this section.

The RTL instruction project

In July 2016, Vladimir Makarov, or Vlad, who optimized Hash at Ruby 2.4 filed a ticket "VM performance improvement proposal" (Feature #12589). It's a project to replace all Ruby VM's stack-based instruction set with register-based one, which is named RTL (Register Transfer Language) instructions.

He is also known as the author of GCC's register allocator and a maintainer of its instruction scheduler. I assumed that he wanted to apply some optimization knowledge in GCC to Ruby.

While it's such a big change to replace many parts of Ruby VM, he successfully passed make test with RTL instruction implementation. It succeeded to improve some micro benchmarks, but a larger benchmark named Optcarrot wasn't improved.

MJIT: JIT compiler that runs on RTL instructions To approach the problem, in March 2017, he also published JIT compiler which compiles RTL instructions, which is named MJIT (MRI JIT).

He discussed some possible JIT methods in rtlmjitbranch and chose the approach that generates C code to a disk, lets C compiler compile it to .so and loads machine code from the object file.

JIT succeeded to make the Optcarrot result 2 or 3 times faster.

On the other hand, as a side effect of largely rewriting the implementation of VM, although the make test is passed, a more severe test such as make test-all` is not passed regardless of whether JIT is enabled or disabled, and Rails fails to start on the RTL instructions.

YARV-MJIT: Yet another JIT compiler that runs on YARV instructions In this way, RTL instruction conversion was a somewhat risky change, but my company implements cloud service as Rails application and provides it, so very high availability is required. If high risk changes were made to Ruby, upgrading Ruby would be very difficult.

After Vlad's session at RubyKaigi last year, I thought about how to reduce the risk to introduce JIT compiler to Ruby. Then I decided to implement another approach called YARV-MJIT, which compiles original stack-based YARV instructions instead of RTL instructions.

The JIT approach is very safe because it can be achieved without modifying VM implementation at all. Even if you find some bug after next Ruby release, you can ensure Ruby works as before by disabling optional JIT compiler.

As it doesn't change bytecode dynamically to avoid risks, it can't reach the performance of original MJIT. But with some improvements, I succeeded to make its performance comparable with MJIT.

By removing some premature aggressive optimizations, YARV-MJIT could pass all Ruby test cases with and without JIT enablement, keeping the performance improvement in some level. I proposed to merge it to Ruby in late 2017, and it's successfully merged this month after fixing some potential bugs and random crashes.

Read full Article