Sitelet https://web.archive.org/web/20250331173536/https://github.com/microsoft/TypeScript/pull/61505
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

[experiment] Cache mapper instantiations #61505

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

Andarist
Copy link
Contributor

@ssalbdivad found out that a chain of somewhat trivial operations can easily end up with dreaded "Type instantiation is excessively deep and possibly infinite".

Two different reproductions were created:

  1. standalone signature receiving its previous output as input in a chain: TS playground
  2. a dotted chain where a method returns a new instance of its own enclosing type alias: TS playground

We were able to bisect both to two different past PRs - one of which is quite old:

  1. the first one bisects to this PR and we can see it performing better in TS 5.4 here
  2. the other one bisects to this PR and we can see it performing better in TS 4.1 here

⚠️ that said - the "chain setup" avoids the error better but the property type lookup can still lead to the error. So, in some sense, the error just shifted place.

I dug into this and what I found out is, those types refer to the same "base" types - they are chained from them and instantiateType repeats the work on them a lot. At least part of the problem is that getObjectTypeInstantiation calls instantiateTypes(type.aliasTypeArguments, mapper) to create part of its cache key. So it can't even check if the result is cached before it instantiates those. This problem compounds heavily in longer chains like this.

So I toyed with possible solutions and I realized that caching results on mappers could help here... to some extent at least. I don't think it's the best solution but I also don't yet understand this problem to its core to propose anything better. The fact that property lookup still leads to the problem is especially worrying here.

Tha being said... it looks like this has very positive impact on instantiation counts across the test suite. It surely trades some memory for it though. It would be interesting to see perf results for this and the extended test suite run (even if only to get new data points for further investigation).

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Mar 30, 2025
@typescript-bot
Copy link
Collaborator

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

@@ -19960,7 +19961,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function makeFunctionTypeMapper(func: (t: Type) => Type, debugInfo: () => string): TypeMapper {
return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Function, func, debugInfo: Debug.isDebugging ? debugInfo : undefined });
const mapper = Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Function, func, debugInfo: Debug.isDebugging ? debugInfo : undefined });
mapper.instantiations = voidMap;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

those mappers are "global" and this is just a quick hack to prevent this caching mechanism to kick in on them

Comment on lines +25589 to +25591
if (context) {
context.nonFixingMapper.instantiations = undefined;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

nonFixingMapper isn't idempotent so whenever inferences are cleared it's instantiation cache has to be cleared too

@jakebailey
Copy link
Member

@typescript-bot test it

@typescript-bot
Copy link
Collaborator

typescript-bot commented Mar 30, 2025 •

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
test top400 ✅ Started
user test this ✅ Started
run dt ✅ Started
perf test this faster ✅ Started

@jakebailey
Copy link
Member

@typescript-bot test it

@typescript-bot
Copy link
Collaborator

typescript-bot commented Mar 31, 2025 •

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
test top400 ✅ Started
user test this ✅ Started 👀 Results
run dt ✅ Started ✅ Results
perf test this faster ✅ Started 👀 Results

@typescript-bot
Copy link
Collaborator

Hey @jakebailey, the results of running the DT tests are ready.

Everything looks the same!

You can check the log here.

@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the user tests with tsc comparing main and refs/pull/61505/merge:

Something interesting changed - please have a look.

Details

effect

packages/effect/benchmark/tsconfig.json

tsconfig.json

tsconfig.build.json

tsconfig.base.json

packages/typeclass/dtslint/tsconfig.json

packages/platform/dtslint/tsconfig.json

packages/effect/dtslint/tsconfig.json

@typescript-bot
Copy link
Collaborator

@jakebailey
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-Unions - node (v18.15.0, x64)
Errors 34 34 ~ ~ ~ p=1.000 n=6
Symbols 62,390 62,390 ~ ~ ~ p=1.000 n=6
Types 50,395 50,395 ~ ~ ~ p=1.000 n=6
Memory used 194,709k (± 1.01%) 196,843k (± 0.98%) ~ 194,935k 198,710k p=0.173 n=6
Parse Time 1.31s (± 0.31%) 1.31s (± 0.57%) ~ 1.30s 1.32s p=1.000 n=6
Bind Time 0.73s 0.73s ~ ~ ~ p=1.000 n=6
Check Time 9.73s (± 0.49%) 9.77s (± 0.35%) ~ 9.71s 9.81s p=0.228 n=6
Emit Time 2.73s (± 0.54%) 2.73s (± 0.65%) ~ 2.71s 2.75s p=0.935 n=6
Total Time 14.51s (± 0.37%) 14.54s (± 0.16%) ~ 14.50s 14.56s p=0.253 n=6
angular-1 - node (v18.15.0, x64)
Errors 56 56 ~ ~ ~ p=1.000 n=6
Symbols 948,670 948,670 ~ ~ ~ p=1.000 n=6
Types 410,947 410,947 ~ ~ ~ p=1.000 n=6
Memory used 1,224,296k (± 0.00%) 1,248,572k (± 0.00%) +24,276k (+ 1.98%) 1,248,514k 1,248,618k p=0.005 n=6
Parse Time 6.63s (± 1.21%) 6.63s (± 0.67%) ~ 6.56s 6.70s p=1.000 n=6
Bind Time 1.88s (± 0.67%) 1.88s (± 0.73%) ~ 1.87s 1.90s p=0.557 n=6
Check Time 31.93s (± 0.37%) 32.31s (± 0.31%) +0.39s (+ 1.21%) 32.18s 32.47s p=0.005 n=6
Emit Time 15.23s (± 0.22%) 15.26s (± 0.24%) ~ 15.21s 15.32s p=0.147 n=6
Total Time 55.67s (± 0.25%) 56.09s (± 0.21%) +0.42s (+ 0.75%) 55.98s 56.31s p=0.005 n=6
mui-docs - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 2,461,267 2,461,267 ~ ~ ~ p=1.000 n=6
Types 893,340 893,340 ~ ~ ~ p=1.000 n=6
Memory used 2,310,804k (± 0.00%) 2,342,249k (± 0.00%) +31,445k (+ 1.36%) 2,342,222k 2,342,302k p=0.005 n=6
Parse Time 9.04s (± 0.22%) 9.04s (± 0.17%) ~ 9.02s 9.06s p=1.000 n=6
Bind Time 2.27s (± 0.36%) 2.26s (± 0.53%) ~ 2.25s 2.28s p=0.652 n=6
Check Time 75.67s (± 0.38%) 75.95s (± 0.42%) ~ 75.43s 76.42s p=0.173 n=6
Emit Time 0.29s (± 1.92%) 0.29s (± 1.80%) ~ 0.28s 0.29s p=0.640 n=6
Total Time 87.26s (± 0.34%) 87.55s (± 0.35%) ~ 87.03s 87.99s p=0.173 n=6
self-build-src - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,226,713 1,226,807 +94 (+ 0.01%) ~ ~ p=0.001 n=6
Types 266,991 267,000 +9 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 2,357,616k (± 0.03%) 2,376,351k (± 0.02%) +18,735k (+ 0.79%) 2,375,702k 2,377,087k p=0.005 n=6
Parse Time 5.20s (± 1.17%) 5.17s (± 0.50%) ~ 5.14s 5.21s p=0.297 n=6
Bind Time 1.79s (± 1.91%) 1.78s (± 0.68%) ~ 1.77s 1.80s p=0.744 n=6
Check Time 35.40s (± 0.56%) 35.58s (± 0.33%) ~ 35.41s 35.75s p=0.066 n=6
Emit Time 2.99s (± 2.22%) 2.99s (± 1.20%) ~ 2.96s 3.06s p=0.630 n=6
Total Time 45.40s (± 0.72%) 45.53s (± 0.17%) ~ 45.45s 45.62s p=0.066 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,226,713 1,226,807 +94 (+ 0.01%) ~ ~ p=0.001 n=6
Types 266,991 267,000 +9 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 2,911,961k (±12.87%) 3,067,098k (± 9.90%) 🔻+155,137k (+ 5.33%) 2,446,535k 3,191,944k p=0.031 n=6
Parse Time 6.94s (± 1.45%) 6.94s (± 1.80%) ~ 6.70s 7.04s p=1.000 n=6
Bind Time 2.14s (± 2.28%) 2.12s (± 1.06%) ~ 2.08s 2.14s p=0.810 n=6
Check Time 42.65s (± 0.57%) 42.85s (± 0.37%) ~ 42.57s 43.01s p=0.128 n=6
Emit Time 3.45s (± 2.05%) 3.53s (± 0.82%) +0.07s (+ 2.17%) 3.49s 3.58s p=0.044 n=6
Total Time 55.20s (± 0.59%) 55.45s (± 0.48%) ~ 54.92s 55.69s p=0.128 n=6
self-compiler - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 262,674 262,691 +17 (+ 0.01%) ~ ~ p=0.001 n=6
Types 106,849 106,858 +9 (+ 0.01%) ~ ~ p=0.001 n=6
Memory used 440,486k (± 0.01%) 449,610k (± 0.02%) +9,124k (+ 2.07%) 449,509k 449,723k p=0.005 n=6
Parse Time 3.54s (± 0.42%) 3.51s (± 0.91%) ~ 3.48s 3.57s p=0.052 n=6
Bind Time 1.31s (± 0.39%) 1.32s (± 0.80%) ~ 1.30s 1.33s p=0.794 n=6
Check Time 19.05s (± 0.31%) 19.04s (± 0.36%) ~ 18.93s 19.13s p=0.810 n=6
Emit Time 1.52s (± 0.65%) 1.53s (± 0.79%) ~ 1.51s 1.54s p=0.246 n=6
Total Time 25.43s (± 0.27%) 25.39s (± 0.32%) ~ 25.29s 25.53s p=0.423 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors 71 71 ~ ~ ~ p=1.000 n=6
Symbols 225,981 225,981 ~ ~ ~ p=1.000 n=6
Types 94,356 94,356 ~ ~ ~ p=1.000 n=6
Memory used 371,214k (± 0.01%) 379,734k (± 0.01%) +8,519k (+ 2.29%) 379,686k 379,811k p=0.005 n=6
Parse Time 2.89s (± 0.60%) 2.91s (± 0.96%) ~ 2.86s 2.93s p=0.192 n=6
Bind Time 1.61s (± 1.69%) 1.60s (± 1.46%) ~ 1.57s 1.63s p=0.333 n=6
Check Time 16.51s (± 0.33%) 16.54s (± 0.26%) ~ 16.49s 16.61s p=0.574 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 21.02s (± 0.26%) 21.04s (± 0.25%) ~ 20.99s 21.12s p=0.628 n=6
vscode - node (v18.15.0, x64)
Errors 3 3 ~ ~ ~ p=1.000 n=6
Symbols 3,336,059 3,336,059 ~ ~ ~ p=1.000 n=6
Types 1,130,507 1,130,507 ~ ~ ~ p=1.000 n=6
Memory used 3,394,122k (± 0.01%) 3,466,746k (± 0.01%) +72,624k (+ 2.14%) 3,466,227k 3,466,964k p=0.005 n=6
Parse Time 14.70s (± 0.34%) 14.60s (± 0.53%) -0.10s (- 0.71%) 14.51s 14.69s p=0.030 n=6
Bind Time 4.67s (± 0.62%) 4.69s (± 0.61%) ~ 4.66s 4.74s p=0.514 n=6
Check Time 93.33s (± 2.44%) 93.32s (± 3.35%) ~ 91.13s 98.75s p=0.936 n=6
Emit Time 29.88s (± 2.66%) 30.10s (± 2.92%) ~ 29.44s 31.36s p=0.575 n=6
Total Time 142.58s (± 2.06%) 142.71s (± 2.81%) ~ 139.84s 149.43s p=1.000 n=6
webpack - node (v18.15.0, x64)
Errors 2 2 ~ ~ ~ p=1.000 n=6
Symbols 310,441 310,441 ~ ~ ~ p=1.000 n=6
Types 136,030 136,030 ~ ~ ~ p=1.000 n=6
Memory used 465,164k (± 0.02%) 475,453k (± 0.01%) +10,290k (+ 2.21%) 475,362k 475,517k p=0.005 n=6
Parse Time 5.15s (± 0.56%) 5.16s (± 0.94%) ~ 5.13s 5.26s p=0.418 n=6
Bind Time 2.26s (± 0.99%) 2.26s (± 1.23%) ~ 2.24s 2.31s p=0.934 n=6
Check Time 25.48s (± 0.42%) 25.67s (± 0.18%) +0.19s (+ 0.73%) 25.62s 25.74s p=0.005 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 32.89s (± 0.34%) 33.09s (± 0.27%) +0.21s (+ 0.63%) 33.00s 33.25s p=0.013 n=6
xstate-main - node (v18.15.0, x64)
Errors 5 5 ~ ~ ~ p=1.000 n=6
Symbols 567,041 567,041 ~ ~ ~ p=1.000 n=6
Types 189,889 189,889 ~ ~ ~ p=1.000 n=6
Memory used 497,780k (± 0.02%) 519,637k (± 0.02%) 🔻+21,857k (+ 4.39%) 519,555k 519,800k p=0.005 n=6
Parse Time 3.36s (± 0.81%) 3.37s (± 0.62%) ~ 3.34s 3.40s p=0.570 n=6
Bind Time 1.21s (± 1.10%) 1.20s (± 1.14%) ~ 1.19s 1.23s p=0.323 n=6
Check Time 19.99s (± 0.10%) 19.81s (± 0.38%) -0.18s (- 0.91%) 19.67s 19.88s p=0.004 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 24.56s (± 0.12%) 24.38s (± 0.42%) -0.18s (- 0.75%) 24.21s 24.51s p=0.006 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Compiler-Unions - node (v18.15.0, x64)
  • angular-1 - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-build-src-public-api - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • ts-pre-modules - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate-main - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
Status: Not started
Development

Successfully merging this pull request may close these issues.

3 participants