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

Merge diagnosticsProducing and nonDiagnosticsProducing checkers into a single checker supporting lazy diagnostics #36747

Merged
merged 5 commits into from
Mar 23, 2022

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Feb 12, 2020

A more complete alternative to #28584 based on the discussions there.

Rather than optimistically using an existing checker, we choose to only ever produce a single checker. That checker is responsible for both collecting diagnostics, and responding to LS queries. It does this (hopefully efficiently) by deferring calculating diagnostics for any nodes it visited during LS operations until they are later requested. This allows results from a "full typecheck" (or getErr request) to then inform a following completions or quickinfo request, without needing to recalculate anything that's already been calculated. Plus, we no longer need to hold onto 2 checkers in services, which should commensurately lower services memory usage.

To be as minimally breaky as possible, in situations where we know we're about to fetch diagnostics, we produce the diagnostics as they're registered, in order to preserve existing union ordering (as union order is based upon order of discovery, which may change if diagnostic production is fully unconditionally deferred until after checking is complete). This means command-line compiler runs before and after this PR should be identical (as nothing has changed when it executes). What is deferred is any diagnostics we produce while doing LS operations in the checker before we request diagnostics. These lazy diagnostic requests are backlogged until a diagnostic (or suggestion) request is made, at which point they are executed and produced. This means that errors made via the IDE might have different union ordering in their types than errors made on the command line (if you have prior LS results executed that caused a partial load of other types in a different order). But that's likely a fine tradeoff to make; especially since the order already differed depending on how files were included/checked in the IDE, anyway.

Do note: Only diagnostics which depended upon the old produceDiagnostics checker flag become lazy in this PR - further work should probably be applied to make more diagnostics lazy, as there are undoubtedly heaps of other diagnostic code that was unconditionally done, which could probably be made lazy to improve LS performance slightly.

Tl;DR: With this change, there can be only one checker. Use addLazyDiagnostic to register diagnostic-specific work in the checker.

Fixes #27997

…a single checker supporting lazy diagnostics
@weswigham
Copy link
Member Author

I don't expect any command-line type changes, so the following should all duplicate master's current state:

@typescript-bot perf test this
@typescript-bot test this
@typescript-bot run dt
@typescript-bot user test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 12, 2020

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 12, 2020

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 12, 2020

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 12, 2020

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - master..36747

