Project

General

Profile

Actions

Feature #21951

closed

Lazy load error extension gems to speed up boot time

Feature #21951: Lazy load error extension gems to speed up boot time
1

Added by hsbt (Hiroshi SHIBATA) 5 months ago. Updated 5 days ago.

Status:
Closed
Target version:
-
[ruby-core:124984]

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

https://github.com/ruby/ruby/pull/16371

Updated by hsbt (Hiroshi SHIBATA) 5 months ago Actions #1

  • 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 Actions #2

  • 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 Actions #3 [ruby-core:125065]

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.

Does anyone know that causes?

Updated by hsbt (Hiroshi SHIBATA) 27 days ago Actions #4 [ruby-core:125870]

  • 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 Actions #5 [ruby-core:126025]

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 Actions #6

  • 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

Actions

Also available in: PDF Atom