-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[ty] Move Salsa caching "down a layer" in tuple.rs
#19877
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
Conversation
Diagnostic diff on typing conformance testsChanges were detected when running ty on typing conformance tests--- old-output.txt 2025-08-12 16:21:25.297441346 +0000
+++ new-output.txt 2025-08-12 16:21:25.364441662 +0000
@@ -1,5 +1,5 @@
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
-fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/918d35d/src/function/execute.rs:215:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(1f113)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/918d35d/src/function/execute.rs:215:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(5f5e)): execute: too many cycle iterations`
_directives_deprecated_library.py:15:31: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
_directives_deprecated_library.py:30:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `str`
_directives_deprecated_library.py:36:41: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@__add__` |
|
3cd18a2 to
aea07ae
Compare
|
The latest version of the PR shows small but consistent improvements of 1-2% on quite a few benchmarks. |
bd517f2 to
4676953
Compare
| impl<'db> Type<'db> { | ||
| pub(crate) fn homogeneous_tuple(db: &'db dyn Db, element: Type<'db>) -> Self { | ||
| Type::tuple(TupleType::homogeneous(db, element)) | ||
| } | ||
|
|
||
| pub(crate) fn heterogeneous_tuple<I, T>(db: &'db dyn Db, elements: I) -> Self | ||
| where | ||
| I: IntoIterator<Item = T>, | ||
| T: Into<Type<'db>>, | ||
| { | ||
| Type::tuple(TupleType::from_elements( | ||
| db, | ||
| elements.into_iter().map(Into::into), | ||
| )) | ||
| } | ||
|
|
||
| pub(crate) fn empty_tuple(db: &'db dyn Db) -> Self { | ||
| Type::tuple(Some(TupleType::empty(db))) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are moved to instance.rs because we can do the same things with less indirection from that module (we can access private implementation details of NominalInstanceType from that module)
cb8fe72 to
2f573e5
Compare
|
(CI failures are all due to the GitHub outage) |
dcreager
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an alternative, we might consider just making Tuple (and therefore TupleSpec in the world where it's still an alias) easier/cheaper to clone. On the assumption that most tuple specs are small, we could use SmallVecs inside of Tuple and friends, and just clone the TupleSpecs where we need to. Then you'd get rid of the Cows by returning owned TupleSpecs everywhere.
we can avoid some very complicated trait bounds that we currently have in the signature of
TupleType::new()onmain.
See below; this was only there to let us call the salsa interning logic with a reference, but if TupleSpec becomes cheap to clone, that's no longer needed.
| T: Borrow<TupleSpec<'db>> + Hash + salsa::plumbing::interned::Lookup<TupleSpec<'db>>, | ||
| TupleSpec<'db>: salsa::plumbing::interned::HashEqLike<T>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These bounds were only here to allow callers to pass in a reference to a TupleSpec or an owned one. If you pass in a reference, we could avoid the clone if the result ended up being None, or if there was already an interned TupleType with an equivalent TupleSpec.
When I first added this code, there were some hot path calls where that seemed to make a noticeable difference in performance. But looking again now, that no longer seems to be the case — in most places we're already calling with an owned TupleSpec. So, given that, you could also get rid of these bounds by just taking in an owned TupleSpec, and requiring the caller to clone before calling if they have a reference.
Hmm... we could, but I'm not sure I see the advantages of doing it that way. If we did this we'd have to keep What are the benefits of your proposal relative to my current PR? |
2f573e5 to
df2a43a
Compare
Yep, with my suggestion, |
Hmmmmmm, I see, fair enough. I'm slightly sceptical that #19867 is indicative of a broader problem when it comes to lock contention -- my instinct is that that issue is quite sui generis. But I do agree that we should probably try to intern the minimum number of objects in the Salsa cache, since it leads to higher memory usage overall; and I think you're right that this PR in its current form probably leads to us interning a number of |
I guess that depends on the perspective :) It is specific in the sense that it is only an issue when the same interned values (of a specific interned struct) are used in a very hot code path. It isn't an issue if many threads intern many different interned structs because Salsa shards the locks by value, meaning most threads will end up acquiring different locks. I don't understand The other part that makes #19867 somewhat unique is that it's a very hot methods. I'm not sure if |
|
I find @dcreager's point pretty convincing: most of the paths in I don't love how viral our current design makes all the Thanks @dcreager! |
We can still try to get rid of the |
|
Right! But I consider the price of a few ugly 🐄s worth it to avoid some unnecessary clones, even if those clones wouldn't actually be that expensive 😆 |
Summary
This PR moves the Salsa caching "down a layer" in
tuple.rs:TupleTypeis no longer a Salsa-tracked struct; instead, it's just a thin wrapper around a Salsa-tracked struct, similar toNominalInstanceType,ProtocolInstanceTypeand others.TupleSpec(the type wrapped byTupleType) is no longer a type alias; instead, it's now a Salsa-tracked struct.The benefits of this are that we need to use many fewer
Cows across the ty codebase (which were previously required due toTupleSpecnot beingCopy), and we can avoid some very complicated trait bounds that we currently have in the signature ofTupleType::new()onmain.Test Plan
Existing tests