

JIT Compilers for Ruby and Rails: An Overview
source link: https://blog.appsignal.com/2022/09/07/jit-compilers-for-ruby-and-rails-an-overview.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

JIT Compilers for Ruby and Rails: An Overview

Renata Marques on Sep 7, 2022

A program is compiled at runtime using a different method from pre-execution compilation. This process is known as just-in-time compilation or dynamic translation.
In this post, we'll look at why JIT compilation can be a good choice for your Ruby on Rails app, before looking at some of the options available (YJIT, MJIT, and TenderJIT) and how to install them.
But first: how does JIT compilation work?
How a JIT Compiler Works
Just-in-time compilation is a method of running computer code that requires compilation while running a program.
This could entail translating the source code, but it's most frequently done by converting the bytecode to machine code, which is then run directly.
The code being executed is often continuously analyzed by a system using a JIT compiler. This identifies sections of code where the benefit of compilation or recompilation (in terms of speed) outweighs the cost.
Benefits of JIT Compilation for Ruby
JIT compilation combines some of the benefits (and shortcomings) of the two conventional methods for converting programs into machine code: interpretation and ahead-of-time compilation (AOT).
Roughly speaking, it combines the flexibility of interpretation with the speed of generated code, and the additional overhead of compiling and linking (not just interpreting).
JIT compilation is a type of dynamic compilation that enables adaptive optimization techniques, including dynamic recompilation and speed-ups tailored to certain microarchitectures. Due to a runtime system's ability to handle late-bound data types and impose security guarantees, dynamic programming languages like Ruby are particularly well-suited for interpretation and JIT compilation.
An optimizing compiler like GCC can more efficiently optimize instructions — a significant advantage of adopting a register-oriented architecture. Compilers operate on intermediate representation with register-based architecture.
Once your instructions reach an intermediate representation during compilation, GCC does additional passes to speed up the CPU's execution of your instructions.
JIT Compilers for Ruby: YJIT, MJIT, and TenderJIT
Now let's explore the different JIT compilers available for Ruby — YJIT, MJIT, and TenderJIT — and how you can set them up.
MJIT (Method-based Just-in-time Compiler) for Ruby
Vladimir Makarov implemented MJIT, and it was the first compiler methodology implemented in Ruby based on the C language. It works with Ruby 2.6, uses YARV instructions, and compiles instructions often used in binary code.
For programs that are not input/output-bound, MJIT enhances performance.
YJIT is better than this original C-based compiler in terms of performance. Ruby 3's JIT is the quickest JIT that MRI has ever had, made possible by the excellent work of MJIT.
How to Use MJIT
To use MJIT, you can enable the JIT in Ruby 2.6 and with the --jit
option.
ruby --jit app.rb
If you skip this part, MJIT will show an error.
clang: error: cannot specify -o when generating multiple output files
MJIT warning: Making precompiled header failed on compilation. Stopping MJIT worker...
MJIT warning: failed to remove "/var/folders/3d/fk_588wd4g12syc56pjqybjc0000gn/T//_ruby_mjit_hp25992u0.h.gch": No such file or directory
Successful MJIT finish
A collection of JIT-specific settings included in Ruby 2.6 helps us understand how it functions. Run ruby --help
to view these options.
In short, MJIT executes in a different thread and is asynchronous. It will begin just-in-time compilation following the first five runs of a calculation.
YJIT for Ruby on Rails
A recent JIT compiler called YJIT was released with Ruby 3.1. It promises a lot of improvements and better performance. Still a work-in-progress project designed by Shopify with experimental results, it must be used with caution, especially on larger applications.
With that in mind, YJIT enhances the performance of Ruby on Rails applications. The majority of real-world software benefits from the fast warm-up and performance enhancements provided by the YJIT basic block versioning JIT compiler.
A JIT compiler will be gradually built into CRuby as part of the YJIT project, eventually replacing the interpreter for most of the code execution.
Official benchmarks — see 'YJIT: Building a New JIT Compiler for CRuby' — show that YJIT improved performance over the default CRuby interpreter by:
- 20% on railsbench
- 39% on liquid template rendering
- 37% on activerecord
However:
Only about 79% of instructions in railsbench are executed by YJIT, and the rest run in the default interpreter.
Source: YJIT: Building a New JIT Compiler for CRuby
This means that a lot still needs to be done to improve YJIT's current results.
Even so, YJIT performs at least as well as the interpreter on every benchmark, even on the hardest ones, and reaches near-peak performance after just one iteration of every benchmark.
How to Use YJIT
Note: YJIT is currently limited to macOS and Linux on x86-64 platforms. Also, as mentioned, YJIT is not recommended for large applications (yet).
YJIT is disabled by default. If you want to enable it, first specify the --yjit
command-line option.
You need to check if it is installed, so run ruby --enable-yjit -v
. If warning: unknown argument for --enable:
yjit'` shows up, you have to install it.
Then open irb
and set RUBY_YJIT_ENABLE=1
. You can exit and now, you're ready to use YJIT. The command ruby --enable-yjit -v
must return something like ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [arm64-darwin21]
TenderJIT
With a design largely based off YJIT, TenderJIT is an experimental JIT compiler for Ruby. What's different about TenderJIT is that it's written in pure Ruby.
This is a demo project and the aim is to ship it as a gem. In the meantime, you can experiment with it, but bear in mind it's still a work in progress. Ruby 3.0.2 or later is required for TenderJIT.
How to Use TenderJIT
TenderJIT does not currently do method compilation automatically. To compile a method, you must manually configure TenderJIT.
Clone the repository and run the following commands:
$ bundle install
$ bundle exec rake test
You must set it manually on your code:
require "tenderjit"
def your_method
...
end
jit = TenderJIT.new
jit.compile(method(:your_method))
Each YARV instruction in the target method is read by TenderJIT, which then transforms it into machine code.
For more examples with TenderJIT, check one of these videos: A JIT compiler for Ruby with Aaron Patterson and Hacking on TenderJIT!
Wrapping Up
In this post, we've taken a quick look at three JIT compilers for Ruby — MJIT, YJIT, and TenderJIT — and how to set them up. Each of the options is experimental and comes with its own limitations.
However, YJIT is the most mature at the moment, and it has the biggest potential to grow and scale. It demonstrates better performance over the other Ruby JITs, was developed with Ruby 3.1.0, and is quickly becoming an important part of CRuby.
Check out this post if you want to build your own compiler for Ruby.
Happy coding!
P.S. If you'd like to read Ruby Magic posts as soon as they get off the press, subscribe to our Ruby Magic newsletter and never miss a single post!
Recommend
-
32
If you already know lots about JIT in general and Ruby’s MJIT in particular… you may not learn much new in this post. But in case you wonder “what is JIT?” or “what is MJIT?” or “what’s different about Ruby’s JIT?” or perh...
-
10
Building and Testing Resilient Ruby on Rails Applications ...
-
14
Upgrading a trivial Rails app from Ruby 2.3.1 to 2.7 and from Rails 4.2.6 to 6.0.3 This blogpost describes the upgrading process of a trivial Rails app. The app is called PlusOne (it’s
-
10
Introduction to Ruby on Rails Patterns and Anti-patterns Nikola Đuza on Aug 5, 2020 “I absolutely love AppSignal.” Discover AppSignal
-
14
Rhizome - a JIT for Ruby, implemented in pure Ruby Rhizome is a paedagogical just-in-time compiler (JIT) for Ruby, implemented in pure Ruby. It's not really designed to be used. It's designed to show you how JITs work and why perhaps...
-
4
Ruby 将引入新 JIT 编译器:YJIT,平均速度提升 23%近日,Ruby 代码仓库新增了一个关于合并 YJIT 的PR。据介绍,YJIT 是一种使用 Lazy Basic Block Versioning (LBBV) 编译器架构构...
-
4
Ruby’s New JITRuby is about to get Way FasterCRuby just got a JIT! There have been many attempts at implementing a JIT for CRuby, the reference implementation of Ruby. None have been merged, until now...
-
12
Ruby 再引入另外一套 JIT 實做:RJIT 在 Hacker News Daily 上看到「
-
5
Ruby previews pure Ruby JIT compiler Ruby 3.3.0 brings significant performance improvements to YJIT and previews RJIT, an experimental just-in-time compi...
-
10
Node Weekly Issue 514 #514 — December 12, 2023 Read o...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK