Skip to content

Make export-module and reference maps invertible #44402

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 6 commits into from
Jun 17, 2021

Conversation

amcasey
Copy link
Member

@amcasey amcasey commented Jun 2, 2021

Right now, we're enumerating all the entries to find out which keys map
to a corresponding value. By maintaining a two-way map, we can convert
this linear search into a map lookup and skip allocation of many, many
iterator results.

@typescript-bot typescript-bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Jun 2, 2021
@amcasey
Copy link
Member Author

amcasey commented Jun 2, 2021

The code's a bit rough, but I thought I should post something before our discussion. I'll add perf numbers shortly.

@amcasey
Copy link
Member Author

amcasey commented Jun 3, 2021

For a small fraction of the original repro

Before:

Duration: 141.75s, Total samples = 138099ms (97.43%)
Showing nodes accounting for 126840ms, 91.85% of 138099ms total
Dropped 2840 nodes (cum <= 690.50ms)
      flat  flat%   sum%        cum   cum%
   28741ms 20.81% 20.81%    28974ms 20.98%  (anonymous) e:\ts_gh\built\local\tsc.js:113326
   26903ms 19.48% 40.29%    97402ms 70.53%  forEachFileAndExportsOfFile e:\ts_gh\built\local\tsc.js:113307
   24543ms 17.77% 58.06%    24550ms 17.78%  (anonymous) e:\ts_gh\built\local\tsc.js:113334
   20966ms 15.18% 73.25%    20966ms 15.18%  (garbage collector)
   16251ms 11.77% 85.01%    95676ms 69.28%  (anonymous) e:\ts_gh\built\local\tsc.js:113318

(The anonymous functions are the lambdas in forEachFileAndExportsOfFile)

After

Duration: 21.43s, Total samples = 20772ms (96.91%)
Showing nodes accounting for 14223ms, 68.47% of 20772ms total
Dropped 2475 nodes (cum <= 103.86ms)
      flat  flat%   sum%        cum   cum%
    1998ms  9.62%  9.62%     1998ms  9.62%  mark perf_hooks.js:391
    1094ms  5.27% 14.89%     1094ms  5.27%  measure perf_hooks.js:397
     969ms  4.66% 19.55%      969ms  4.66%  (garbage collector)
     922ms  4.44% 23.99%      922ms  4.44%  stat
     642ms  3.09% 27.08%     2125ms 10.23%  createUnionOrIntersectionProperty e:\ts_gh\built\local\tsc.js:55535

@amcasey
Copy link
Member Author

amcasey commented Jun 3, 2021

To validate, I traced the path argument to every forEachFileAndExportsOfFile call and the same calls were made in the same order.

@amcasey
Copy link
Member Author

amcasey commented Jun 3, 2021

Force push is a rebase.

@amcasey
Copy link
Member Author

amcasey commented Jun 3, 2021

@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 3, 2021

Heya @amcasey, I've started to run the perf test suite on this PR at eef8705. You can monitor the build here.

Update: The results are in!

@amcasey
Copy link
Member Author

amcasey commented Jun 3, 2021

I'm pretty sure we have no perf suite coverage of the builder, but why not?

@@ -546,70 +549,59 @@ namespace ts {
}

Debug.assert(!!state.currentAffectedFilesExportedModulesMap);

const seenFileAndExportsOfFile = new Set<string>();
Copy link
Member Author

Choose a reason for hiding this comment

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

Separate PR: @sheetalkamat can we lift this out a couple levels so we don't revisit the same paths repeatedly for different "affected" files?

Copy link
Member Author

Choose a reason for hiding this comment

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

Or maybe it belongs on the state?

Copy link
Member Author

Choose a reason for hiding this comment

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

To share it across more than one affected file, it would have to be on the state. I'm going to try updating it in parallel with seenAffectedFiles.

Copy link
Member Author

Choose a reason for hiding this comment

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

Assuming I've done it correctly, it saves about 10% of total time. Nothing to complain about, but much less than this change.

forEachEntry(state.exportedModulesMap, (exportedModules, exportedFromPath) =>
!state.currentAffectedFilesExportedModulesMap!.has(exportedFromPath) && // If we already iterated this through cache, ignore it
exportedModules.has(affectedFile.resolvedPath) &&
state.exportedModulesMap.getKeys(affectedFile.resolvedPath)?.forEach(exportedFromPath =>
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 couldn't find a place where exportedModulesMap was consumed "forward", but it's maintained forward and I couldn't see a way to reverse the meaning without making maintenance (specifically, deleting paths) really expensive.

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - master..44402

Metric master 44402 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 343,935k (± 0.03%) 344,034k (± 0.02%) +99k (+ 0.03%) 343,822k 344,134k
Parse Time 1.79s (± 0.25%) 1.79s (± 0.42%) +0.01s (+ 0.39%) 1.77s 1.81s
Bind Time 0.84s (± 0.69%) 0.84s (± 0.71%) -0.00s (- 0.12%) 0.82s 0.85s
Check Time 5.18s (± 0.36%) 5.22s (± 0.51%) +0.04s (+ 0.71%) 5.16s 5.27s
Emit Time 5.47s (± 0.58%) 5.47s (± 0.64%) +0.00s (+ 0.07%) 5.39s 5.55s
Total Time 13.28s (± 0.35%) 13.32s (± 0.44%) +0.04s (+ 0.32%) 13.22s 13.45s
Compiler-Unions - node (v10.16.3, x64)
Memory used 200,424k (± 0.06%) 200,484k (± 0.06%) +60k (+ 0.03%) 200,043k 200,694k
Parse Time 0.78s (± 0.77%) 0.78s (± 0.64%) -0.00s (- 0.13%) 0.77s 0.79s
Bind Time 0.53s (± 1.44%) 0.53s (± 1.23%) +0.00s (+ 0.38%) 0.51s 0.54s
Check Time 7.55s (± 0.60%) 7.52s (± 0.57%) -0.03s (- 0.37%) 7.45s 7.58s
Emit Time 2.27s (± 0.85%) 2.26s (± 1.36%) -0.01s (- 0.53%) 2.20s 2.33s
Total Time 11.12s (± 0.50%) 11.08s (± 0.45%) -0.04s (- 0.33%) 10.96s 11.21s
Monaco - node (v10.16.3, x64)
Memory used 340,462k (± 0.02%) 340,495k (± 0.01%) +33k (+ 0.01%) 340,359k 340,591k
Parse Time 1.44s (± 0.79%) 1.45s (± 0.92%) +0.00s (+ 0.28%) 1.41s 1.47s
Bind Time 0.74s (± 0.70%) 0.74s (± 0.95%) 0.00s ( 0.00%) 0.73s 0.75s
Check Time 5.33s (± 0.62%) 5.37s (± 0.64%) +0.04s (+ 0.75%) 5.26s 5.45s
Emit Time 2.96s (± 1.09%) 2.96s (± 1.06%) -0.00s (- 0.03%) 2.90s 3.06s
Total Time 10.48s (± 0.34%) 10.52s (± 0.40%) +0.05s (+ 0.45%) 10.42s 10.63s
TFS - node (v10.16.3, x64)
Memory used 304,041k (± 0.02%) 304,048k (± 0.03%) +7k (+ 0.00%) 303,865k 304,266k
Parse Time 1.18s (± 0.47%) 1.18s (± 0.63%) -0.00s (- 0.08%) 1.17s 1.20s
Bind Time 0.70s (± 0.83%) 0.70s (± 0.53%) +0.00s (+ 0.28%) 0.70s 0.71s
Check Time 4.85s (± 0.46%) 4.86s (± 0.39%) +0.01s (+ 0.25%) 4.81s 4.88s
Emit Time 3.04s (± 1.03%) 3.04s (± 0.39%) +0.01s (+ 0.20%) 3.02s 3.06s
Total Time 9.76s (± 0.51%) 9.78s (± 0.28%) +0.02s (+ 0.20%) 9.72s 9.84s
material-ui - node (v10.16.3, x64)
Memory used 471,636k (± 0.02%) 473,963k (± 0.01%) +2,327k (+ 0.49%) 473,900k 474,065k
Parse Time 1.72s (± 0.27%) 1.72s (± 0.62%) +0.00s (+ 0.06%) 1.71s 1.76s
Bind Time 0.66s (± 0.87%) 0.66s (± 0.74%) +0.00s (+ 0.61%) 0.66s 0.68s
Check Time 14.22s (± 0.59%) 14.95s (± 0.23%) +0.73s (+ 5.13%) 14.86s 15.01s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 16.60s (± 0.51%) 17.33s (± 0.19%) +0.73s (+ 4.43%) 17.25s 17.39s
Angular - node (v12.1.0, x64)
Memory used 322,171k (± 0.02%) 322,201k (± 0.02%) +29k (+ 0.01%) 322,090k 322,338k
Parse Time 1.77s (± 0.53%) 1.78s (± 0.84%) +0.01s (+ 0.34%) 1.75s 1.82s
Bind Time 0.83s (± 0.97%) 0.83s (± 0.67%) -0.00s (- 0.00%) 0.82s 0.84s
Check Time 5.07s (± 0.41%) 5.11s (± 0.53%) +0.04s (+ 0.83%) 5.06s 5.16s
Emit Time 5.65s (± 0.63%) 5.65s (± 0.66%) 0.00s ( 0.00%) 5.58s 5.77s
Total Time 13.32s (± 0.38%) 13.37s (± 0.41%) +0.05s (+ 0.36%) 13.27s 13.51s
Compiler-Unions - node (v12.1.0, x64)
Memory used 187,842k (± 0.07%) 187,906k (± 0.06%) +65k (+ 0.03%) 187,487k 188,051k
Parse Time 0.77s (± 0.61%) 0.77s (± 0.86%) +0.00s (+ 0.39%) 0.76s 0.79s
Bind Time 0.53s (± 1.13%) 0.53s (± 1.27%) +0.00s (+ 0.19%) 0.52s 0.55s
Check Time 7.00s (± 0.51%) 7.02s (± 0.58%) +0.02s (+ 0.27%) 6.96s 7.14s
Emit Time 2.23s (± 0.58%) 2.23s (± 0.81%) -0.00s (- 0.22%) 2.18s 2.25s
Total Time 10.52s (± 0.37%) 10.55s (± 0.48%) +0.03s (+ 0.26%) 10.49s 10.72s
Monaco - node (v12.1.0, x64)
Memory used 323,452k (± 0.02%) 323,530k (± 0.03%) +78k (+ 0.02%) 323,417k 323,815k
Parse Time 1.41s (± 0.54%) 1.42s (± 0.65%) +0.00s (+ 0.28%) 1.40s 1.44s
Bind Time 0.72s (± 0.93%) 0.71s (± 0.94%) -0.00s (- 0.56%) 0.70s 0.73s
Check Time 5.20s (± 0.47%) 5.19s (± 0.46%) -0.01s (- 0.19%) 5.14s 5.25s
Emit Time 2.99s (± 0.43%) 2.99s (± 0.66%) -0.00s (- 0.03%) 2.96s 3.05s
Total Time 10.33s (± 0.32%) 10.31s (± 0.33%) -0.01s (- 0.13%) 10.23s 10.42s
TFS - node (v12.1.0, x64)
Memory used 288,599k (± 0.02%) 288,685k (± 0.02%) +85k (+ 0.03%) 288,580k 288,846k
Parse Time 1.18s (± 0.69%) 1.19s (± 0.58%) +0.00s (+ 0.17%) 1.17s 1.20s
Bind Time 0.70s (± 2.30%) 0.69s (± 0.81%) -0.01s (- 1.57%) 0.68s 0.70s
Check Time 4.78s (± 0.48%) 4.77s (± 0.51%) -0.01s (- 0.23%) 4.72s 4.84s
Emit Time 3.12s (± 0.59%) 3.09s (± 0.46%) -0.02s (- 0.80%) 3.07s 3.13s
Total Time 9.78s (± 0.46%) 9.74s (± 0.35%) -0.05s (- 0.48%) 9.70s 9.84s
material-ui - node (v12.1.0, x64)
Memory used 450,177k (± 0.06%) 452,639k (± 0.05%) +2,463k (+ 0.55%) 451,675k 452,832k
Parse Time 1.71s (± 0.23%) 1.72s (± 0.55%) +0.00s (+ 0.29%) 1.70s 1.74s
Bind Time 0.63s (± 0.57%) 0.64s (± 1.10%) +0.01s (+ 0.79%) 0.63s 0.66s
Check Time 12.74s (± 0.53%) 13.50s (± 0.73%) +0.76s (+ 5.99%) 13.35s 13.79s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 15.09s (± 0.48%) 15.86s (± 0.64%) +0.77s (+ 5.10%) 15.69s 16.15s
Angular - node (v14.15.1, x64)
Memory used 320,917k (± 0.01%) 320,951k (± 0.00%) +33k (+ 0.01%) 320,912k 320,984k
Parse Time 1.78s (± 0.26%) 1.80s (± 0.95%) +0.02s (+ 1.18%) 1.77s 1.85s
Bind Time 0.87s (± 0.57%) 0.87s (± 0.54%) +0.00s (+ 0.46%) 0.86s 0.88s
Check Time 5.08s (± 0.27%) 5.12s (± 0.43%) +0.04s (+ 0.89%) 5.08s 5.17s
Emit Time 5.71s (± 0.58%) 5.73s (± 0.74%) +0.02s (+ 0.37%) 5.65s 5.83s
Total Time 13.43s (± 0.32%) 13.52s (± 0.42%) +0.09s (+ 0.68%) 13.45s 13.68s
Compiler-Unions - node (v14.15.1, x64)
Memory used 188,442k (± 0.67%) 188,886k (± 0.58%) +444k (+ 0.24%) 186,619k 189,947k
Parse Time 0.80s (± 0.37%) 0.81s (± 0.46%) +0.00s (+ 0.37%) 0.80s 0.81s
Bind Time 0.55s (± 0.66%) 0.56s (± 0.85%) +0.00s (+ 0.54%) 0.55s 0.57s
Check Time 7.14s (± 0.59%) 7.14s (± 0.49%) -0.00s (- 0.01%) 7.05s 7.19s
Emit Time 2.26s (± 1.27%) 2.26s (± 0.92%) -0.01s (- 0.27%) 2.22s 2.32s
Total Time 10.76s (± 0.51%) 10.76s (± 0.48%) -0.01s (- 0.06%) 10.62s 10.82s
Monaco - node (v14.15.1, x64)
Memory used 322,517k (± 0.01%) 322,551k (± 0.01%) +34k (+ 0.01%) 322,513k 322,605k
Parse Time 1.46s (± 0.51%) 1.46s (± 0.83%) +0.00s (+ 0.14%) 1.45s 1.50s
Bind Time 0.74s (± 0.46%) 0.75s (± 0.78%) +0.00s (+ 0.54%) 0.74s 0.76s
Check Time 5.17s (± 0.23%) 5.19s (± 0.56%) +0.02s (+ 0.29%) 5.13s 5.24s
Emit Time 3.07s (± 0.58%) 3.06s (± 0.67%) -0.01s (- 0.23%) 3.03s 3.11s
Total Time 10.45s (± 0.26%) 10.46s (± 0.47%) +0.01s (+ 0.11%) 10.37s 10.57s
TFS - node (v14.15.1, x64)
Memory used 287,631k (± 0.00%) 287,685k (± 0.01%) +54k (+ 0.02%) 287,617k 287,720k
Parse Time 1.24s (± 0.97%) 1.25s (± 1.46%) +0.01s (+ 0.56%) 1.22s 1.31s
Bind Time 0.71s (± 0.87%) 0.71s (± 0.91%) +0.00s (+ 0.14%) 0.70s 0.73s
Check Time 4.80s (± 0.40%) 4.82s (± 0.55%) +0.02s (+ 0.37%) 4.77s 4.90s
Emit Time 3.23s (± 1.03%) 3.21s (± 0.66%) -0.03s (- 0.84%) 3.16s 3.26s
Total Time 9.99s (± 0.43%) 9.98s (± 0.42%) -0.00s (- 0.03%) 9.90s 10.06s
material-ui - node (v14.15.1, x64)
Memory used 448,641k (± 0.00%) 450,934k (± 0.05%) +2,293k (+ 0.51%) 449,950k 451,111k
Parse Time 1.74s (± 0.42%) 1.75s (± 1.07%) +0.01s (+ 0.81%) 1.72s 1.81s
Bind Time 0.69s (± 0.58%) 0.69s (± 0.69%) -0.00s (- 0.58%) 0.68s 0.70s
Check Time 12.93s (± 0.62%) 13.70s (± 0.74%) +0.78s (+ 6.01%) 13.53s 13.97s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 15.36s (± 0.54%) 16.14s (± 0.69%) +0.79s (+ 5.13%) 15.97s 16.46s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-206-generic
Architecturex64
Available Memory16 GB
Available Memory1 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v14.15.1, x64)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v14.15.1, x64)
  • Compiler-Unions - node (v10.16.3, x64)
  • Compiler-Unions - node (v12.1.0, x64)
  • Compiler-Unions - node (v14.15.1, x64)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v14.15.1, x64)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v14.15.1, x64)
  • material-ui - node (v10.16.3, x64)
  • material-ui - node (v12.1.0, x64)
  • material-ui - node (v14.15.1, x64)
Benchmark Name Iterations
Current 44402 10
Baseline master 10

Developer Information:

Download Benchmark

@amcasey
Copy link
Member Author

amcasey commented Jun 3, 2021

I claim the material-ui check time regression is from another change because the builder (which I don't believe runs in that perf test) doesn't count towards check time.

@dmichon-msft
Copy link
Contributor

@amcasey, if you want a project that has egregious issues with builder performance, we have one that repros issues fairly regularly (I've seen >30 minutes spent in the stage of determining what files are affected before). I expect it is largely due to the ~2500 files that are in a circular dependency snarl.

@amcasey
Copy link
Member Author

amcasey commented Jun 3, 2021

@typescript-bot pack this

@amcasey
Copy link
Member Author

amcasey commented Jun 3, 2021

@dmichon-msft Cool! Do you mind giving it a spin? You'll probably want to set "strictOptionalProperties": false for now.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 3, 2021

Heya @amcasey, I've started to run the tarball bundle task on this PR at d8d8169. You can monitor the build here.

amcasey added 3 commits June 11, 2021 14:56
Right now, we're enumerating all the entries to find out which keys map
to a corresponding value.  By maintaining a two-way map, we can convert
this linear search into a map lookup and skip allocation of many, many
iterator results.
@amcasey
Copy link
Member Author

amcasey commented Jun 11, 2021

Force push is a rebase.

@amcasey
Copy link
Member Author

amcasey commented Jun 17, 2021

I've re-verified that a trace of the traversals matches the pre-change version.

@amcasey amcasey merged commit 9549928 into microsoft:main Jun 17, 2021
@amcasey amcasey deleted the TwoWayMap branch June 17, 2021 18:06
@@ -311,7 +313,7 @@ namespace ts {
newState.affectedFilesIndex = state.affectedFilesIndex;
newState.currentChangedFilePath = state.currentChangedFilePath;
newState.currentAffectedFilesSignatures = state.currentAffectedFilesSignatures && new Map(state.currentAffectedFilesSignatures);
newState.currentAffectedFilesExportedModulesMap = state.currentAffectedFilesExportedModulesMap && new Map(state.currentAffectedFilesExportedModulesMap);
Copy link
Member Author

Choose a reason for hiding this comment

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

@andrewbranch I retained the existing behavior but, now that I look at it, it seems wrong. The value type of this map is a set - doesn't that mean that the new and old maps will refer to (and modify) the same sets? It seems like the intention was probably to do a deep copy.

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

Successfully merging this pull request may close these issues.

6 participants