Metric master 36747 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 359,212k (± 0.02%) 358,494k (± 0.04%) -718k (- 0.20%) 358,095k 358,694k
Parse Time 1.63s (± 0.36%) 1.62s (± 0.55%) -0.00s (- 0.12%) 1.61s 1.64s
Bind Time 0.88s (± 1.07%) 0.88s (± 1.08%) +0.00s (+ 0.11%) 0.86s 0.90s
Check Time 4.65s (± 0.42%) 4.68s (± 0.69%) +0.03s (+ 0.65%) 4.59s 4.73s
Emit Time 5.20s (± 0.66%) 5.23s (± 0.63%) +0.03s (+ 0.62%) 5.17s 5.30s
Total Time 12.36s (± 0.34%) 12.42s (± 0.52%) +0.06s (+ 0.52%) 12.30s 12.56s
Monaco - node (v10.16.3, x64)
Memory used 364,651k (± 0.01%) 364,628k (± 0.02%) -23k (- 0.01%) 364,464k 364,781k
Parse Time 1.25s (± 0.71%) 1.25s (± 0.79%) -0.01s (- 0.48%) 1.23s 1.28s
Bind Time 0.78s (± 0.63%) 0.78s (± 0.47%) 0.00s ( 0.00%) 0.77s 0.78s
Check Time 4.68s (± 0.38%) 4.72s (± 0.51%) +0.05s (+ 0.98%) 4.68s 4.78s
Emit Time 2.87s (± 0.74%) 2.90s (± 0.56%) +0.03s (+ 1.15%) 2.87s 2.93s
Total Time 9.58s (± 0.34%) 9.65s (± 0.33%) +0.07s (+ 0.75%) 9.59s 9.70s
TFS - node (v10.16.3, x64)
Memory used 324,193k (± 0.03%) 324,156k (± 0.01%) -36k (- 0.01%) 324,020k 324,235k
Parse Time 0.95s (± 0.55%) 0.95s (± 0.82%) -0.00s (- 0.00%) 0.93s 0.97s
Bind Time 0.74s (± 1.28%) 0.74s (± 0.95%) +0.00s (+ 0.27%) 0.72s 0.75s
Check Time 4.22s (± 0.55%) 4.26s (± 0.49%) +0.04s (+ 1.07%) 4.22s 4.30s
Emit Time 3.00s (± 1.02%) 3.01s (± 0.95%) +0.01s (+ 0.40%) 2.94s 3.08s
Total Time 8.90s (± 0.54%) 8.96s (± 0.46%) +0.06s (+ 0.69%) 8.87s 9.05s
Angular - node (v12.1.0, x64)
Memory used 334,863k (± 0.02%) 334,223k (± 0.05%) -640k (- 0.19%) 333,549k 334,365k
Parse Time 1.58s (± 0.70%) 1.57s (± 0.49%) -0.01s (- 0.95%) 1.54s 1.58s
Bind Time 0.87s (± 0.81%) 0.87s (± 0.66%) +0.00s (+ 0.12%) 0.86s 0.88s
Check Time 4.57s (± 0.51%) 4.60s (± 0.45%) +0.02s (+ 0.52%) 4.56s 4.65s
Emit Time 5.36s (± 0.86%) 5.39s (± 0.67%) +0.03s (+ 0.52%) 5.33s 5.52s
Total Time 12.39s (± 0.47%) 12.42s (± 0.40%) +0.03s (+ 0.28%) 12.36s 12.60s
Monaco - node (v12.1.0, x64)
Memory used 344,581k (± 0.01%) 344,509k (± 0.01%) -71k (- 0.02%) 344,367k 344,570k
Parse Time 1.22s (± 0.60%) 1.21s (± 0.67%) -0.00s (- 0.41%) 1.20s 1.24s
Bind Time 0.75s (± 1.17%) 0.75s (± 0.53%) -0.00s (- 0.13%) 0.74s 0.76s
Check Time 4.54s (± 0.45%) 4.57s (± 0.54%) +0.03s (+ 0.73%) 4.49s 4.61s
Emit Time 2.95s (± 0.56%) 2.95s (± 0.84%) -0.00s (- 0.14%) 2.89s 3.02s
Total Time 9.45s (± 0.35%) 9.48s (± 0.44%) +0.02s (+ 0.24%) 9.39s 9.57s
TFS - node (v12.1.0, x64)
Memory used 306,431k (± 0.02%) 306,451k (± 0.02%) +19k (+ 0.01%) 306,339k 306,566k
Parse Time 0.94s (± 0.61%) 0.93s (± 0.73%) -0.01s (- 0.53%) 0.92s 0.95s
Bind Time 0.70s (± 1.17%) 0.70s (± 1.20%) -0.00s (- 0.43%) 0.69s 0.73s
Check Time 4.16s (± 0.46%) 4.19s (± 0.59%) +0.03s (+ 0.82%) 4.15s 4.27s
Emit Time 3.05s (± 1.27%) 3.07s (± 0.57%) +0.01s (+ 0.43%) 3.02s 3.10s
Total Time 8.86s (± 0.47%) 8.90s (± 0.37%) +0.04s (+ 0.46%) 8.83s 8.97s
Angular - node (v8.9.0, x64)
Memory used 354,068k (± 0.01%) 353,451k (± 0.01%) -617k (- 0.17%) 353,352k 353,558k
Parse Time 2.13s (± 0.69%) 2.12s (± 0.25%) -0.01s (- 0.47%) 2.11s 2.13s
Bind Time 0.93s (± 1.08%) 0.94s (± 0.85%) +0.00s (+ 0.43%) 0.93s 0.96s
Check Time 5.42s (± 0.50%) 5.49s (± 0.73%) +0.07s (+ 1.24%) 5.39s 5.55s
Emit Time 6.23s (± 0.66%) 6.26s (± 0.61%) +0.03s (+ 0.55%) 6.19s 6.34s
Total Time 14.72s (± 0.35%) 14.81s (± 0.47%) +0.09s (+ 0.65%) 14.65s 14.92s
Monaco - node (v8.9.0, x64)
Memory used 362,949k (± 0.01%) 362,960k (± 0.01%) +10k (+ 0.00%) 362,881k 363,012k
Parse Time 1.56s (± 0.48%) 1.56s (± 0.40%) -0.01s (- 0.32%) 1.55s 1.57s
Bind Time 0.95s (± 0.38%) 0.95s (± 0.74%) +0.00s (+ 0.32%) 0.94s 0.97s
Check Time 5.39s (± 1.60%) 5.45s (± 1.50%) +0.05s (+ 1.02%) 5.32s 5.64s
Emit Time 3.31s (± 3.84%) 3.29s (± 4.71%) -0.01s (- 0.39%) 2.98s 3.49s
Total Time 11.21s (± 0.72%) 11.25s (± 0.80%) +0.04s (+ 0.39%) 11.05s 11.41s
TFS - node (v8.9.0, x64)
Memory used 323,510k (± 0.01%) 323,523k (± 0.01%) +12k (+ 0.00%) 323,417k 323,628k
Parse Time 1.26s (± 0.60%) 1.26s (± 0.46%) -0.00s (- 0.16%) 1.25s 1.28s
Bind Time 0.75s (± 0.45%) 0.75s (± 0.48%) +0.00s (+ 0.13%) 0.75s 0.76s
Check Time 4.84s (± 0.63%) 4.82s (± 0.44%) -0.02s (- 0.37%) 4.78s 4.87s
Emit Time 3.20s (± 0.40%) 3.20s (± 0.78%) 0.00s ( 0.00%) 3.11s 3.23s
Total Time 10.06s (± 0.33%) 10.04s (± 0.41%) -0.02s (- 0.17%) 9.91s 10.11s
Angular - node (v8.9.0, x86)
Memory used 201,227k (± 0.03%) 200,904k (± 0.03%) -323k (- 0.16%) 200,791k 201,038k
Parse Time 2.05s (± 0.50%) 2.05s (± 0.62%) 0.00s ( 0.00%) 2.02s 2.08s
Bind Time 1.06s (± 0.64%) 1.05s (± 0.85%) -0.00s (- 0.19%) 1.04s 1.07s
Check Time 4.95s (± 0.64%) 4.99s (± 0.68%) +0.04s (+ 0.89%) 4.95s 5.08s
Emit Time 6.16s (± 1.92%) 6.18s (± 1.69%) +0.02s (+ 0.36%) 5.99s 6.41s
Total Time 14.22s (± 0.72%) 14.28s (± 0.85%) +0.06s (+ 0.42%) 14.08s 14.61s
Monaco - node (v8.9.0, x86)
Memory used 203,815k (± 0.02%) 203,803k (± 0.02%) -12k (- 0.01%) 203,690k 203,855k
Parse Time 1.60s (± 0.52%) 1.61s (± 0.87%) +0.00s (+ 0.25%) 1.59s 1.66s
Bind Time 0.77s (± 0.44%) 0.77s (± 1.04%) -0.00s (- 0.13%) 0.76s 0.79s
Check Time 5.19s (± 1.86%) 5.31s (± 1.61%) +0.12s (+ 2.31%) 5.14s 5.47s
Emit Time 3.13s (± 2.62%) 3.05s (± 3.27%) -0.08s (- 2.62%) 2.80s 3.23s
Total Time 10.70s (± 0.27%) 10.74s (± 0.32%) +0.05s (+ 0.43%) 10.64s 10.84s
TFS - node (v8.9.0, x86)
Memory used 182,626k (± 0.02%) 182,621k (± 0.02%) -5k (- 0.00%) 182,530k 182,718k
Parse Time 1.31s (± 0.67%) 1.29s (± 0.46%) -0.01s (- 0.92%) 1.28s 1.31s
Bind Time 0.71s (± 0.73%) 0.71s (± 0.47%) -0.00s (- 0.14%) 0.70s 0.72s
Check Time 4.59s (± 0.84%) 4.60s (± 0.68%) +0.01s (+ 0.31%) 4.52s 4.66s
Emit Time 2.95s (± 0.89%) 2.95s (± 0.68%) +0.01s (+ 0.27%) 2.92s 3.01s
Total Time 9.55s (± 0.35%) 9.56s (± 0.36%) +0.01s (+ 0.09%) 9.50s 9.64s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-166-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 (v8.9.0, x64)
  • node (v8.9.0, x86)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
