Feature #16847
closedCache instruction sequences by default
Description
Instruction sequence caching is available since Ruby 2.3, and on recent rubies it speeds up code loading by about 30%.
I just benchmarked it on Redmine's master, using bootsnap with only that optimization enabled:
if ENV['CACHE_ISEQ']
require 'bootsnap'
Bootsnap.setup(
cache_dir: 'tmp/cache',
development_mode: false,
load_path_cache: false,
autoload_paths_cache: false,
disable_trace: false,
compile_cache_iseq: true,
compile_cache_yaml: false,
)
end
$ RAILS_ENV=production time bin/rails runner 'p 1'
2.70 real 2.02 user 0.67 sys
$ RAILS_ENV=production time bin/rails runner 'p 1'
2.70 real 2.02 user 0.67 sys
$ CACHE_ISEQ=1 RAILS_ENV=production time bin/rails runner 'p 1'
1.89 real 1.27 user 0.60 sys
$ CACHE_ISEQ=1 RAILS_ENV=production time bin/rails runner 'p 1'
1.90 real 1.28 user 0.61 sys
Since Bootsnap is installed by default when you create a new Rails app, many Ruby users already benefit from it, however not all applications are Rails applications, and some users remove it because they tend to blame it as it appear on most backtrace.
Having read previous discussions about it, my understanding is that caching instruction sequences by default is only a matter of agreeing on a storage mechanism.
Python store them alongside source files as .pyc
. If I remember correctly Matz wasn't very kin on introducing .rbc
files.
The alternative would be to store them in a dedicated directory, that you could define with an environment variable (e.g. $RUBY_CACHE_PATH
), and would have a sane default. The downside here of course is permission management, especially on shared systems.
You don't want to load cache files that might have been generated by another users, potentially a malicious one.
I'm not particularly opinionated on which storage mechanism should be used, but it's disappointing that so many Ruby users pass out on this fairly significant optimization because it's opt-in.