ГоловнаВсі публікаціїКатегоріїПро проєкт

Вмикаємо YJIT у Ruby 3.2.1 (Ruby on Rails)

Обкладинка нотатки: Вмикаємо YJIT у Ruby 3.2.1 (Ruby on Rails)
Спочатку треба розібратися з тим що таке JIT, YJIT та чи воно нам треба. В цій нотатці я опишу процес оновлення ruby (бо YJIT інсталюється разом з ruby лише при використанні прапорця). Протестуємо швидкість Ruby та Ruby з YJIT.

Що таке JIT та YJIT?

JIT (Just-In-Time) компіляція в Ruby — це технологія, яка перетворює байт-код Ruby у нативний машинний код безпосередньо під час виконання програми. Використання JIT може значно підвищити продуктивність виконання програми, оскільки нативний машинний код виконується швидше, ніж інтерпретований байт-код. Ruby використовує віртуальну машину YARV (Yet Another Ruby VM), яка трансформує написаний код Ruby у байт-код перед його виконанням. Додавання JIT до цього процесу дозволяє динамічно компілювати деякі частини коду на льоту, що пришвидшує роботу коду та зменшує навантаження на сервер.
YJIT - це новий JIT компілятор, який вже вбудований в Ruby починаючи з версії 3.1. YJIT використовує так звану "ліниву" JIT-компіляцію, де компіляція виконується лише для "гарячих" шляхів виконання, які виконуються часто. Це знижує витрати на компіляцію коду, який виконується рідко, та забезпечує приріст продуктивності там, де це найбільш необхідно.
YJIT підвищує швидкість виконання програм без потреби в істотних змінах в самому коді. YJIT став результатом спроби оптимізувати роботу Ruby за допомогою JIT-компіляції, зберігаючи при цьому стабільність і сумісність з існуючими програмами.

Перевіряємо чи ввімкнен YJIT

Мій локальний сетап - macOS, rbenv та brew. Локально перевіряємо версію ruby та чи ввімкнутий YJIT:
Термінал:
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?                                     
      ^^^^^^
Тобто, наразі Ruby немає YJIT.

Заміряємо швидкість виконання Ruby без YJIT

Зробимо скрипт, який буде рахувати послідовність Фібоначчі. Я трохи погуглив і попитав ChatGPT, як краще зробити простий бенчмаркінг і це найпоширеніший варіант.
Створюємо файл benchmark.rb з кодом:
require 'benchmark'

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

puts Benchmark.measure {
  fibonacci(40)
}
Запускаємо:
ruby ~/Desktop/benchmark.rb
І мій результат наразі (без YJIT):
 8.309469   0.000711  8.310180 (8.320920)

Встановлюємо Ruby з YJIT

Наразі я маю ruby 3.2.1 (rbenv). Мені треба встановити цю саму версію, але вже з YJIT. Тож почнемо.
Дисклеймер:
Кожен має свій сетап. Наведений приклад - лише мій кейс.
Офіційна документація каже, що YJIT потребує:
  • 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.
З цього всього я маю лише встановити Rust (Прикольно, так. Мова програмування Rust використовуються в якості компілятора).
Встановлюємо Rust за допомогою brew:
brew install rust
На це може піти доволі багато часу (~10хв).
В .zshrc треба додати наступний прапорець:
export RUBY_CONFIGURE_OPTS="--enable-yjit"
Без прапорцю Ruby буде встановлено без YJIT (за замовчуванням він вимкненний). Це важливий момент.
Перезапускаємо термінал, щоб він підтягнув RUBY_CONFIGURE_OPTS
Встановлюємо Ruby (технічно, rbenv install 3.2.1 буде виконуватись з прапорцем --enable-yjit):
\W $ rbenv install 3.2.1
rbenv: /Users/user/.rbenv/versions/3.2.1 already exists
continue with installation? (y/N) y
Після встановлення перевіряємо чи працює YJIT та  бенчмарки виконання файлу benchmark.rb.
Тут є нюанс. YJIT навіть якщо встановленно разом з Ruby - вимкненний.
Додайте цей прапорець, щоб ruby запускався з YJIT:
export RUBY_YJIT_ENABLE=true
Потім ми маємо побачити +YJIT при перевірці ruby -v
ruby -v
ruby 3.2.1 (2023-02-08 revision 31819e82c8) +YJIT [x86_64-darwin23]
irb
RubyVM::YJIT.enabled?
=> true

YJIT працює. Далі тестуємо.

ruby ~/Desktop/benchmark.rb
І отримуємо:
1.624351 0.000245 1.624596 (1.626251)
Тобто різниця в швидкості виконання скрипту 5,11 разів:
8.309469/1.624351=5,1155624616
Технічно, це доволі великий та значний апгрейд в швидкості Ruby. Ввімкнув лише одну опцію, на рівні компіляції ми отримуємо дуже потужну оптимізацію. YJIT вже production-ready й може застосовуватись на продакшн серверах, наприклад для Ruby on Rails додатків. Наприклад heroku пропонує включити YJIT лише за допомогою однієї команди:
heroku config:set RUBYOPT="--enable-yjit"
27.04.2024 09:29

Що таке CC та BCC в емейлах? Для чого та як використовувати?

meme code
meme code@memecode
Що таке промпт (prompt) та промпт-інжинірінг?
03.05.2024 12:08

Що таке промпт (prompt) та промпт-інжинірінг?

meme code
meme code@memecode
ZOMBIE в Ruby. Що це таке?
03.05.2024 12:41

ZOMBIE в Ruby. Що це таке?

meme code
meme code@memecode
03.05.2024 13:13

Що таке Garbage Collector у Ruby? Як працює та для чого потрібен GC?

meme code
meme code@memecode
Трохи про типи реалізації Ruby (CRuby (MRI), JRuby, Rubinius, TruffleRuby, mruby)
05.05.2024 12:36

Трохи про типи реалізації Ruby (CRuby (MRI), JRuby, Rubinius, TruffleRuby, mruby)

meme code
meme code@memecode
07.05.2024 07:24

Що таке нативний машинний код?

meme code
meme code@memecode
09.05.2024 12:43

[Фікс] Rails Admin - undefined local variable or method javascript_importmap_shim_nonce_configuration_tag

meme code
meme code@memecode
Що таке технічний борг (technical debt) в IT проєктах?
13.05.2024 06:17

Що таке технічний борг (technical debt) в IT проєктах?

meme code
meme code@memecode
13.05.2024 07:11

Що означає скоуп (scope) в управлінні IT-проєктами?

meme code
meme code@memecode
Що таке "розповзання скоупу" (Scope Creep / Скоуп кріп)?
13.05.2024 07:20

Що таке "розповзання скоупу" (Scope Creep / Скоуп кріп)?

meme code
meme code@memecode
Що означає "Нативний"?
22.05.2024 07:01

Що означає "Нативний"?

meme code
meme code@memecode
Як працює 'rails console --sandbox'?
23.05.2024 19:39

Як працює 'rails console --sandbox'?

meme code
meme code@memecode