Benchmark Name Iterations
Current 36747 10
Baseline master 10

@typescript-bot
Copy link
Collaborator

The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master.

@weswigham
Copy link
Member Author

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 15, 2020

Heya @weswigham, I've started to run the tarball bundle task on this PR at ea9dbe1. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 15, 2020

Hey @weswigham, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/64752/artifacts?artifactName=tgz&fileId=41206C2DC5F9A05FD1F5CBAF87C990D2AFB449F0AB3C39079E8215AF6CA298AC02&fileName=/typescript-3.9.0-insiders.20200215.tgz"
    }
}

and then running npm install.


There is also a playground for this build.

@sandersn sandersn added the For Backlog Bug PRs that fix a backlog bug label Mar 27, 2020
@typescript-bot typescript-bot added For Uncommitted Bug PR for untriaged, rejected, closed or missing bug and removed For Backlog Bug PRs that fix a backlog bug labels Mar 10, 2022
@@ -15,7 +15,7 @@
"containerName": "",
"fileName": "/a.js",
"kind": "local class",
"name": "(local class) C",
"name": "(local class) C\nmodule C",
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 new result is more correct (it accurately reflects the merge done on the symbol), however the "new" result isn't actually stable - symbol merges are ad-hoc in the checker, and the merge that produces this result is only created when the symbol for the source file is pulled on (as by diagnostic production), but not when the local class is pulled on (you can probably trigger the same inconsistency today by requesting all refs for the file followed by all refs for the class)! This is probably an amazingly subtle bug somewhere in JS checking that's been revealed by this diff, and fixing it is a separate issue. (The fix should involve making the merge no matter which entrypoint requests the symbol.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Opened #48197 to track the issue.

const prototypeAssignment = symbol.exports?.get("prototype" as __String)?.declarations?.[0]?.parent;
if (prototypeAssignment && isBinaryExpression(prototypeAssignment) && isObjectLiteralExpression(prototypeAssignment.right) && some(prototypeAssignment.right.properties, isConstructorAssignment)) {
// fn.prototype = { constructor: fn }
// Already deleted in `createClassElement` in first pass
Copy link
Member Author

Choose a reason for hiding this comment

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

Likewise, convertToES6Class had an issue where a js prototype property merge sometimes happens and sometimes does not (and it breaks when the merge does occur in main). Since I didn't like crashing fourslash tests, in lieu of fixing the underlying issue (making the merge always occur regardless of what symbol is requested as an entrypoint), I've hardened the implementation to work when a symbol appears as both a .prototype member and has been merged into the actual symbol.members set (and, coincedentally, moved static members to before instance members in the generated class, which I much prefer). Just like with the only-sometimes-merged js baseline symbol, I think fixing that (existing) bug should be a separate issue.

@gabritto
Copy link
Member

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Mar 21, 2022

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Mar 21, 2022

Hey @gabritto, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/122317/artifacts?artifactName=tgz&fileId=46CDEE2C7A83EA7834324687780A4AC6716EC6644EC55F26D4CDA2134AE1115A02&fileName=/typescript-4.7.0-insiders.20220321.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/pr-build@4.7.0-pr-36747-12".;

@gabritto
Copy link
Member

The fuzzer ran yesterday (March 22) with this PR's code instead of the usual TypeScript package, and I don't see any new issues/crashes reported.

@weswigham
Copy link
Member Author

Oh boy! @RyanCavanaugh does that mean I can sync this (again) and merge it? Reviews appreciated~

@weswigham
Copy link
Member Author

Oh, also, @gabritto, does the fuzzer record memory used for each project it fuzzes in its logs somewhere? It'd be cool to know the before/after memory usage stats.

@weswigham weswigham merged commit b5a3a05 into microsoft:main Mar 23, 2022
@weswigham
Copy link
Member Author

cc @alexeagle since you were interested in the original issue, many moons ago 👀

@alexeagle
Copy link
Contributor

Does that mean we can someday have custom diagnostics configured in tsc like http://tsetse.info?

@weswigham
Copy link
Member Author

Uhh, it means you should no longer have to worry about the two-checker overhead when doing both diagnostic reporting and other LS operations.

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
Archived in project
Development

Successfully merging this pull request may close these issues.

Expose getDiagnosticsProducingTypeChecker to avoid duplicate type instantiations
6 participants