perf: fold all early lint passes into one statically-combined pass#17132
Conversation
3eeec14 to
6884673
Compare
|
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @llogiq (or someone else) some time within the next two weeks. Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
6884673 to
666e75b
Compare
Resolved |
Clippy registers about 50 early passes, each as its own boxed `dyn EarlyLintPass`. Every `check_*` call is an indirect (vtable) dispatch, even for the many passes that don't override that method and just run the empty default. Walking the AST multiplies this across every node. Fold all early passes into a single statically-combined struct: one concrete field per pass, with a single `EarlyLintPass` impl that forwards each `check_*` to every field in turn. Because the field types are concrete and the calls are `#[inline(always)]`, passes that don't override a method contribute a DCE'd empty body and the ones that do become direct, inlined calls. No vtable and no per-node dynamic dispatch. changelog: none
666e75b to
d5c0121
Compare
|
r? blyxyas |
|
|
Clippy registers about 50 early passes, each as its own boxed
dyn EarlyLintPass. Everycheck_*call is an indirect (vtable) dispatch, even for the many passes that don't override that method and just run the empty default. Walking the AST multiplies this across every node.This folds all early passes into a single statically-combined struct: one concrete field per pass, with a single
EarlyLintPassimpl that forwards eachcheck_*to every field in turn. Because the field types are concrete and the calls are#[inline(always)], passes that don't override a method contribute a DCE'd empty body and the ones that do become direct, inlined calls. No vtable and no per-node dynamic dispatch.This mirrors the late-pass combine from #17124, but with no
Gatedactive flag. rustc drops fully-disabled late passes vialints_that_dont_need_to_run, but the early pass runner has no such filtering. TheEarlyLintPassimpl is generated from rustc'searly_lint_methods!list so the two cannot drift.cargo dev new_lintnow emits a combined-struct field for new early passes at the in-list marker.Measured the same way as #17124 (valgrind callgrind, release build, this branch against its parent, re-linting the ripgrep 14.1.0 workspace): clippy-driver instructions drop about 3.9%, from 1317445596 to 1266296487. The improvement is smaller than the late-pass combine because there are far fewer early passes and the AST walk is lighter than the HIR walk. The UI test suite and dogfood pass unchanged.
changelog: none