Skip to content

Conversation

@camchenry
Copy link
Member

@camchenry camchenry commented Jul 11, 2025

Copy link
Member Author

camchenry commented Jul 11, 2025

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions github-actions bot added the C-performance Category - Solution not expected to change functional behavior, only performance label Jul 11, 2025
@codspeed-hq
Copy link

codspeed-hq bot commented Jul 11, 2025

CodSpeed Instrumentation Performance Report

Merging #12228 will not alter performance

Comparing 07-11-perf_linter_add_should_run_based_on_node_types_batch_1_ (f353586) with 07-11-feat_semantic_add_methods_to_check_if_ast_contains_any_all_node_types (cd7d601)

Summary

✅ 34 untouched benchmarks

@camchenry
Copy link
Member Author

+2% perf improvement on the radix UI benchmark:

Screenshot 2025-07-11 at 12 17 58 PM

@camchenry camchenry force-pushed the 07-11-feat_semantic_add_methods_to_check_if_ast_contains_any_all_node_types branch from 09291b4 to cd7d601 Compare July 11, 2025 16:29
@camchenry camchenry marked this pull request as ready for review July 11, 2025 16:29
@camchenry camchenry force-pushed the 07-11-perf_linter_add_should_run_based_on_node_types_batch_1_ branch from 3b85248 to f353586 Compare July 11, 2025 16:50
@camchenry camchenry force-pushed the 07-11-feat_semantic_add_methods_to_check_if_ast_contains_any_all_node_types branch from cd7d601 to 1449a81 Compare July 11, 2025 17:20
Comment on lines +114 to +120
fn should_run(&self, ctx: &crate::context::ContextHost) -> bool {
ctx.semantic().nodes().contains(oxc_ast::AstType::BinaryExpression)
&& ctx
.semantic()
.nodes()
.contains_any(&[oxc_ast::AstType::NumericLiteral, oxc_ast::AstType::BigIntLiteral])
}
Copy link
Member

@overlookmotel overlookmotel Jul 11, 2025

Choose a reason for hiding this comment

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

From benchmarks, obviously some of these changes are having a positive effect.

But some of these methods may be of limited value. How many ASTs don't contain a single BinaryExpression and not a single NumericLiteral?

I imagine most of the gain is from rarer types e.g. AstType::Class and AstType::DebuggerStatement.

You may want to "pick your fights".

@camchenry camchenry closed this Jul 13, 2025
@camchenry camchenry deleted the 07-11-perf_linter_add_should_run_based_on_node_types_batch_1_ branch August 17, 2025 02:50
graphite-app bot pushed a commit that referenced this pull request Sep 8, 2025
…3138)

- part of #12223
- supersedes stack: #12228

This PR adds the ability to add node type information to indicate what node types a lint rule acts on. The lint rule runner can use this information to optimize running lint rules by skipping nodes, files, or rules that don't apply.

This is a simple version that is focused on creating the framework for automatically generating the rule runner code. This is not the end of optimizations. Currently only 102 rules have node type information, while 471 rules have no node type information and will not be skipped. Adding node type information for more rules will improve performance. We may also be able to skip more nodes and files by being clever about how we use this information. For example, filtering out any rules which do not run on any node type, if the file contains no relevant node types for the rule.

- Adds a new `RuleRunner` trait which includes information needed for indicating whether a rule has node type info or not
- Adds a `oxc_linter_codegen` task which is used to generate the implementation of `RuleRunner` trait for all lint rules. This is mostly written by AI, so worth a bit of skepticism, but I've tried to manually verify the results and it looks good (just lacking more complex detection).
  - Currently, only rules that contain a single top-level `if` statement (or chain of `else if`), or a single `match` statement will have their node type info generated. This should give us a high level of confidence, since these patterns are relatively easy to verify and identify, but it's only a subset of all rules. Next steps will be to add support for `let...else`
- Adjusts the main linting loop to use the node type information to skip rules for node types that don't apply
- Updates CI to include a check for any uncommitted linter codegen changes

---

## Benchmarks

In the latest version of this PR, CodSpeed shows an up to +13% increase in linter performance across large and small files. In the real-world, I've seen a ~5-15% improvement in performance, but in some cases close to zero for very small files. In either case, there appears to be little downside and a lot of potential upside here.

<img width="769" height="242" alt="Screenshot 2025-08-24 at 9 29 30 PM" src="https://github.com/user-attachments/assets/d2c430c4-17a9-4606-85d5-c66c734975d9" />
<img width="757" height="308" alt="Screenshot 2025-08-24 at 9 30 24 PM" src="https://github.com/user-attachments/assets/5508464f-de55-4f4e-9ddd-58f215c4ce85" />
<img width="976" height="368" alt="Screenshot 2025-08-24 at 9 34 52 PM" src="https://github.com/user-attachments/assets/203f83c7-46f3-49f1-a1a8-e18f7ec8483b" />
graphite-app bot pushed a commit that referenced this pull request Sep 8, 2025
…3138)

- part of #12223
- supersedes stack: #12228

This PR adds the ability to add node type information to indicate what node types a lint rule acts on. The lint rule runner can use this information to optimize running lint rules by skipping nodes, files, or rules that don't apply.

This is a simple version that is focused on creating the framework for automatically generating the rule runner code. This is not the end of optimizations. Currently only 102 rules have node type information, while 471 rules have no node type information and will not be skipped. Adding node type information for more rules will improve performance. We may also be able to skip more nodes and files by being clever about how we use this information. For example, filtering out any rules which do not run on any node type, if the file contains no relevant node types for the rule.

- Adds a new `RuleRunner` trait which includes information needed for indicating whether a rule has node type info or not
- Adds a `oxc_linter_codegen` task which is used to generate the implementation of `RuleRunner` trait for all lint rules. This is mostly written by AI, so worth a bit of skepticism, but I've tried to manually verify the results and it looks good (just lacking more complex detection).
  - Currently, only rules that contain a single top-level `if` statement (or chain of `else if`), or a single `match` statement will have their node type info generated. This should give us a high level of confidence, since these patterns are relatively easy to verify and identify, but it's only a subset of all rules. Next steps will be to add support for `let...else`
- Adjusts the main linting loop to use the node type information to skip rules for node types that don't apply
- Updates CI to include a check for any uncommitted linter codegen changes

---

## Benchmarks

In the latest version of this PR, CodSpeed shows an up to +13% increase in linter performance across large and small files. In the real-world, I've seen a ~5-15% improvement in performance, but in some cases close to zero for very small files. In either case, there appears to be little downside and a lot of potential upside here.

<img width="769" height="242" alt="Screenshot 2025-08-24 at 9 29 30 PM" src="https://github.com/user-attachments/assets/d2c430c4-17a9-4606-85d5-c66c734975d9" />
<img width="757" height="308" alt="Screenshot 2025-08-24 at 9 30 24 PM" src="https://github.com/user-attachments/assets/5508464f-de55-4f4e-9ddd-58f215c4ce85" />
<img width="976" height="368" alt="Screenshot 2025-08-24 at 9 34 52 PM" src="https://github.com/user-attachments/assets/203f83c7-46f3-49f1-a1a8-e18f7ec8483b" />
Copilot AI pushed a commit that referenced this pull request Sep 8, 2025
…3138)

- part of #12223
- supersedes stack: #12228

This PR adds the ability to add node type information to indicate what node types a lint rule acts on. The lint rule runner can use this information to optimize running lint rules by skipping nodes, files, or rules that don't apply.

This is a simple version that is focused on creating the framework for automatically generating the rule runner code. This is not the end of optimizations. Currently only 102 rules have node type information, while 471 rules have no node type information and will not be skipped. Adding node type information for more rules will improve performance. We may also be able to skip more nodes and files by being clever about how we use this information. For example, filtering out any rules which do not run on any node type, if the file contains no relevant node types for the rule.

- Adds a new `RuleRunner` trait which includes information needed for indicating whether a rule has node type info or not
- Adds a `oxc_linter_codegen` task which is used to generate the implementation of `RuleRunner` trait for all lint rules. This is mostly written by AI, so worth a bit of skepticism, but I've tried to manually verify the results and it looks good (just lacking more complex detection).
  - Currently, only rules that contain a single top-level `if` statement (or chain of `else if`), or a single `match` statement will have their node type info generated. This should give us a high level of confidence, since these patterns are relatively easy to verify and identify, but it's only a subset of all rules. Next steps will be to add support for `let...else`
- Adjusts the main linting loop to use the node type information to skip rules for node types that don't apply
- Updates CI to include a check for any uncommitted linter codegen changes

---

## Benchmarks

In the latest version of this PR, CodSpeed shows an up to +13% increase in linter performance across large and small files. In the real-world, I've seen a ~5-15% improvement in performance, but in some cases close to zero for very small files. In either case, there appears to be little downside and a lot of potential upside here.

<img width="769" height="242" alt="Screenshot 2025-08-24 at 9 29 30 PM" src="https://github.com/user-attachments/assets/d2c430c4-17a9-4606-85d5-c66c734975d9" />
<img width="757" height="308" alt="Screenshot 2025-08-24 at 9 30 24 PM" src="https://github.com/user-attachments/assets/5508464f-de55-4f4e-9ddd-58f215c4ce85" />
<img width="976" height="368" alt="Screenshot 2025-08-24 at 9 34 52 PM" src="https://github.com/user-attachments/assets/203f83c7-46f3-49f1-a1a8-e18f7ec8483b" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-linter Area - Linter C-performance Category - Solution not expected to change functional behavior, only performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants