Skip to content

Conversation

@AlexWaygood
Copy link
Member

@AlexWaygood AlexWaygood commented Aug 7, 2025

Stacked on top of #19669; review that PR first!


Summary

This implements @carljm's suggestion from #19669 (comment), which appears to buy back almost all the performance and memory regressions from #19669. If we like this approach, I'll merge this PR into that branch shortly before merging that PR. (I'm keeping them as separate PRs for now, for ease of review.)

Test Plan

All existing tests pass. I don't believe this has any impact on semantics. There is still a small primer report on this PR, but it's now a bit of a mystery to me: I can't reproduce any of the "diagnostics going away" on the target branch of this PR, and I can reproduce all of the "diagnostics being added" on the target branch of this PR. I've seen slightly confusing results from mypy_primer in the past for stacked PRs; I suspect there's a subtle bug in the workflow somewhere that leads to it reporting a diagnostic diff even when there isn't one in cases like this.

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Aug 7, 2025
@AlexWaygood AlexWaygood force-pushed the alex/remove-tuples-instance-enum branch from 055747d to f010554 Compare August 7, 2025 17:21
@github-actions
Copy link
Contributor

github-actions bot commented Aug 7, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@github-actions
Copy link
Contributor

github-actions bot commented Aug 7, 2025

mypy_primer results

No ecosystem changes detected ✅

Memory usage changes were detected when running on open source projects
flake8 (https://github.com/pycqa/flake8)
-     struct metadata = ~3MB
+     struct metadata = ~2MB

trio (https://github.com/python-trio/trio)
-     struct metadata = ~8MB
+     struct metadata = ~7MB

sphinx (https://github.com/sphinx-doc/sphinx)
-     struct fields = ~16MB
+     struct fields = ~15MB

prefect (https://github.com/PrefectHQ/prefect)
-     struct fields = ~35MB
+     struct fields = ~33MB
-     memo metadata = ~84MB
+     memo metadata = ~80MB

@codspeed-hq
Copy link

codspeed-hq bot commented Aug 7, 2025

CodSpeed WallTime Performance Report

Merging #19811 will improve performances by 63.76%

Comparing alex/remove-tuples-instance-enum (dd260ae) with alex/remove-tuples (3436d5d)

Summary

⚡ 4 improvements
✅ 3 untouched benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
large[sympy] 41.3 s 39.7 s +4.08%
medium[colour-science] 10.6 s 6.5 s +63.76%
medium[pandas] 26.4 s 24.7 s +6.94%
small[tanjun] 1.7 s 1.6 s +5.65%

@codspeed-hq
Copy link

codspeed-hq bot commented Aug 7, 2025

CodSpeed Instrumentation Performance Report

Merging #19811 will improve performances by 6.26%

Comparing alex/remove-tuples-instance-enum (dd260ae) with alex/remove-tuples (3436d5d)

Summary

⚡ 1 improvements
✅ 41 untouched benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
ty_micro[many_string_assignments] 73.9 ms 69.6 ms +6.26%

@AlexWaygood

This comment was marked as outdated.

@AlexWaygood

This comment was marked as outdated.

@AlexWaygood AlexWaygood force-pushed the alex/remove-tuples branch 2 times, most recently from 00b10f8 to 0fc1a93 Compare August 8, 2025 12:19
@AlexWaygood AlexWaygood force-pushed the alex/remove-tuples-instance-enum branch 2 times, most recently from 25a225c to 899fb87 Compare August 8, 2025 12:45
@AlexWaygood

This comment was marked as outdated.

@AlexWaygood

This comment was marked as outdated.

@AlexWaygood AlexWaygood force-pushed the alex/remove-tuples-instance-enum branch from b16f9af to e8ceb16 Compare August 8, 2025 13:33
@AlexWaygood AlexWaygood force-pushed the alex/remove-tuples branch 2 times, most recently from a24e949 to df1357f Compare August 8, 2025 16:51
@AlexWaygood AlexWaygood force-pushed the alex/remove-tuples-instance-enum branch from e8ceb16 to ce7ee42 Compare August 8, 2025 16:54
@AlexWaygood AlexWaygood marked this pull request as ready for review August 8, 2025 16:57
@AlexWaygood AlexWaygood added the performance Potential performance improvement label Aug 8, 2025
@AlexWaygood
Copy link
Member Author

Well... there's some bad news here. I just noticed that mypy_primer runs seem to be taking a very long time on this PR branch. It looks like it takes 10 minutes to type-check static-frame with this PR branch in mypy_primer, whereas it takes around 1 minute to type-check static-frame with #19669. I can reproduce a severe slowdown locally on this branch for that repo too. No idea why that would be yet.

@AlexWaygood
Copy link
Member Author

AlexWaygood commented Aug 8, 2025

Okay, fbcb8e3 fixes the static-frame perf regression for me locally! It might be worthwhile for us to add static-frame as a benchmark -- I can look into that as a followup.

Edit: and it fixed it in CI as well -- mypy_primer is back to completing in ~3m!

@AlexWaygood

This comment was marked as outdated.

@AlexWaygood AlexWaygood force-pushed the alex/remove-tuples-instance-enum branch from fbcb8e3 to c84f961 Compare August 8, 2025 22:25
@AlexWaygood AlexWaygood force-pushed the alex/remove-tuples-instance-enum branch from 8c00cdb to 3b39238 Compare August 9, 2025 08:42
// N.B. If this method is not Salsa-tracked, we take 10 minutes to check
// `static-frame` as part of a mypy_primer run! This is because it's called
// from `NominalInstanceType::class()`, which is a very hot method.
#[salsa::tracked]
Copy link
Member Author

Choose a reason for hiding this comment

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

Comment on lines +115 to +119
/// If this is an instance type where the class has a tuple spec, returns the tuple spec.
///
/// I.e., for the type `tuple[int, str]`, this will return the tuple spec `[int, str]`.
/// For a subclass of `tuple[int, str]`, it will return the same tuple spec.
pub(super) fn tuple_spec(&self, db: &'db dyn Db) -> Option<Cow<'db, TupleSpec<'db>>> {
Copy link
Member Author

Choose a reason for hiding this comment

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

I moved this method from class.rs to instance.rs so that we could avoid having to materialize the ClassType if the instance type was an ExactTuple variant internally.

Now that I've added caching to TupleType::to_class_type(), this might not be a particularly significant optimisation anymore. But with our current callsites across the repo, we only ever need to know the tuple spec of instances, never the tuple spec of Type::GenericAliases. So there doesn't appear to be a huge amount of downside to making this a method on NominalInstanceType rather than a method on ClassType.

slice_literal could also possibly be made a method on NominalInstanceType rather than ClassType, but it doesn't seem to have any performance benefits from what I can tell locally, and it would make this PR's diff bigger.

.apply_specialization(db, |_| generic_context.specialize_tuple(db, self)),
),
})
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
Copy link
Member Author

Choose a reason for hiding this comment

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

This .expect() call means we now panic if we're given a custom typeshed without a tuple class. I don't love this but I also think it's okay -- there are already classes where we panic if they're not available in typeshed, such as object and types.ModuleType. tuple is similarly special; I think it's okay if we effectively mandate that custom typesheds have to have a tuple class in them.

Doing this refactor without the .expect() call here would be quite a bit harder, I think.

@AlexWaygood
Copy link
Member Author

I've merged the changes here directly into #19669

@AlexWaygood AlexWaygood deleted the alex/remove-tuples-instance-enum branch August 11, 2025 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Potential performance improvement ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants