Skip to content

perf: cache the most recent MSRV attribute scan - #17139

Closed
xmakro wants to merge 2 commits into
rust-lang:masterfrom
xmakro:perf/msrv-attr-memo
Closed

perf: cache the most recent MSRV attribute scan#17139
xmakro wants to merge 2 commits into
rust-lang:masterfrom
xmakro:perf/msrv-attr-memo

Conversation

@xmakro

@xmakro xmakro commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #17138 (skip MSRV attribute parsing for nodes without attributes). This PR is stacked on it, so the first commit is shared; if #17138 lands first, rebasing leaves only the cache commit here.

The five early MsrvStack passes are registered separately, so for each AST node the same attribute slice is scanned once per pass on both enter and exit. Those calls arrive back to back with the same slice. This adds a single-slot thread-local cache, keyed on the slice's pointer and length, so the repeated scans of one node collapse to a single parse. Only the early AST path goes through the cache, so it never mixes ast and hir attributes.

Lint output is unchanged.

Measurements

callgrind Ir (sum of clippy-driver Ir over a workspace re-lint), master vs the fast path alone (#17138) vs this PR, back to back in one session:

crate master #17138 only + cache (this PR)
wasmi 12,182,497,351 -0.09% -0.12%
syn 2,069,987,997 -0.25% -0.34%
regex 808,301,202 +0.06% -0.04%
serde 3,165,571,048 -0.25% -0.24%
ripgrep 1,273,725,148 -0.31% -0.28%

On top of the fast path the cache is roughly break-even: it helps wasmi, syn and regex a little and costs serde and ripgrep about as much, all within noise. I'm opening it for completeness on top of #17138, but it may not be worth the extra complexity over the fast path alone.

Diagnostics are byte-identical against master on serde, wasmi, ripgrep, regex, syn and tokio.

Benchmarked against master at 2b4f8f5; re-measure if #17132 (combine early lint passes) lands first.

changelog: none

xmakro added 2 commits June 1, 2026 14:54
The early `MsrvStack` passes scan every node's attributes for `#[clippy::msrv]`
on both enter and exit, but most nodes carry none. Returning early when the
attribute slice is empty avoids building the filter iterator in that common case.

changelog: none
The early `MsrvStack` passes are registered separately, so each node's
attribute slice is scanned once per pass on both enter and exit. Those calls
arrive back to back with the same slice, so a single-slot cache keyed on the
slice pointer collapses them to one scan.

changelog: none
@samueltardieu samueltardieu added the G-performance-project Goal: For issues and PRs related to the Clippy Performance Project label Jun 2, 2026
@xmakro xmakro closed this Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

G-performance-project Goal: For issues and PRs related to the Clippy Performance Project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants