Table of contents
How to customize YJIT in the Rails app
Software Engineer
Software Engineer
Ruby on Rails
Ruby on Rails
In this post, we'll dive into what YJIT is, how to enable it in your Rails app, and how to monitor and configure it for optimal performance.
What is YJIT?
YJIT is a lightweight Just-In-Time (JIT) compiler introduced in Ruby to speed up method execution by compiling Ruby code into machine code on the fly. This approach can significantly boost performance for Ruby applications, including those built with Rails.
YJIT may not be suitable for certain applications. It currently only supports macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs. YJIT will use more memory than the Ruby interpreter because the JIT compiler needs to generate machine code in memory and maintain additional state information.
That's why we have to customize it to take advantage of the speed and avoid memory overflow.
YJIT may not be suitable for certain applications. It currently only supports macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs. YJIT will use more memory than the Ruby interpreter because the JIT compiler needs to generate machine code in memory and maintain additional state information.
That's why we have to customize it to take advantage of the speed and avoid memory overflow.
Enabling YJIT in Your Rails Application
To leverage YJIT in your Rails app, follow these steps:
1. Install Ruby 3.3.x: Ensure you're running Ruby 3.3.x or later, as YJIT's performance improvements are most effective than 3.2
Make sure you install Rust because Ruby requires it to compile YJIT.
2. Enable YJIT: You can enable YJIT by setting an environment variable or using command-line options:
1. Install Ruby 3.3.x: Ensure you're running Ruby 3.3.x or later, as YJIT's performance improvements are most effective than 3.2
Make sure you install Rust because Ruby requires it to compile YJIT.
2. Enable YJIT: You can enable YJIT by setting an environment variable or using command-line options:
// language: bash RUBY_YJIT_ENABLE=1
Or start your Rails server with:
// language: bash RUBYOPT="--yjit" rails s
Enable YJIT at Runtime: For better boot performance, you can disable YJIT at startup and enable it later in your application:
// language: ruby RubyVM::YJIT.enable
From Rails 7.2 with Ruby 3.3+, YJIT is enabled by default. This approach prevents YJIT from compiling initialization code, which typically doesn't benefit from JIT compilation.
Monitoring YJIT's Performance
To gain insights into YJIT's performance in your Rails app, integrate a custom middleware to log runtime statistics. Here's a sample logger you can use:
// language: ruby class YJITLogger def initialize(app) @app = app end def call(env) # Sample approximately 5% of requests if rand < 0.05 && defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? stats = RubyVM::YJIT.runtime_stats Rails.logger.info "YJIT - code region size: #{stats[:code_region_size]}" Rails.logger.info "YJIT - ratio in YJIT: #{stats[:ratio_in_yjit]}" end @app.call(env) end end Rails.application.config.middleware.use YJITLogger
This middleware logs key YJIT statistics, such as the size of the code region used by JIT-compiled code and the ratio of instructions executed by YJIT versus the Ruby interpreter.
Configuring YJIT for Better Performance
YJIT comes with several configuration options that can affect its performance. Here are some tips to optimize YJIT for your Rails app:
1. Adjust Executable Memory Size: The default memory size for YJIT is 48 MiB (you can read more in this
document), but increasing it can improve performance. For instance, setting it to 64 - 96 MiB might benefit applications with larger codebases:
1. Adjust Executable Memory Size: The default memory size for YJIT is 48 MiB (you can read more in this
document), but increasing it can improve performance. For instance, setting it to 64 - 96 MiB might benefit applications with larger codebases:
// language: bash RUBYOPT="--yjit-exec-mem-size=64"
Use the RubyVM::YJIT.runtime_stats[:code_region_size] metric to ensure your code region size stays below this limit.
2. Monitor Ratio in YJIT: Aim for a high ratio_in_yjit value, ideally above 98%, indicating that most of your code is being executed by YJIT.
3. Use jemalloc for Memory Management: jemalloc is a memory allocator that can improve memory usage patterns and reduce fragmentation in Ruby applications. It's often used in production environments to enhance performance and stability. By using jemalloc, you can help your application run with higher --yjit-exec-mem-size setting
2. Monitor Ratio in YJIT: Aim for a high ratio_in_yjit value, ideally above 98%, indicating that most of your code is being executed by YJIT.
3. Use jemalloc for Memory Management: jemalloc is a memory allocator that can improve memory usage patterns and reduce fragmentation in Ruby applications. It's often used in production environments to enhance performance and stability. By using jemalloc, you can help your application run with higher --yjit-exec-mem-size setting
Conclusion
By enabling and configuring YJIT, you can achieve substantial performance improvements in your Rails application. DON'T FORGET to monitor key metrics (response time, memory, ...) and adjust configurations. There is not one fit solution for all projects.
References:
References:
Created at
2024-12-04 16:29:15 +0700
Related blogs
How Google achieves seamless SSO across multiple domains like Gmail and Youtube?
Hey there! Ever wondered how you can log into Gmail and then magically find yourself logged into YouTube, Google Drive, and all other Google services ...
Software Engineer
Software Engineer
2024-09-24 22:52:06 +0700
One Design Pattern a Week: Week 4
Welcome back to my "One Design Pattern a Week" series!Try to solve this real problem: Request HandlingImagine you're building an enterprise applicatio...
Software Engineer
Software Engineer
2024-10-28 16:46:15 +0700