Feature #21951
closedLazy load error extension gems to speed up boot time
Description
Summary¶
I investigate https://github.com/ruby/rubygems/issues/3799 for speed up Ruby's boot time. It depends on the environment, but when gems are included in GEM_HOME and user installation. I and Claude found that the most time-consuming part is requiring the three gems related to error notification, rather than loading the gemspec of default gems.
How it works¶
Defer loading of error_highlight, did_you_mean, and syntax_suggest from boot time to first error display. These gems only enhance Exception#detailed_message, so they are not needed until an error is actually displayed.
Performance¶
ruby -e1 boot time on Apple M1 Pro:
| Configuration | With user gems | Default gems only |
|---|---|---|
| master | 114.3 ms | 38.3 ms |
| This patch | 30.2 ms | 30.4 ms |
--disable-did_you_mean --disable-error_highlight --disable-syntax_suggest |
30.3 ms | 30.6 ms |
With this patch, ruby -e1 is as fast as disabling all three gems via flags. The error path has no measurable regression (+0.9 ms, within noise).
Patch¶
Updated by hsbt (Hiroshi SHIBATA) 5 months ago
- Tracker changed from Bug to Feature
- Backport deleted (
3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN)
Updated by hsbt (Hiroshi SHIBATA) 4 months ago
- Subject changed from Lazy load error enhancer gems to speed up boot time to Lazy load error extension gems to speed up boot time
Updated by hsbt (Hiroshi SHIBATA) 4 months ago
Some libraries implicitly depend on did_you_mean and other gems being loaded at boot, calling their class methods (e.g., DidYouMean::SpellChecker) without an explicit require.
I tried to switch from a simple deferred require approach to using autoload. Unfortunately, when using autoload for lazy loading of them, some Ractor btests is failed with YJIT/ZJIT.
- https://github.com/ruby/ruby/actions/runs/23230199826/job/67521873278?pr=16371
- https://github.com/ruby/ruby/actions/runs/23230199813/job/67521873227?pr=16371
Does anyone know that causes?
Updated by hsbt (Hiroshi SHIBATA) 27 days ago
- Status changed from Open to Assigned
I update the original pull-request with C code.
https://github.com/ruby/ruby/pull/16371
Now, we don't need to add extra workaround to gem_prelude.rb.
Updated by matz (Yukihiro Matsumoto) 17 days ago
Accepted. A 3.8x boot time improvement with no regression on the error path is a clear win. Implementation details are up to you.
Matz.
Updated by hsbt (Hiroshi SHIBATA) 5 days ago
- Status changed from Assigned to Closed
Applied in changeset git|cadf8e7933be1164993531e413a1f1cfd0c84554.
Lazy load error_highlight, did_you_mean, and syntax_suggest
[Feature #21951]
Defer loading these gems from boot to the first error display. They
only decorate Exception#detailed_message, so requiring them at boot is
unnecessary overhead. ruby -e1 with user-installed gems drops from
114.3ms to 30.2ms on Apple M1 Pro, matching the --disable-* flags for
the three gems.
exc_detailed_message forces the autoload entries once on the first
call, only in the main Ractor, and then re-dispatches to pick up the
detailed_message decorators the gems prepend. When the first call
arrives through an already-prepended decorator, re-dispatching is
skipped to avoid decorating twice. The gems are loaded with the
C-level require so that displaying an error neither invokes nor
depends on Kernel#require monkeypatches.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com