All original content is created in Ukrainian. Not all content has been translated yet. Some posts may only be available in Ukrainian.Learn more

Enabling YJIT in Ruby 3.2.1 (Ruby on Rails)

Post cover: Enabling YJIT in Ruby 3.2.1 (Ruby on Rails)
This content has been automatically translated from Ukrainian.
First, we need to understand what JIT, YJIT are and whether we need them. In this note, I will describe the process of updating Ruby (since YJIT is installed with Ruby only when using a flag). We will test the speed of Ruby and Ruby with YJIT.

What is JIT and YJIT?

JIT (Just-In-Time) compilation in Ruby is a technology that transforms Ruby bytecode into native machine code directly during program execution. Using JIT can significantly improve the performance of program execution since native machine code runs faster than interpreted bytecode. Ruby uses the YARV (Yet Another Ruby VM) virtual machine, which transforms the written Ruby code into bytecode before executing it. Adding JIT to this process allows for dynamic compilation of some parts of the code on the fly, speeding up code execution and reducing server load.
YJIT is a new JIT compiler that has been built into Ruby since version 3.1. YJIT uses so-called "lazy" JIT compilation, where compilation is performed only for "hot" execution paths that are executed frequently. This reduces the cost of compiling code that is executed rarely and provides a performance boost where it is most needed.
YJIT increases the execution speed of programs without the need for significant changes to the code itself. YJIT is the result of an attempt to optimize Ruby's performance using JIT compilation while maintaining stability and compatibility with existing programs.

Checking if YJIT is enabled

My local setup is macOS, rbenv, and brew. Locally, we check the Ruby version and whether YJIT is enabled:
Terminal:
ruby -v

ruby 3.2.1
Rails Console:
irb(main):003:0> RubyVM::YJIT.enabled?
(irb):3:in `<main>': uninitialized constant RubyVM::YJIT (NameError)
                                                          
RubyVM::YJIT.enabled?                                     
      ^^^^^^
That is, currently Ruby does not have YJIT.

Measuring the execution speed of Ruby without YJIT

Let's create a script that will calculate the Fibonacci sequence. I did a bit of Googling and asked ChatGPT how to do simple benchmarking, and this is the most common option.
We create a file benchmark.rb with the code:
require 'benchmark'

def fibonacci(n)
  return n if n <= 1
  fibonacci(n - 1) + fibonacci(n - 2)
end

puts Benchmark.measure {
  fibonacci(40)
}
We run:
ruby ~/Desktop/benchmark.rb
And my result currently (without YJIT):
 8.309469   0.000711  8.310180 (8.320920)

Installing Ruby with YJIT

Currently, I have Ruby 3.2.1 (rbenv). I need to install the same version, but with YJIT. So let's get started.
Disclaimer:
Everyone has their own setup. The example provided is just my case.
The official documentation states that YJIT requires:
  • A C compiler such as GCC or Clang
  • GNU Make and Autoconf
  • The Rust compiler rustc and Cargo (if you want to build in dev/debug mode)
    • The Rust version must be >= 1.58.0.
From all this, I only need to install Rust (Cool, right? The Rust programming language is used as a compiler).
We install Rust using brew:
brew install rust
This may take quite a long time (~10min).
In .zshrc, you need to add the following flag:
export RUBY_CONFIGURE_OPTS="--enable-yjit"
Without the flag, Ruby will be installed without YJIT (by default, it is disabled). This is an important point.
Restart the terminal to pull in RUBY_CONFIGURE_OPTS
We install Ruby (technically, rbenv install 3.2.1 will run with the flag --enable-yjit):
\W $ rbenv install 3.2.1
rbenv: /Users/user/.rbenv/versions/3.2.1 already exists
continue with installation? (y/N) y
After installation, we check if YJIT works and benchmark the execution of the benchmark.rb file.
There is a nuance here. YJIT, even if installed with Ruby, is disabled.
Add this flag to run Ruby with YJIT:
export RUBY_YJIT_ENABLE=true
Then we should see +YJIT when checking ruby -v
ruby -v
ruby 3.2.1 (2023-02-08 revision 31819e82c8) +YJIT [x86_64-darwin23]
irb
RubyVM::YJIT.enabled?
=> true

YJIT is working. Next, we test.

ruby ~/Desktop/benchmark.rb
And we get:
1.624351 0.000245 1.624596 (1.626251)
So the difference in execution speed of the script is 5.11 times:
8.309469/1.624351=5.1155624616
Technically, this is quite a large and significant upgrade in Ruby's speed. By enabling just one option, at the compilation level, we achieve a very powerful optimization. YJIT is already production-ready and can be used on production servers, for example, for Ruby on Rails applications. For instance, Heroku offers to enable YJIT with just one command:
heroku config:set RUBYOPT="--enable-yjit"

This post doesn't have any additions from the author yet.

27 Apr 09:29

What are CC and BCC in emails? What are they for and how to use them?

meme code
meme code@memecode
What is a prompt and prompt engineering?
03 May 12:08

What is a prompt and prompt engineering?

meme code
meme code@memecode
ZOMBIE in Ruby. What is it?
03 May 12:41

ZOMBIE in Ruby. What is it?

meme code
meme code@memecode
03 May 13:13

What is the Garbage Collector in Ruby? How does it work and what is GC used for?

meme code
meme code@memecode
A little about the types of Ruby implementations (CRuby (MRI), JRuby, Rubinius, TruffleRuby, mruby)
05 May 12:36

A little about the types of Ruby implementations (CRuby (MRI), JRuby, Rubinius, TruffleRuby, mruby)

meme code
meme code@memecode
07 May 07:24

What is native machine code?

meme code
meme code@memecode
09 May 12:43

[Fix] Rails Admin - undefined local variable or method javascript_importmap_shim_nonce_configuration_tag

meme code
meme code@memecode
What is technical debt in IT projects?
13 May 06:17

What is technical debt in IT projects?

meme code
meme code@memecode
13 May 07:11

What does scope mean in IT project management?

meme code
meme code@memecode
What is "scope creep"?
13 May 07:20

What is "scope creep"?

meme code
meme code@memecode
What does "Native" mean?
22 May 07:01

What does "Native" mean?

meme code
meme code@memecode
How does 'rails console --sandbox' work?
23 May 19:39

How does 'rails console --sandbox' work?

meme code
meme code@memecode