We're using Rails as API and web frontend with a pretty high number of requests per second, so I was hoping we'd see something. Does anyone have any experience rolling it out?
We're using Rails as API and web frontend with a pretty high number of requests per second, so I was hoping we'd see something. Does anyone have any experience rolling it out?
Does anyone have any experience rolling it out?
FWIW, the linked article has prod benchmarks. I'm pretty sure (there isn't a lot of info on how
to enable it in production workloads) we're running
YJIT in production
Sure you're running it? You have to compile with YJIT support, and then pass the command line arg. (It doesn't support YJIT out of the box because, I presume, they didn't want to force a Rust dependency on everybody?)Here's how on MacOS + asdf, others will be similar. Note that I think --enable-yjit might work (but do nothing) even if you don't have support compiled in.
# if you already installed 3.2.0
asdf uninstall ruby 3.2.0
# install Rust
asdf plugin-add rust
asdf...
# now install Ruby 3.2
asdf plugin-update ruby
export RUBY_CONFIGURE_OPTS=--enable-yjit
asdf install ruby 3.2.0
asdf global ruby 3.2.0
# verify it's installed and ready
ruby --enable-yjit --version
# now run your workload
ruby --enable-yjit foo.rb1. Compiled with jyjit confrmed (ruby --yjit) returns the correct value
2. RubyVM::YJIT.enabled? returned true
But the information available on how to confirm YJIT is running is not super clear. Since I didn't notice any improvements I started wondering.
Since I didn't notice any improvements I started wondering.
It only speeds up Ruby itself. In a "real world" web app performance, performance is mostly dominated by Ruby/PHP/Java/whatever sitting around and waiting for database queries to execute.So for a lot of web workloads the perf increase won't be huge. If your average endpoint is e.g. 5ms of Ruby and 500ms of DB queries, your max speedup will be negligible if you switch to YJIT... or even if you rewrite the whole app in hand-optimized assembler.
(Also gets to the root of why perf-based criticism of Ruby is usually dumb, IMHO. It's usually not the problem)
The best way to know it to enable YJIT runtime statistics [0] to see whether YJIT is doing a lot of side exits and if so why. But it requires a bit of YJIT knowledge to interpret them.
It's also entirely possible that your application isn't CPU bound in the first place, or that it's bottlenecked by things YJIT can't do anything about (e.g. GVL).
That's close to impossible to guess what it might be without being able to instrument the application.
[0] https://github.com/ruby/ruby/blob/df6b72b8ff7af16a56fa48f3b4...
The YJIT is not on by default in ruby 3.2, you have to specifically enable it. If you aren't sure if you have enabled it... what makes you pretty sure you have enabled it? It seems possible you have not enabled it, if you aren't confident you know how to do so?
I am not using it yet myself, and don't want to put any possibly incorrect info here about how to enable it. I agree that it's not clear to me where to find this documented. I am pretty sure it is not on by default.
passenger_env_var RUBY_YJIT_ENABLE 1;
> For Rails you'd want to just edit the executable Rails scripts like `bin/rails` to include that flag.
Alternately, you can edit your shell init scripts to put the correct thing in `RUBY_OPTS` ENV variable, yes?
I would consider this preferable to editing executable rails scripts with implementation-specific stuff (and then hoping that the app is always launched with those edited shell scripts, which I'm not sure eg `bundle exec rails` will do). I don't think editing Rails scripts is probably the "right" or recommended way to do this.
But I'm not going to try to specify what you put in `RUBY_OPTS` since i haven't done it myself and don't want to spread misinformation! (Again, is this documented in a centralized trustworthy place? As I try to google it... I am somewhat frustrated with the ruby documentation situation!)
The performance impact of enabling yjit was quite obvious in our charts. Another giveaway that it's properly enabled is the servers will use consume more memory.
GitHub issue link here: https://github.com/docker-library/ruby/pull/398
$ podman run -it -e RUBYOPT="--yjit" ruby:3.2
irb(main):001:0> puts RUBY_DESCRIPTION
ruby 3.2.0 (2022-12-25 revision a528908271) +YJIT [aarch64-linux]
=> nilInitially when 3.2 was released Debian based images didn't support it because Bullseye ships with a version of rustc that's too old to compile YJIT.
But https://github.com/docker-library/ruby/commit/6db728e addressed this a few days ago by installing a pre-compiled version of rustc straight from Rust and YJIT is available in Debian now.
You can confirm if it's available to use by running:
$ docker container run --rm ruby:3.2.0-slim-bullseye ruby --enable-yjit -v
ruby 3.2.0 (2022-12-25 revision a528908271) +YJIT [x86_64-linux]
If it weren't available then you would get an unknown argument error. $ docker container run --rm ruby:3.2.0-slim-bullseye ruby --enable-yjit -v
ruby 3.2.0 (2022-12-25 revision a528908271) +YJIT [aarch64-linux]
Runs on Arm as well!1. Compiled with jyjit confrmed (ruby --yjit) returns the correct value
2. RubyVM::YJIT.enabled? returned true
I didn't notice any improvements at basically so I can't really say _for sure_ if it was working as intended.