Skip to content

perf(specifiers): cache a Specifier's canonical form - #1372

Open
notatallshaw wants to merge 1 commit into
pypa:mainfrom
notatallshaw:perf/canonical-spec-memo
Open

perf(specifiers): cache a Specifier's canonical form#1372
notatallshaw wants to merge 1 commit into
pypa:mainfrom
notatallshaw:perf/canonical-spec-memo

Conversation

@notatallshaw

@notatallshaw notatallshaw commented Aug 8, 2026

Copy link
Copy Markdown
Member

Specifier.__hash__ and __eq__ both read _canonical_spec, which recomputed canonicalize_version on every call. This memoizes it in a slot beside the existing _spec_version and _ranges caches, cleared by __setstate__, the only path that replaces _spec.

Warm, on CPython 3.12 and 3.14:

before after
Specifier hash 876 / 739 µs 91 / 79 µs
Specifier equality 1.66 / 1.42 ms 142 / 135 µs
SpecifierSet construct + dedup 1.21 / 1.16 ms 648 / 601 µs

@notatallshaw
notatallshaw marked this pull request as draft August 8, 2026 19:14
@notatallshaw

Copy link
Copy Markdown
Member Author

Faster:

| Change   | Before [ef91ddbe]    | After [dc380a5d]    |   Ratio | Benchmark (Parameter)                                                                                    |
|----------|----------------------|---------------------|---------|----------------------------------------------------------------------------------------------------------|
|          | 5.40±0.04ms          | 5.44±0.04ms         |    1.01 | markers.TimeMarkerSuite.time_constructor [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]               |
|          | 4.05±0.03ms          | 4.04±0.04ms         |    1    | markers.TimeMarkerSuite.time_constructor [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]               |
|          | 4.59±0.03ms          | 4.64±0.04ms         |    1.01 | markers.TimeMarkerSuite.time_constructor [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]               |
|          | 4.62±0.03ms          | 4.69±0.03ms         |    1.01 | markers.TimeMarkerSuite.time_constructor [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]               |
|          | 4.58±0.04ms          | 4.57±0.04ms         |    1    | markers.TimeMarkerSuite.time_constructor [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]               |
|          | 1.07±0.01ms          | 1.07±0.01ms         |    1    | markers.TimeMarkerSuite.time_evaluate [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]                  |
|          | 748±7μs              | 756±7μs             |    1.01 | markers.TimeMarkerSuite.time_evaluate [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]                  |
|          | 877±10μs             | 871±5μs             |    0.99 | markers.TimeMarkerSuite.time_evaluate [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]                  |
|          | 810±6μs              | 826±7μs             |    1.02 | markers.TimeMarkerSuite.time_evaluate [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]                  |
|          | 788±6μs              | 792±4μs             |    1.01 | markers.TimeMarkerSuite.time_evaluate [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]                  |
|          | 19.3±0.08ms          | 19.4±0.1ms          |    1    | requirement.TimeRequirementSuite.time_constructor [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]      |
|          | 14.6±0.08ms          | 14.4±0.05ms         |    0.99 | requirement.TimeRequirementSuite.time_constructor [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]      |
|          | 16.4±0.1ms           | 16.3±0.08ms         |    1    | requirement.TimeRequirementSuite.time_constructor [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]      |
|          | 16.7±0.09ms          | 16.5±0.1ms          |    0.99 | requirement.TimeRequirementSuite.time_constructor [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]      |
|          | 16.1±0.07ms          | 16.2±0.1ms          |    1.01 | requirement.TimeRequirementSuite.time_constructor [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]      |
|          | 643±7μs              | 643±5μs             |    1    | resolver.TimeResolverSuite.time_resolver_loop [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]          |
|          | 453±9μs              | 457±9μs             |    1.01 | resolver.TimeResolverSuite.time_resolver_loop [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]          |
|          | 458±10μs             | 453±9μs             |    0.99 | resolver.TimeResolverSuite.time_resolver_loop [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]          |
|          | 429±9μs              | 431±8μs             |    1.01 | resolver.TimeResolverSuite.time_resolver_loop [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]          |
|          | 402±8μs              | 401±8μs             |    1    | resolver.TimeResolverSuite.time_resolver_loop [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]          |
| -        | 3.17±0.02ms          | 1.48±0.02ms         |    0.47 | specifiers.TimeSpecSuite.time_construct_and_dedup_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0] |
| -        | 2.39±0.02ms          | 1.21±0.01ms         |    0.51 | specifiers.TimeSpecSuite.time_construct_and_dedup_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0] |
| -        | 2.64±0.03ms          | 1.45±0.01ms         |    0.55 | specifiers.TimeSpecSuite.time_construct_and_dedup_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0] |
| -        | 2.44±0.01ms          | 1.40±0.01ms         |    0.57 | specifiers.TimeSpecSuite.time_construct_and_dedup_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0] |
| -        | 2.42±0.02ms          | 1.36±0.02ms         |    0.56 | specifiers.TimeSpecSuite.time_construct_and_dedup_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0] |
|          | 2.35±0.01ms          | 2.38±0.03ms         |    1.01 | specifiers.TimeSpecSuite.time_constructor [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]              |
|          | 2.03±0.02ms          | 2.02±0.01ms         |    1    | specifiers.TimeSpecSuite.time_constructor [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]              |
|          | 2.27±0.02ms          | 2.26±0.01ms         |    0.99 | specifiers.TimeSpecSuite.time_constructor [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]              |
|          | 2.00±0.02ms          | 1.98±0.02ms         |    0.99 | specifiers.TimeSpecSuite.time_constructor [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]              |
|          | 2.00±0.05ms          | 1.98±0.01ms         |    0.99 | specifiers.TimeSpecSuite.time_constructor [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]              |
|          | 9.04±0.05ms          | 9.10±0.06ms         |    1.01 | specifiers.TimeSpecSuite.time_contains_cold [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]            |
|          | 5.93±0.04ms          | 5.95±0.06ms         |    1    | specifiers.TimeSpecSuite.time_contains_cold [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]            |
|          | 6.39±0.06ms          | 6.37±0.06ms         |    1    | specifiers.TimeSpecSuite.time_contains_cold [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]            |
|          | 5.95±0.03ms          | 5.98±0.05ms         |    1    | specifiers.TimeSpecSuite.time_contains_cold [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]            |
|          | 5.63±0.06ms          | 5.61±0.02ms         |    1    | specifiers.TimeSpecSuite.time_contains_cold [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]            |
|          | 264±4μs              | 264±4μs             |    1    | specifiers.TimeSpecSuite.time_contains_complex_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]    |
|          | 171±1μs              | 175±4μs             |    1.02 | specifiers.TimeSpecSuite.time_contains_complex_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]    |
|          | 168±2μs              | 169±4μs             |    1.01 | specifiers.TimeSpecSuite.time_contains_complex_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]    |
|          | 166±6μs              | 165±4μs             |    0.99 | specifiers.TimeSpecSuite.time_contains_complex_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]    |
|          | 158±2μs              | 159±2μs             |    1.01 | specifiers.TimeSpecSuite.time_contains_complex_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]    |
|          | 3.75±0.04ms          | 3.78±0.02ms         |    1.01 | specifiers.TimeSpecSuite.time_contains_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]            |
|          | 2.55±0.02ms          | 2.57±0.04ms         |    1.01 | specifiers.TimeSpecSuite.time_contains_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]            |
|          | 2.74±0.01ms          | 2.72±0.02ms         |    0.99 | specifiers.TimeSpecSuite.time_contains_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]            |
|          | 2.42±0.01ms          | 2.44±0.02ms         |    1.01 | specifiers.TimeSpecSuite.time_contains_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]            |
|          | 2.31±0.02ms          | 2.32±0.05ms         |    1    | specifiers.TimeSpecSuite.time_contains_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]            |
| -        | 4.90±0.05ms          | 401±4μs             |    0.08 | specifiers.TimeSpecSuite.time_eq_specifier_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]        |
| -        | 3.34±0.01ms          | 275±10μs            |    0.08 | specifiers.TimeSpecSuite.time_eq_specifier_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]        |
| -        | 3.42±0.04ms          | 259±4μs             |    0.08 | specifiers.TimeSpecSuite.time_eq_specifier_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]        |
| -        | 2.95±0.02ms          | 259±6μs             |    0.09 | specifiers.TimeSpecSuite.time_eq_specifier_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]        |
| -        | 2.96±0.01ms          | 254±6μs             |    0.09 | specifiers.TimeSpecSuite.time_eq_specifier_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]        |
|          | 79.7±2μs             | 80.6±2μs            |    1.01 | specifiers.TimeSpecSuite.time_filter_compatible_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]   |
|          | 54.4±1μs             | 55.7±1μs            |    1.02 | specifiers.TimeSpecSuite.time_filter_compatible_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]   |
|          | 49.7±0.3μs           | 50.4±0.6μs          |    1.01 | specifiers.TimeSpecSuite.time_filter_compatible_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]   |
|          | 52.7±0.4μs           | 52.7±0.4μs          |    1    | specifiers.TimeSpecSuite.time_filter_compatible_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]   |
|          | 49.4±0.3μs           | 50.0±2μs            |    1.01 | specifiers.TimeSpecSuite.time_filter_compatible_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]   |
|          | 239±4μs              | 243±8μs             |    1.01 | specifiers.TimeSpecSuite.time_filter_complex_cold [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]      |
|          | 162±4μs              | 163±7μs             |    1    | specifiers.TimeSpecSuite.time_filter_complex_cold [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]      |
|          | 169±1μs              | 170±2μs             |    1    | specifiers.TimeSpecSuite.time_filter_complex_cold [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]      |
|          | 162±0.7μs            | 166±7μs             |    1.02 | specifiers.TimeSpecSuite.time_filter_complex_cold [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]      |
|          | 160±1μs              | 164±7μs             |    1.03 | specifiers.TimeSpecSuite.time_filter_complex_cold [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]      |
|          | 188±2μs              | 189±5μs             |    1.01 | specifiers.TimeSpecSuite.time_filter_complex_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]      |
|          | 129±3μs              | 127±3μs             |    0.99 | specifiers.TimeSpecSuite.time_filter_complex_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]      |
|          | 133±4μs              | 134±3μs             |    1.01 | specifiers.TimeSpecSuite.time_filter_complex_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]      |
|          | 130±2μs              | 130±5μs             |    1    | specifiers.TimeSpecSuite.time_filter_complex_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]      |
|          | 125±2μs              | 125±1μs             |    1    | specifiers.TimeSpecSuite.time_filter_complex_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]      |
|          | 32.0±0.7μs           | 32.6±1μs            |    1.02 | specifiers.TimeSpecSuite.time_filter_simple_cold [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]       |
|          | 24.1±0.7μs           | 23.9±1μs            |    0.99 | specifiers.TimeSpecSuite.time_filter_simple_cold [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]       |
|          | 22.8±0.7μs           | 23.2±0.4μs          |    1.02 | specifiers.TimeSpecSuite.time_filter_simple_cold [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]       |
|          | 22.3±0.2μs           | 22.8±0.5μs          |    1.02 | specifiers.TimeSpecSuite.time_filter_simple_cold [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]       |
|          | 22.9±0.4μs           | 22.8±0.5μs          |    1    | specifiers.TimeSpecSuite.time_filter_simple_cold [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]       |
|          | 25.1±0.3μs           | 25.6±0.7μs          |    1.02 | specifiers.TimeSpecSuite.time_filter_simple_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]       |
|          | 19.9±1μs             | 20.1±1μs            |    1.01 | specifiers.TimeSpecSuite.time_filter_simple_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]       |
|          | 18.1±0.4μs           | 18.2±0.3μs          |    1.01 | specifiers.TimeSpecSuite.time_filter_simple_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]       |
|          | 18.1±0.3μs           | 18.2±0.2μs          |    1.01 | specifiers.TimeSpecSuite.time_filter_simple_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]       |
|          | 19.0±1μs             | 19.0±1μs            |    1    | specifiers.TimeSpecSuite.time_filter_simple_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]       |
| -        | 2.58±0.04ms          | 245±5μs             |    0.09 | specifiers.TimeSpecSuite.time_hash_specifier_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]      |
| -        | 1.77±0.01ms          | 164±1μs             |    0.09 | specifiers.TimeSpecSuite.time_hash_specifier_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]      |
| -        | 1.77±0.01ms          | 164±5μs             |    0.09 | specifiers.TimeSpecSuite.time_hash_specifier_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]      |
| -        | 1.54±0.02ms          | 163±6μs             |    0.11 | specifiers.TimeSpecSuite.time_hash_specifier_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]      |
| -        | 1.57±0.01ms          | 162±2μs             |    0.1  | specifiers.TimeSpecSuite.time_hash_specifier_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]      |
|          | 5.16±0.02μs          | 5.17±0.05μs         |    1    | utils.TimeUtils.time_canonicalize_name [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]                 |
|          | 3.50±0.01μs          | 3.48±0.02μs         |    0.99 | utils.TimeUtils.time_canonicalize_name [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]                 |
|          | 3.76±0.03μs          | 3.78±0.08μs         |    1.01 | utils.TimeUtils.time_canonicalize_name [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]                 |
|          | 3.82±0.02μs          | 3.83±0.01μs         |    1    | utils.TimeUtils.time_canonicalize_name [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]                 |
|          | 4.25±0.01μs          | 4.26±0.01μs         |    1    | utils.TimeUtils.time_canonicalize_name [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]                 |
|          | 2.74±0.01ms          | 2.75±0.01ms         |    1    | version.TimeVersionSuite.time_constructor [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]              |
|          | 1.83±0.02ms          | 1.82±0.02ms         |    1    | version.TimeVersionSuite.time_constructor [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]              |
|          | 2.26±0.02ms          | 2.26±0.02ms         |    1    | version.TimeVersionSuite.time_constructor [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]              |
|          | 2.00±0.03ms          | 2.00±0.02ms         |    1    | version.TimeVersionSuite.time_constructor [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]              |
|          | 1.76±0.01ms          | 1.77±0.01ms         |    1    | version.TimeVersionSuite.time_constructor [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]              |
|          | 3.62±0.03ms          | 3.58±0.02ms         |    0.99 | version.TimeVersionSuite.time_hash [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]                     |
|          | 2.44±0.01ms          | 2.46±0.01ms         |    1.01 | version.TimeVersionSuite.time_hash [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]                     |
|          | 2.94±0.01ms          | 2.96±0.01ms         |    1.01 | version.TimeVersionSuite.time_hash [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]                     |
|          | 2.73±0.01ms          | 2.76±0.01ms         |    1.01 | version.TimeVersionSuite.time_hash [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]                     |
|          | 2.48±0.02ms          | 2.46±0.02ms         |    0.99 | version.TimeVersionSuite.time_hash [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]                     |
|          | 354±8μs              | 352±5μs             |    1    | version.TimeVersionSuite.time_hash_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]                |
|          | 234±6μs              | 238±3μs             |    1.02 | version.TimeVersionSuite.time_hash_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]                |
|          | 254±5μs              | 253±4μs             |    1    | version.TimeVersionSuite.time_hash_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]                |
|          | 258±6μs              | 256±5μs             |    0.99 | version.TimeVersionSuite.time_hash_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]                |
|          | 243±3μs              | 241±7μs             |    0.99 | version.TimeVersionSuite.time_hash_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]                |
|          | 2.73±0.02ms          | 2.74±0.01ms         |    1    | version.TimeVersionSuite.time_sort_cold [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]                |
|          | 2.04±0.01ms          | 2.03±0.01ms         |    1    | version.TimeVersionSuite.time_sort_cold [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]                |
|          | 2.44±0.03ms          | 2.44±0.03ms         |    1    | version.TimeVersionSuite.time_sort_cold [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]                |
|          | 2.32±0.01ms          | 2.33±0.01ms         |    1    | version.TimeVersionSuite.time_sort_cold [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]                |
|          | 2.30±0.01ms          | 2.30±0.01ms         |    1    | version.TimeVersionSuite.time_sort_cold [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]                |
|          | 2.14±0.01ms          | 2.13±0.02ms         |    1    | version.TimeVersionSuite.time_sort_warm [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]                |
|          | 1.65±0.01ms          | 1.66±0.01ms         |    1    | version.TimeVersionSuite.time_sort_warm [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]                |
|          | 1.84±0.07ms          | 1.84±0.01ms         |    1    | version.TimeVersionSuite.time_sort_warm [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]                |
|          | 1.94±0.01ms          | 1.93±0.01ms         |    1    | version.TimeVersionSuite.time_sort_warm [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]                |
|          | 1.92±0.01ms          | 1.93±0.01ms         |    1.01 | version.TimeVersionSuite.time_sort_warm [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]                |
|          | 4.54±0.01ms          | 4.53±0.02ms         |    1    | version.TimeVersionSuite.time_str [runnervmvrwv9/virtualenv-py3.10-PYTHONHASHSEED0]                      |
|          | 3.22±0.03ms          | 3.25±0.01ms         |    1.01 | version.TimeVersionSuite.time_str [runnervmvrwv9/virtualenv-py3.11-PYTHONHASHSEED0]                      |
|          | 3.64±0.01ms          | 3.63±0.02ms         |    1    | version.TimeVersionSuite.time_str [runnervmvrwv9/virtualenv-py3.12-PYTHONHASHSEED0]                      |
|          | 3.22±0.01ms          | 3.25±0.02ms         |    1.01 | version.TimeVersionSuite.time_str [runnervmvrwv9/virtualenv-py3.13-PYTHONHASHSEED0]                      |
|          | 3.11±0.03ms          | 3.11±0.02ms         |    1    | version.TimeVersionSuite.time_str [runnervmvrwv9/virtualenv-py3.14-PYTHONHASHSEED0]                      |

SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.
PERFORMANCE INCREASED.

@notatallshaw
notatallshaw marked this pull request as ready for review August 8, 2026 19:33
@henryiii

henryiii commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

A few things from a Fable review, if you want:

(1: A helper might have a cost, probably not worth it)
(2: Depends on how important having fast hashing is here. This is 1/3 of #1252)

🤖 AI text below 🤖

The review found no correctness bugs in the caching change itself — verifiers independently confirmed the cache invalidation on __setstate__, pickling paths, and equality/hash semantics are sound. The five reported findings are cleanup opportunities:

  1. Cache-slot bookkeeping — each new cache slot must now be maintained in four places (__slots__, __init__, __setstate__, and the benchmark's _make_cold); a small _clear_caches() helper would centralize that.
  2. __hash__ follow-on — storing the precomputed hash in the new slot would turn warm hashing into a single attribute read (~62ns → ~35ns per member).
  3. Benchmark comment/design — the comment on time_construct_and_dedup_warm is wrong, and including construction in the timed region dilutes the dedup signal by roughly 40%.
  4. Duplicate testtest_canonical_spec_cache_matches_fresh_value is subsumed by the consistency test.
  5. Benchmark warmup — the eq/hash warmup reparses the corpus twice when already-warmed objects are on hand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants