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

Remove AST-node dependency from FunctionType and ClassType #14087

Merged
merged 6 commits into from
Nov 5, 2024

Conversation

MichaReiser
Copy link
Member

@MichaReiser MichaReiser commented Nov 4, 2024

Summary

This PR improves Red Knot's incremental computation by:

  • Making FunctionType::return_type and ClassType::explicit_bases salsa queries. I suspect this is where the main performance improvement comes from. Making these two functions salsa queries prevents that the class or function's node (accessed through definition.node) is marked as a dependency at the callee side. Instead, the callee only depends on whatever the return type or bases are.
  • Removing FunctionType::definition and ClassType::definition and instead use semantic_index.definition(..) to lookup the type's definition lazily. This ensures that deserializing a type doesn't require deserializing the AST as well.
  • Remove ScopeId::node and move it to Scope::node. Same as for FunctionType::definition. Moving the Node from the ScopeId to the definition allows deserializing the ScopeId without deserializing the AST node. This is important because both FunctionType and ClassType have a ScopeId field.

Fixes #14054

Test Plan

cargo test

@MichaReiser MichaReiser changed the title Move ScopeId::node to Scope to avoid depending on AST node Remove AST-node dependency from Type Nov 4, 2024
@MichaReiser MichaReiser added the red-knot Multi-file analysis & type inference label Nov 4, 2024
@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch from 817ee80 to 7908514 Compare November 4, 2024 09:01
Copy link
Contributor

github-actions bot commented Nov 4, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch from 079e46a to 1fc3dc4 Compare November 4, 2024 14:30
Copy link

codspeed-hq bot commented Nov 4, 2024

CodSpeed Performance Report

Merging #14087 will improve performances by 12.36%

Comparing micha/remove-ast-dependencies-from-type (eb97246) with main (9dddd73)

Summary

⚡ 1 improvements
✅ 31 untouched benchmarks

Benchmarks breakdown

Benchmark main micha/remove-ast-dependencies-from-type Change
red_knot_check_file[incremental] 4.6 ms 4.1 ms +12.36%

@MichaReiser
Copy link
Member Author

Lol what

@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch from 1fc3dc4 to a1a709f Compare November 4, 2024 14:55
@MichaReiser MichaReiser changed the title Remove AST-node dependency from Type Remove AST-node dependency from FunctionType and ClassType Nov 4, 2024
@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch from a1a709f to 6d5f492 Compare November 4, 2024 15:13
/// would depend on the function's AST and rerun for every change in that file.
pub fn return_ty(self, db: &'db dyn Db) -> Type<'db> {
let scope = self.body_scope(db);
let function_stmt_node = scope.node(db).expect_function();
Copy link
Member Author

@MichaReiser MichaReiser Nov 4, 2024

Choose a reason for hiding this comment

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

The issue without this being a salsa query is that the calling-query suddenly depends on the function's ast (and, therefore, the file).

In the case of our benchmark: _parser.py calls match_to_datetime which is defined in _re.py. Now, it shouldn't be necessary to recheck _parser.py because no type in _re.py changed. However, Salsa had to recheck every callsite because the return_type query accessed the definition.kind(db) which is the AST node of the match_to_datetime and its AST has changed (not really, but we use no_eq...)

I verified that making return_ty is the reason for the perf improvement by removing the #[salsa::tracked].

@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch from 0b80226 to 6d5f492 Compare November 4, 2024 15:21
@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch 2 times, most recently from f93cea2 to 4bb6209 Compare November 4, 2024 15:25
@MichaReiser MichaReiser marked this pull request as ready for review November 4, 2024 15:33
@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch from 4bb6209 to a4f8f95 Compare November 4, 2024 15:42
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Nice!

@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch from a4f8f95 to 51a9983 Compare November 4, 2024 15:51
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

LGTM other than my remaining docs nits and one further optional comment:

crates/red_knot_python_semantic/src/types.rs Show resolved Hide resolved
Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

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

Code changes here look great, thanks for sorting this out!

My main concern is that I think the guidance here is going to prove quite difficult to remember and follow manually and solely via code review; it's just very easy for these things to leak. It seems like it should be possible to write tests that are similar to what happen in our benchmark, just verifying that if you make a no-op change to one file, it doesn't cause re-execution of queries in another file that shouldn't need to re-execute. I think a few tests like that could go a really long way in helping us avoid regression here.

@MichaReiser
Copy link
Member Author

MichaReiser commented Nov 5, 2024

@carljm I agree that a test would be nice. I added one for call inference although I'm not sure how valuable it is because it is rather fragile (a slight change to inference will break the test itself).

I don't know how to write the ideal test that:

  • Exercises most language features
  • Asserts that infer_definition_types or infer_expression_types is never called for any other file than the file to which the comment was added.

The problem here is that salsa doesn't provide the necessary reflection API to answer the second question. We could log all events but that test is likely going to break with every inference test AND it's kind of impossible to tell from a ExpressionId to which file it belongs.

I don't mind adding more tests if you have suggestions on how to test this, but I'll leave it at what I have for now. I do think that our benchmarks do a decent job at this anyway. I would hope that we would investigate a 12% perf regression ;)

I don't think there's a way to test deserialization in a meaningful before salsa adds persistent caching support.

@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch from f3bec2d to 26cd7ed Compare November 5, 2024 07:51
@MichaReiser MichaReiser force-pushed the micha/remove-ast-dependencies-from-type branch from 26cd7ed to 969461f Compare November 5, 2024 07:53
@MichaReiser MichaReiser enabled auto-merge (squash) November 5, 2024 07:53
@MichaReiser MichaReiser merged commit 4323512 into main Nov 5, 2024
16 checks passed
@MichaReiser MichaReiser deleted the micha/remove-ast-dependencies-from-type branch November 5, 2024 08:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
red-knot Multi-file analysis & type inference
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[red-knot] Remove Definition from Class and FunctionType
5 participants