Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend declare_lint_pass! macro #228

Merged
merged 7 commits into from
Jan 17, 2025
Merged

Extend declare_lint_pass! macro #228

merged 7 commits into from
Jan 17, 2025

Conversation

BD103
Copy link
Member

@BD103 BD103 commented Jan 14, 2025

Often lints need to compare Symbols. Some lints take the inefficient route by interning the string each time:

if ident.name == Symbol::intern("component") {
    // ...
}

// Also seen as...
if ident.name == sym!(component) {
    // ...
}

This is bad because interning a string is quite expensive. To avoid this, lint passes cache the Symbol:

struct MyLintPass {
    component_sym: Symbol,
}

impl Default for MyLintPass {
    fn default() -> Self {
        Self { component_sym: Symbol::intern("component") }
    }
}

impl<'tcx> LateLintPass<'tcx> for MyLintPass {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
        // ...

        if ident.name == self.component_sym {
            // ...
        }
    }
}

This requires a lot of boilerplate. To shorten this, this PR introduces a custom declare_bevy_lint_pass! macro that supports cached values:

declare_bevy_lint_pass! {
    MyLintPass => [MY_LINT.lint],
    @default = {
        component: Symbol = sym!("component"),
    },
}

Eventually this macro will be used to declare custom lint config, but for now it just supports default values. I've migrated all existing lints to use declare_bevy_lint_pass!.

@BD103 BD103 added A-Linter Related to the linter and custom lints C-Usability An improvement that makes the API more pleasant labels Jan 14, 2025
Copy link
Collaborator

@TimJentzsch TimJentzsch left a comment

Choose a reason for hiding this comment

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

In general looks good to me, although I'm still bad with the macro syntax, so can't say much about that (seriously, probably one of the worst looking parts of Rust, IMO).

I'm curious: Do you have any benchmarks (even if it's just a simple timing of running the linter on some random repo) by how much this improves the performance?

bevy_lint/src/lint.rs Outdated Show resolved Hide resolved
"excluded" -> "omitted"

Co-authored-by: TimJentzsch <[email protected]>
@DaAlbrecht
Copy link
Contributor

Looks really good, makes defining lints so much easier!!

@BD103
Copy link
Member Author

BD103 commented Jan 17, 2025

I'm curious: Do you have any benchmarks (even if it's just a simple timing of running the linter on some random repo) by how much this improves the performance?

For the Symbol::intern() optimization, it avoids1:

  1. Locking a thread-local
  2. Looking up the symbol string in a hash set
  3. Allocating space for the symbol (which may re-allocate the arena if it's out of room)

Instead, it's a simple u32 == u32 comparison, which should be much faster. I don't have exact benchmarks, since I ran into some issues running criterion in #![feature(rustc_private)] mode, but I may be able to get them working if you want them.

I don't think caching symbols will have visible performance effects on the linter right now, but they may add up if we have as many lints as Clippy does.


On another note, we don't have benchmarks tracking the time of the entire linter being run on a project. I would like to setup something like that eventually, so we can track the performance of individual lints.

Footnotes

  1. See Symbol::intern(), Interner, and Interner::intern()

Copy link
Collaborator

@TimJentzsch TimJentzsch left a comment

Choose a reason for hiding this comment

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

Thanks, then it's fine for me now.

Let's create a follow-up issue to set up some basic way to compare performance, even if it's only logging the time instead of comprehensive benchmarking like with criterion

@BD103 BD103 enabled auto-merge (squash) January 17, 2025 23:14
@BD103 BD103 merged commit 12635b7 into main Jan 17, 2025
8 checks passed
@BD103 BD103 deleted the lint-pass-default branch January 17, 2025 23:18
DaAlbrecht added a commit to DaAlbrecht/bevy_cli that referenced this pull request Jan 19, 2025
DaAlbrecht added a commit to DaAlbrecht/bevy_cli that referenced this pull request Jan 21, 2025
DaAlbrecht added a commit to DaAlbrecht/bevy_cli that referenced this pull request Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Linter Related to the linter and custom lints C-Usability An improvement that makes the API more pleasant
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants