Skip to content

Cache substitution types #30775

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

Merged
merged 1 commit into from
Apr 5, 2019
Merged

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Apr 5, 2019

This doesn't fully fix anything, per se, but it does reduce the compounding effects in some of our outstanding perf issues a bit. We cache conditional types heavily, but because we failed to cache substitution types (which are manufactured within conditional type true branches), we'd end up making way more conditional type identities than we thought. These not being cached is just an oversight on our part - they're essentially "invisible" intersections, which are already cached.

Fixes #30663.

@@ -31,7 +31,7 @@ class A {
>z : A[]

whereRelated< // Works // Type is same as A1, but is not assignable to type A
>whereRelated : <RF extends RelationFields = RelationFields, N extends "x" | "y" | "z" = "x" | "y" | "z", A1 extends A = RF[N] extends A[] ? RF[N][0] : never, A2 extends A = ShouldA<RF, N>>() => number
Copy link
Member Author

Choose a reason for hiding this comment

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

ShouldA<RF, N> is identical to RF[N] extends A[] ? RF[N][0] : never, and we make the second before the aliased version, so we cache a version with no alias symbol. Previously we'd make two different types because of the substitution in the true branch. :(

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

Sounds good. Any perf numbers or type usage numbers for problematic vs normal projects?

@weswigham
Copy link
Member Author

Normally it just goes down by a few types when there are, eg, multiple Omit definitions in a project's dependency tree.

@sandersn
Copy link
Member

sandersn commented Apr 5, 2019

So is the purpose of this PR completeness/symmetry instead of performance or correctness?

@weswigham
Copy link
Member Author

weswigham commented Apr 5, 2019

No, it's perf - this is a prereq for any other perf fix that relies on correct conditional type caching to really work. It's more like this acts as a multiplier on degenerate perf issues we have. Fixing it doesn't remove the perf issue, but it does shave a few seconds off the 6s to 90s perf regression reported in another issue (though it doesn't bring it back down to 6s). This is a straight improvement - we should have been caching these from the start - it was an oversight on our part; not caching them defeats our other caching layers, which is not the intent at all.

@DanielRosenwasser
Copy link
Member

If this is a perf improvement, can you please post a diff of --extendedDiagnostics on before/after this change?

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

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

but it does shave a few seconds off the 6s to 90s perf regression

What am I missing that would make this possible? The type construction that this short-circuits appears to be really cheap; my intuition would think similar cost to generating the id and looking it up in the map?

@weswigham
Copy link
Member Author

What am I missing that would make this possible? The type construction that this short-circuits appears to be really cheap; my intuition would think similar cost to generating the id and looking it up in the map?

Cacheing the type causes the type to share identity - the type sharing identity causes relationship comparisons to be shared, which otherwise would have been repeated. For deep structures, these comparisons are costly.

@weswigham
Copy link
Member Author

@typescript-bot perf test

@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 5, 2019

Heya @weswigham, I've started to run the perf test suite on this PR at 3fa4fce. You can monitor the build here. It should now contribute to this PR's status checks.

Update: The results are in!

@weswigham
Copy link
Member Author

(Although maybe the bot's perf test won't be the best example and won't show a diff, since it's not really the pathological case; we'll see)

@DanielRosenwasser
Copy link
Member

The type construction that this short-circuits appears to be really cheap; my intuition would think similar cost to generating the id and looking it up in the map?

@andrewbranch Wesley's answer is probably right. In some other cases, lots of allocations of new types means you add GC pressure which leads to heap thrashing. Not sure if that's really the culprit though.

(Although maybe the bot's perf test won't be the best example and won't show a diff, since it's not really the pathological case; we'll see)

@weswigham right I meant the pathological case diff.

@typescript-bot
Copy link
Collaborator

@weswigham
The results of the perf run you requested are in! Here they are:

Comparison Report - master..30775

Metric master 30775 Delta Best Worst
Angular - node (v6.5.0, x64)
Memory used 340,529k (± 0.44%) 340,118k (± 0.44%) -411k (- 0.12%) 338,462k 342,594k
Parse Time 1.56s (± 1.41%) 1.56s (± 1.08%) +0.00s (+ 0.00%) 1.53s 1.60s
Bind Time 1.64s (± 2.02%) 1.63s (± 1.96%) -0.01s (- 0.55%) 1.55s 1.68s
Check Time 4.71s (± 0.51%) 4.71s (± 0.54%) -0.01s (- 0.21%) 4.66s 4.77s
Emit Time 6.40s (± 1.70%) 6.40s (± 1.98%) -0.00s (- 0.03%) 6.24s 6.68s
Total Time 14.31s (± 0.75%) 14.30s (± 0.90%) -0.02s (- 0.13%) 14.10s 14.59s
Monaco - node (v6.5.0, x64)
Memory used 364,241k (± 0.13%) 364,454k (± 0.14%) +212k (+ 0.06%) 363,938k 365,494k
Parse Time 1.25s (± 0.48%) 1.26s (± 0.47%) +0.00s (+ 0.08%) 1.24s 1.27s
Bind Time 1.51s (± 0.73%) 1.51s (± 0.43%) -0.01s (- 0.33%) 1.49s 1.52s
Check Time 5.60s (± 0.68%) 5.55s (± 2.25%) -0.05s (- 0.91%) 5.14s 5.70s
Emit Time 3.55s (± 3.16%) 3.52s (± 3.95%) -0.03s (- 0.79%) 3.13s 3.68s
Total Time 11.92s (± 1.23%) 11.84s (± 2.09%) -0.08s (- 0.67%) 11.05s 12.10s
TFS - node (v6.5.0, x64)
Memory used 320,951k (± 0.00%) 320,960k (± 0.00%) +10k (+ 0.00%) 320,926k 321,001k
Parse Time 0.98s (± 0.49%) 0.98s (± 0.50%) -0.00s (- 0.10%) 0.97s 0.99s
Bind Time 1.26s (± 0.29%) 1.27s (± 0.65%) +0.00s (+ 0.08%) 1.25s 1.28s
Check Time 4.25s (± 0.48%) 4.26s (± 0.54%) +0.02s (+ 0.42%) 4.20s 4.32s
Emit Time 3.13s (± 0.47%) 3.14s (± 0.75%) +0.01s (+ 0.45%) 3.09s 3.19s
Total Time 9.62s (± 0.33%) 9.65s (± 0.33%) +0.03s (+ 0.29%) 9.55s 9.71s
Angular - node (v6.5.0, x86)
Memory used 190,585k (± 0.01%) 190,583k (± 0.01%) -3k (- 0.00%) 190,559k 190,612k
Parse Time 1.45s (± 0.40%) 1.46s (± 0.91%) +0.01s (+ 0.48%) 1.44s 1.50s
Bind Time 1.52s (± 1.31%) 1.52s (± 1.07%) -0.00s (- 0.26%) 1.48s 1.56s
Check Time 4.60s (± 0.38%) 4.67s (± 1.63%) +0.07s (+ 1.54%) 4.57s 4.89s
Emit Time 6.04s (± 0.76%) 6.14s (± 1.81%) +0.10s (+ 1.72%) 5.91s 6.38s
Total Time 13.61s (± 0.44%) 13.79s (± 1.17%) +0.18s (+ 1.33%) 13.53s 14.18s
Monaco - node (v6.5.0, x86)
Memory used 204,214k (± 0.01%) 204,221k (± 0.01%) +7k (+ 0.00%) 204,203k 204,249k
Parse Time 1.26s (± 0.39%) 1.27s (± 0.64%) +0.01s (+ 1.11%) 1.25s 1.28s
Bind Time 1.55s (± 0.34%) 1.56s (± 0.82%) +0.01s (+ 0.58%) 1.54s 1.59s
Check Time 4.52s (± 1.16%) 4.53s (± 1.21%) +0.01s (+ 0.15%) 4.46s 4.74s
Emit Time 3.15s (± 1.67%) 3.17s (± 1.48%) +0.02s (+ 0.79%) 3.00s 3.26s
Total Time 10.48s (± 0.25%) 10.53s (± 0.35%) +0.05s (+ 0.50%) 10.47s 10.61s
TFS - node (v6.5.0, x86)
Memory used 180,260k (± 0.01%) 180,250k (± 0.01%) -9k (- 0.01%) 180,219k 180,282k
Parse Time 0.97s (± 0.70%) 0.98s (± 0.90%) +0.01s (+ 0.51%) 0.97s 1.01s
Bind Time 1.30s (± 0.58%) 1.31s (± 0.58%) +0.00s (+ 0.08%) 1.29s 1.32s
Check Time 3.82s (± 0.77%) 3.82s (± 0.34%) -0.01s (- 0.18%) 3.79s 3.85s
Emit Time 2.57s (± 1.12%) 2.57s (± 0.88%) -0.00s (- 0.04%) 2.52s 2.61s
Total Time 8.67s (± 0.40%) 8.67s (± 0.39%) -0.00s (- 0.03%) 8.57s 8.73s
Angular - node (v8.9.0, x64)
Memory used 329,899k (± 0.02%) 329,916k (± 0.02%) +16k (+ 0.00%) 329,718k 330,027k
Parse Time 1.78s (± 0.27%) 1.78s (± 0.43%) +0.00s (+ 0.11%) 1.77s 1.80s
Bind Time 1.35s (± 0.72%) 1.34s (± 0.60%) -0.01s (- 0.52%) 1.32s 1.36s
Check Time 4.41s (± 1.14%) 4.42s (± 1.37%) +0.01s (+ 0.23%) 4.34s 4.63s
Emit Time 5.90s (± 2.33%) 5.91s (± 2.41%) +0.01s (+ 0.08%) 5.43s 6.08s
Total Time 13.45s (± 0.93%) 13.46s (± 0.82%) +0.01s (+ 0.10%) 13.21s 13.71s
Monaco - node (v8.9.0, x64)
Memory used 358,274k (± 0.02%) 358,240k (± 0.01%) -34k (- 0.01%) 358,121k 358,318k
Parse Time 1.45s (± 0.52%) 1.45s (± 0.40%) 0.00s ( 0.00%) 1.44s 1.46s
Bind Time 1.52s (± 0.98%) 1.52s (± 1.09%) +0.00s (+ 0.20%) 1.50s 1.58s
Check Time 4.72s (± 1.68%) 4.72s (± 2.22%) -0.00s (- 0.08%) 4.55s 4.88s
Emit Time 3.06s (± 5.35%) 3.05s (± 5.39%) -0.00s (- 0.13%) 2.79s 3.29s
Total Time 10.75s (± 0.94%) 10.75s (± 0.73%) -0.00s (- 0.04%) 10.58s 10.93s
TFS - node (v8.9.0, x64)
Memory used 313,686k (± 0.02%) 313,709k (± 0.02%) +22k (+ 0.01%) 313,578k 313,840k
Parse Time 1.13s (± 0.32%) 1.14s (± 0.58%) +0.01s (+ 0.53%) 1.13s 1.15s
Bind Time 1.22s (± 0.74%) 1.23s (± 0.49%) +0.01s (+ 0.49%) 1.21s 1.24s
Check Time 4.19s (± 0.70%) 4.20s (± 0.49%) +0.01s (+ 0.24%) 4.17s 4.26s
Emit Time 3.12s (± 0.88%) 3.14s (± 0.47%) +0.02s (+ 0.48%) 3.11s 3.18s
Total Time 9.67s (± 0.53%) 9.71s (± 0.29%) +0.04s (+ 0.39%) 9.67s 9.79s
Angular - node (v8.9.0, x86)
Memory used 186,736k (± 0.03%) 186,732k (± 0.02%) -4k (- 0.00%) 186,656k 186,836k
Parse Time 1.74s (± 0.66%) 1.73s (± 0.48%) -0.01s (- 0.69%) 1.71s 1.74s
Bind Time 1.52s (± 0.76%) 1.52s (± 0.66%) +0.00s (+ 0.26%) 1.50s 1.55s
Check Time 4.15s (± 0.81%) 4.14s (± 0.67%) -0.00s (- 0.12%) 4.09s 4.22s
Emit Time 5.58s (± 0.97%) 5.66s (± 0.86%) +0.08s (+ 1.42%) 5.55s 5.81s
Total Time 12.98s (± 0.41%) 13.05s (± 0.43%) +0.06s (+ 0.49%) 12.98s 13.19s
Monaco - node (v8.9.0, x86)
Memory used 199,675k (± 0.03%) 199,640k (± 0.02%) -35k (- 0.02%) 199,574k 199,727k
Parse Time 1.50s (± 0.80%) 1.50s (± 0.60%) -0.01s (- 0.53%) 1.48s 1.51s
Bind Time 1.39s (± 0.42%) 1.39s (± 0.42%) +0.01s (+ 0.43%) 1.38s 1.41s
Check Time 4.52s (± 0.74%) 4.49s (± 0.42%) -0.03s (- 0.60%) 4.45s 4.54s
Emit Time 3.09s (± 0.54%) 3.10s (± 0.75%) +0.01s (+ 0.23%) 3.07s 3.17s
Total Time 10.50s (± 0.40%) 10.48s (± 0.28%) -0.02s (- 0.22%) 10.41s 10.54s
TFS - node (v8.9.0, x86)
Memory used 175,772k (± 0.02%) 175,775k (± 0.02%) +3k (+ 0.00%) 175,672k 175,849k
Parse Time 1.18s (± 0.64%) 1.20s (± 0.61%) +0.01s (+ 1.10%) 1.19s 1.22s
Bind Time 1.24s (± 0.87%) 1.24s (± 0.85%) -0.00s (- 0.08%) 1.22s 1.26s
Check Time 4.02s (± 0.72%) 4.01s (± 0.96%) -0.01s (- 0.15%) 3.94s 4.12s
Emit Time 2.76s (± 1.20%) 2.76s (± 1.13%) -0.01s (- 0.25%) 2.70s 2.86s
Total Time 9.21s (± 0.38%) 9.21s (± 0.39%) +0.00s (+ 0.01%) 9.13s 9.29s
Angular - node (v9.0.0, x64)
Memory used 329,696k (± 0.02%) 329,676k (± 0.02%) -20k (- 0.01%) 329,508k 329,777k
Parse Time 1.63s (± 0.34%) 1.62s (± 0.62%) -0.00s (- 0.31%) 1.60s 1.65s
Bind Time 1.33s (± 0.77%) 1.33s (± 0.42%) -0.00s (- 0.23%) 1.32s 1.34s
Check Time 4.20s (± 0.55%) 4.26s (± 1.35%) +0.05s (+ 1.21%) 4.19s 4.46s
Emit Time 5.80s (± 1.89%) 5.78s (± 2.71%) -0.02s (- 0.41%) 5.35s 6.02s
Total Time 12.96s (± 0.98%) 12.98s (± 1.09%) +0.02s (+ 0.17%) 12.69s 13.20s
Monaco - node (v9.0.0, x64)
Memory used 357,987k (± 0.02%) 357,957k (± 0.01%) -31k (- 0.01%) 357,851k 358,048k
Parse Time 1.29s (± 0.45%) 1.29s (± 0.45%) +0.00s (+ 0.23%) 1.28s 1.30s
Bind Time 1.51s (± 0.63%) 1.51s (± 0.38%) -0.01s (- 0.46%) 1.50s 1.52s
Check Time 4.58s (± 0.39%) 4.57s (± 0.25%) -0.01s (- 0.22%) 4.54s 4.59s
Emit Time 3.22s (± 0.32%) 3.23s (± 0.35%) +0.00s (+ 0.12%) 3.19s 3.25s
Total Time 10.60s (± 0.24%) 10.59s (± 0.19%) -0.01s (- 0.11%) 10.55s 10.64s
TFS - node (v9.0.0, x64)
Memory used 313,670k (± 0.01%) 313,631k (± 0.01%) -39k (- 0.01%) 313,544k 313,725k
Parse Time 1.01s (± 0.49%) 1.01s (± 0.47%) -0.00s (- 0.39%) 1.00s 1.02s
Bind Time 1.21s (± 0.43%) 1.20s (± 0.69%) -0.00s (- 0.33%) 1.19s 1.22s
Check Time 4.09s (± 1.38%) 4.05s (± 0.37%) -0.04s (- 0.93%) 4.02s 4.08s
Emit Time 3.03s (± 1.93%) 3.09s (± 0.61%) +0.06s (+ 1.98%) 3.05s 3.13s
Total Time 9.33s (± 0.26%) 9.35s (± 0.38%) +0.02s (+ 0.20%) 9.29s 9.43s
Angular - node (v9.0.0, x86)
Memory used 186,905k (± 0.02%) 186,877k (± 0.03%) -28k (- 0.01%) 186,763k 186,976k
Parse Time 1.56s (± 1.22%) 1.55s (± 0.72%) -0.01s (- 0.77%) 1.52s 1.57s
Bind Time 1.50s (± 0.32%) 1.50s (± 0.97%) +0.00s (+ 0.13%) 1.47s 1.55s
Check Time 3.90s (± 0.81%) 3.90s (± 0.47%) +0.00s (+ 0.05%) 3.86s 3.95s
Emit Time 5.26s (± 0.93%) 5.27s (± 0.51%) +0.01s (+ 0.15%) 5.21s 5.33s
Total Time 12.23s (± 0.62%) 12.23s (± 0.45%) +0.00s (+ 0.01%) 12.13s 12.37s
Monaco - node (v9.0.0, x86)
Memory used 199,719k (± 0.02%) 199,691k (± 0.02%) -28k (- 0.01%) 199,591k 199,741k
Parse Time 1.32s (± 0.39%) 1.32s (± 0.81%) +0.00s (+ 0.15%) 1.30s 1.35s
Bind Time 1.35s (± 0.48%) 1.36s (± 0.64%) +0.01s (+ 0.44%) 1.34s 1.38s
Check Time 4.39s (± 0.37%) 4.38s (± 0.51%) -0.00s (- 0.09%) 4.34s 4.44s
Emit Time 3.02s (± 0.78%) 3.02s (± 0.63%) -0.00s (- 0.17%) 2.96s 3.05s
Total Time 10.08s (± 0.29%) 10.08s (± 0.27%) -0.00s (- 0.04%) 10.02s 10.13s
TFS - node (v9.0.0, x86)
Memory used 175,910k (± 0.02%) 175,907k (± 0.03%) -3k (- 0.00%) 175,759k 176,014k
Parse Time 1.03s (± 0.74%) 1.04s (± 0.64%) +0.00s (+ 0.19%) 1.02s 1.05s
Bind Time 1.21s (± 0.73%) 1.22s (± 0.56%) +0.00s (+ 0.08%) 1.20s 1.23s
Check Time 3.82s (± 0.60%) 3.80s (± 0.41%) -0.02s (- 0.55%) 3.77s 3.85s
Emit Time 2.71s (± 1.46%) 2.70s (± 1.01%) -0.01s (- 0.41%) 2.63s 2.76s
Total Time 8.79s (± 0.47%) 8.75s (± 0.40%) -0.04s (- 0.40%) 8.65s 8.81s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-142-generic
Architecturex64
Available Memory16 GB
Available Memory1 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v6.5.0, x64)
  • node (v6.5.0, x86)
  • node (v8.9.0, x64)
  • node (v8.9.0, x86)
  • node (v9.0.0, x64)
  • node (v9.0.0, x86)
Scenarios
  • Angular - node (v6.5.0, x64)
  • Angular - node (v6.5.0, x86)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Angular - node (v9.0.0, x64)
  • Angular - node (v9.0.0, x86)
  • Monaco - node (v6.5.0, x64)
  • Monaco - node (v6.5.0, x86)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • Monaco - node (v9.0.0, x64)
  • Monaco - node (v9.0.0, x86)
  • TFS - node (v6.5.0, x64)
  • TFS - node (v6.5.0, x86)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
  • TFS - node (v9.0.0, x64)
  • TFS - node (v9.0.0, x86)
Benchmark Name Iterations
Current 30775 10
Baseline master 10

@weswigham
Copy link
Member Author

Whoa, so apparently I lied. This is the fix for #30663. With this alone:
typescript v3.4.2:

Files:             101
Lines:           86511
Nodes:          262886
Identifiers:     84384
Symbols:        260566
Types:          570329
Memory used:   285626K
I/O Read time:   0.04s
Parse time:      0.53s
Program time:    0.69s
Bind time:       0.47s
Check time:     80.80s
Total time:     81.97s

this PR + master:

Files:             101
Lines:           86516
Nodes:          262906
Identifiers:     84392
Symbols:        111297
Types:           57067
Memory used:   169304K
I/O Read time:   0.03s
Parse time:      0.55s
Program time:    0.70s
Bind time:       0.52s
Check time:      1.16s
Total time:      2.38s

for some reason I thought I still had other things that were needed to fix this but I guess not :shipit:

@weswigham weswigham merged commit c1f2aba into microsoft:master Apr 5, 2019
@weswigham weswigham deleted the substitution-cacheing branch April 5, 2019 21:37
@weswigham
Copy link
Member Author

weswigham commented Apr 5, 2019

OK! There was more that was needed alongside this to fix release-3.4 - cherry picking this into 3.4 gives the result I was expecting:

Files:             101
Lines:           86511
Nodes:          262886
Identifiers:     84384
Symbols:        260540
Types:          564009
Memory used:   309474K
I/O Read time:   0.03s
Parse time:      0.53s
Program time:    0.69s
Bind time:       0.50s
Check time:     65.67s
Total time:     66.85s

which is an improvement, but not a fix. Yet... it is fixed in master (without this PR, even). One of our other post-3.4 changes happens to fix the styled-components perf issue fully.

@ulrichb
Copy link

ulrichb commented Apr 6, 2019

@weswigham I saw that you didn't push the cherry-pick for 3.4. Is it planned to release this improvement with 3.4.3?

@weswigham
Copy link
Member Author

weswigham commented Apr 6, 2019

Well, this is a significant improvement for 3.4 - 90s down to 70s is notable; but it's not the order-of-magnitude improvement master currently is with the full fix. I spoke with @RyanCavanaugh and we're presently not too inclined to port what's only a partial fix to 3.4 (esp. when we have the full fix available and know we can't port it - it's #30637).

Maybe we'll reconsider, but since @types/styled-components has had the types that caused the perf issue removed and typescript@next is fully fixed, we're not really inclined to port a partial fix from what I can tell.

@ulrichb
Copy link

ulrichb commented Apr 6, 2019

Hmm.. In WebStorm I still have an ~8 sec lag after every code change before the language service finishes and the updated squiggles appear. (With the @types/styled-components fix; before it didn't finish at all.) ... So I would be happy with a partial fix reducing these 8 secs.

BTW: I can confirm that typescript@next greatly improves the performance (mentioned lag is ~ 2 sec).

weswigham added a commit to weswigham/TypeScript that referenced this pull request Apr 12, 2019
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.

3.4.1 tsc works 20! times slower than 3.3.4
6 participants