Skip to content

RBS scan cache to improve overall performance - #1796

Draft
skatkov wants to merge 7 commits into
ruby:masterfrom
skatkov:perf/rbs-member-lookups
Draft

RBS scan cache to improve overall performance#1796
skatkov wants to merge 7 commits into
ruby:masterfrom
skatkov:perf/rbs-member-lookups

Conversation

@skatkov

@skatkov skatkov commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

RBS parsing repeatedly searched growing method and attribute arrays, making classes with many declarations quadratic. This replaces those searches with parser-local Hash indexes while leaving the ordered code-object collections unchanged.

The indexes are initialized from existing context members and updated when methods, attributes, or aliases are added. This preserves behavior for rebuilt stores, forward aliases, and legacy instance methods with a nil singleton value.

Five measured runs with 2,000 declarations per workload:

Parser-only workload Baseline Optimized Speedup
RBS methods 0.1610s 0.0353s 4.6x
RBS attributes 0.1108s 0.0253s 4.4x
End-to-end workload Baseline Optimized Change
RBS methods 0.722s 0.587s -18.7%
RBS attributes 0.630s 0.569s -9.8%

Benchmark
https://gist.github.com/skatkov/82f89eaf2269286a42a4adf966d2fd12

@skatkov
skatkov requested a deployment to fork-preview-protection August 29, 2026 15:02 — with GitHub Actions Waiting
@skatkov
skatkov marked this pull request as ready for review August 29, 2026 15:43
Copilot AI balanced review requested due to automatic review settings August 29, 2026 15:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Context#add_alias can append methods or attributes as a side effect, making
mutation-side cache updates depend on Context internals. Index each
collection's unconsumed tail during lookup instead, keeping synchronization
in one place while preserving linear lookup.
Copilot AI review requested due to automatic review settings August 30, 2026 12:21
@skatkov
skatkov requested a deployment to fork-preview-protection August 30, 2026 12:21 — with GitHub Actions Waiting

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 30, 2026 12:44
@skatkov
skatkov requested a deployment to fork-preview-protection August 30, 2026 12:44 — with GitHub Actions Waiting

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 30, 2026 12:54
@skatkov
skatkov requested a deployment to fork-preview-protection August 30, 2026 12:54 — with GitHub Actions Waiting

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 30, 2026 14:17
@skatkov
skatkov requested a deployment to fork-preview-protection August 30, 2026 14:17 — with GitHub Actions Waiting

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@tompng

tompng commented Aug 30, 2026

Copy link
Copy Markdown
Member

I agree that the quadratic cost should be fixed. However, it also happens in the normal RDoc parse path, not just RBS.

It would be simpler to implement the cache in Context itself rather than in each parser. Making context.find_method faster fixes all of them at once, and the parser-side change in this PR reduces to a few lines.

Context already has a hash-based lookup: @methods_hash. It could not be used for find_method as-is because @method_list and @methods_hash could disagree — the main source was the #initialize → ::new rename performed after add_method, which left the hash keyed by the old name. I've just opened #1802 to remove that. Once it is merged, a parse-time lookup can read @methods_hash directly.

Concretely, we could add internal methods like context.find_method_from_hash / context.find_attribute_from_hash, marked # :nodoc:. Two things to keep in mind:

  • @methods_hash also holds attributes (for redefinition checks), so the method finder needs an RDoc::Attr check.
  • The remaining list/hash divergences (e.g. remove_invisible only removes from @method_list) happen after parsing, so they don't affect parse-time lookups like this PR's, but they are why the public find_method can't simply switch to the hash yet. Longer term, @method_list and @methods_hash should be unified into a single source of truth (same for @constants and @constants_hash), and these internal methods can be removed at that point.

@skatkov
skatkov marked this pull request as draft August 30, 2026 19:12
@skatkov

skatkov commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

I will revisit this PR once #1802 will be merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants