What is JIT?
JIT stands for Just-In-Time compiler. It converts repeatedly used code to bytecode which can be sent to processor directly hence saving time of compiling same piece of code again and again.
MJIT is introduced in Ruby 2.6. It is most commonly known as MRI JIT or Method Based JIT.
It’s part of Ruby 3x3 project that was started by Matz. The name was to signify that Ruby 3.0 will be 3 times faster than Ruby 2.0 and it focused mainly on performance. Apart from performance it also aims for following things.
MJIT is still in development and hence MJIT is optional in Ruby 2.6. If you are running Ruby 2.6 then execute following commnad.
You will see following options.
Vladimir Makarov proposed to improve performance by replacing VM instructions with RTL(Register Transfer Language) and introducing Method based JIT compiler.
Vladimir explained MJIT architecture in his RubyKaigi 2017 conference keynote.
Ruby’s compiler converts the code to YARV(Yet Another Ruby VM) instructions and then these instructions are run by the Ruby Virtual Machine. Code that is executed too often are converted to RTL instructions which runs faster.
Let’s take a look at how MJIT works.
Let’s run this code with MJIT options and check what we got.
Nothing interesting right? And why is that?
because we are iterating the loop for 4 times
and default value for MJIT to work is 5.
We can always decide after how many calls MJIT should work by providing
Let’s tweak the program a bit so that MJIT gets some work to do.
After running above code we can see some work done by MJIT.
Here’s whats happening. Method ran 4 times
and on 5th call it found that it is running same code again.
So MJIT started a separate thread to convert the code into RTL instructions
which created shared object library.
Next threads took that shared code and executed directly.
As we passed option
we can see what MJIT did.
What we are seeing in output are followings.
- Time took to compile.
- What block of code is compiled by JIT.
- Location of compiled code.
We can open the file
see how MJIT converted piece of code to binary instructions but for that
we need to pass another option which is
then just inspect those files.
After compiling code to RTL instructions, take look at the execution time. It dropped down to 0.10 ms from 0.46 ms. That’s a neat speed bump.
Here is comparation across some of the Ruby versions for some basic operations.
Rails comparison on Ruby 2.5, Ruby 2.6 and Ruby 2.6 with JIT
Create a rails application with different Ruby versions and start a server. We can start rails server with JIT option as shown below.
Now we can start testing performance on servers. What we found is that Ruby 2.6 is faster than Ruby 2.5, but enabling JIT in Ruby 2.6 is not adding more value to Rails application.
MJIT status and future directions
- It’s in early development stage.
- Doesn’t work on windows.
- Needs more time to mature.
- Needs more optimisations.
- MJIT can use GCC or LLVM in the future C Compilers.