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

Allow --noCheck to be commandLine option #58839

Merged
merged 3 commits into from
Jun 14, 2024
Merged

Allow --noCheck to be commandLine option #58839

merged 3 commits into from
Jun 14, 2024

Conversation

sheetalkamat
Copy link
Member

Works on top of #58626 and #58838

Adds checkPending to buildInfo so as to handle if there was noCheck pending. This does not add "noCheck" as semantic affecting diagnostics because builder can handle that and save the diagnostics between runs with and without "noCheck"

@typescript-bot typescript-bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Jun 12, 2024
@sheetalkamat sheetalkamat force-pushed the noCheck branch 4 times, most recently from 6dc2e31 to b641a43 Compare June 13, 2024 18:54
@jakebailey
Copy link
Member

This will close #29651, right?

@sheetalkamat
Copy link
Member Author

Yes. We would report ssyntax errors though while emitting.

@fatcerberus
Copy link

ssyntax errors

Oh no, I hadn't realized some of the TypeScript devs were snakes

@sheetalkamat
Copy link
Member Author

@typescript-bot test it

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 13, 2024

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

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

@sheetalkamat sheetalkamat marked this pull request as ready for review June 13, 2024 20:39
@typescript-bot
Copy link
Collaborator

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

Everything looks the same!

You can check the log here.

src/compiler/builder.ts Outdated Show resolved Hide resolved
@typescript-bot
Copy link
Collaborator

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

Everything looks good!

@@ -986,6 +994,7 @@ function getSemanticDiagnosticsOfFile(
cancellationToken: CancellationToken | undefined,
semanticDiagnosticsPerFile?: BuilderProgramState["semanticDiagnosticsPerFile"],
): readonly Diagnostic[] {
if (state.compilerOptions.noCheck) return emptyArray;
Copy link
Member

Choose a reason for hiding this comment

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

Isn't it funky that a noCheck with -b fetches different diagnostics than a noCheck normally does? This is going to skip all the program construction errors that noCheck would normally still report, no?

Copy link
Member Author

Choose a reason for hiding this comment

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

No. If typechecking is skipped the semantic and program diagnostics are skipped for that file too.. (Look at getBindAndCheckDiagnostics as well as getProgramDiagnostics in program)

Copy link
Member

Choose a reason for hiding this comment

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

Oh, so this early bail here just skips the per-file iteration that'll internally bail on every individual file anyway; got it. It's not really clear that that's guaranteed to be the case.

@typescript-bot
Copy link
Collaborator

@sheetalkamat
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 30 30 ~ ~ ~ p=1.000 n=6
Symbols 62,153 62,153 ~ ~ ~ p=1.000 n=6
Types 50,242 50,242 ~ ~ ~ p=1.000 n=6
Memory used 193,532k (± 0.93%) 194,770k (± 0.92%) ~ 192,257k 196,095k p=0.378 n=6
Parse Time 1.57s (± 0.52%) 1.58s (± 0.48%) ~ 1.57s 1.59s p=0.120 n=6
Bind Time 0.87s (± 0.87%) 0.86s (± 1.40%) ~ 0.85s 0.88s p=0.502 n=6
Check Time 11.38s (± 0.44%) 11.39s (± 0.12%) ~ 11.37s 11.41s p=0.377 n=6
Emit Time 3.25s (± 0.91%) 3.28s (± 0.69%) ~ 3.24s 3.30s p=0.059 n=6
Total Time 17.07s (± 0.37%) 17.11s (± 0.21%) ~ 17.06s 17.16s p=0.296 n=6
angular-1 - node (v18.15.0, x64)
Errors 5 5 ~ ~ ~ p=1.000 n=6
Symbols 944,104 944,104 ~ ~ ~ p=1.000 n=6
Types 407,044 407,044 ~ ~ ~ p=1.000 n=6
Memory used 1,218,567k (± 0.00%) 1,218,586k (± 0.00%) ~ 1,218,527k 1,218,651k p=0.521 n=6
Parse Time 7.97s (± 0.47%) 7.97s (± 0.60%) ~ 7.89s 8.02s p=0.809 n=6
Bind Time 2.23s (± 0.66%) 2.23s (± 0.63%) ~ 2.21s 2.25s p=0.870 n=6
Check Time 36.34s (± 0.34%) 36.24s (± 0.23%) ~ 36.13s 36.31s p=0.261 n=6
Emit Time 17.82s (± 0.87%) 17.88s (± 0.67%) ~ 17.79s 18.11s p=0.470 n=6
Total Time 64.36s (± 0.37%) 64.32s (± 0.27%) ~ 64.14s 64.64s p=1.000 n=6
mui-docs - node (v18.15.0, x64)
Errors 5 5 ~ ~ ~ p=1.000 n=6
Symbols 2,132,301 2,132,301 ~ ~ ~ p=1.000 n=6
Types 926,081 926,081 ~ ~ ~ p=1.000 n=6
Memory used 2,114,925k (± 0.00%) 2,114,963k (± 0.01%) ~ 2,114,765k 2,115,123k p=0.689 n=6
Parse Time 7.84s (± 0.57%) 7.85s (± 0.34%) ~ 7.82s 7.89s p=0.808 n=6
Bind Time 2.75s (± 0.50%) 2.74s (± 0.67%) ~ 2.72s 2.77s p=0.249 n=6
Check Time 84.10s (± 0.31%) 84.31s (± 0.47%) ~ 83.70s 84.88s p=0.378 n=6
Emit Time 0.16s (± 2.58%) 0.16s (± 5.58%) ~ 0.15s 0.17s p=0.787 n=6
Total Time 94.86s (± 0.29%) 95.05s (± 0.42%) ~ 94.44s 95.63s p=0.378 n=6
self-build-src - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,229,542 1,229,778 +236 (+ 0.02%) ~ ~ p=0.001 n=6
Types 260,916 260,978 +62 (+ 0.02%) ~ ~ p=0.001 n=6
Memory used 2,370,937k (± 2.60%) 2,406,525k (± 3.06%) +35,588k (+ 1.50%) 2,346,363k 2,497,315k p=0.031 n=6
Parse Time 7.47s (± 0.95%) 7.41s (± 0.59%) ~ 7.36s 7.47s p=0.199 n=6
Bind Time 2.77s (± 0.77%) 2.77s (± 0.38%) ~ 2.76s 2.79s p=0.806 n=6
Check Time 49.62s (± 0.48%) 49.56s (± 0.27%) ~ 49.42s 49.79s p=0.689 n=6
Emit Time 3.88s (± 2.53%) 3.79s (± 1.88%) ~ 3.70s 3.90s p=0.128 n=6
Total Time 63.73s (± 0.40%) 63.53s (± 0.31%) ~ 63.31s 63.79s p=0.149 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,229,542 1,229,778 +236 (+ 0.02%) ~ ~ p=0.001 n=6
Types 260,916 260,978 +62 (+ 0.02%) ~ ~ p=0.001 n=6
Memory used 2,421,421k (± 0.02%) 2,448,000k (± 2.51%) +26,579k (+ 1.10%) 2,422,078k 2,573,671k p=0.008 n=6
Parse Time 6.27s (± 0.76%) 6.26s (± 0.35%) ~ 6.23s 6.29s p=0.748 n=6
Bind Time 2.01s (± 0.58%) 2.02s (± 0.87%) ~ 1.99s 2.04s p=0.514 n=6
Check Time 40.69s (± 0.75%) 40.59s (± 0.28%) ~ 40.43s 40.75s p=1.000 n=6
Emit Time 3.23s (± 4.46%) 3.14s (± 2.36%) ~ 3.06s 3.28s p=0.199 n=6
Total Time 52.22s (± 0.93%) 52.01s (± 0.36%) ~ 51.86s 52.36s p=0.230 n=6
self-compiler - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 258,665 258,684 +19 (+ 0.01%) ~ ~ p=0.001 n=6
Types 104,931 104,933 +2 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 428,295k (± 0.01%) 428,407k (± 0.01%) +112k (+ 0.03%) 428,352k 428,472k p=0.005 n=6
Parse Time 3.32s (± 0.53%) 3.32s (± 0.52%) ~ 3.29s 3.34s p=0.870 n=6
Bind Time 1.30s (± 0.84%) 1.30s (± 1.13%) ~ 1.29s 1.32s p=0.863 n=6
Check Time 18.09s (± 0.41%) 18.09s (± 0.32%) ~ 17.99s 18.14s p=0.872 n=6
Emit Time 1.38s (± 1.91%) 1.39s (± 1.26%) ~ 1.36s 1.41s p=0.413 n=6
Total Time 24.09s (± 0.29%) 24.10s (± 0.22%) ~ 24.02s 24.14s p=0.810 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors 35 35 ~ ~ ~ p=1.000 n=6
Symbols 224,565 224,565 ~ ~ ~ p=1.000 n=6
Types 93,734 93,734 ~ ~ ~ p=1.000 n=6
Memory used 369,493k (± 0.02%) 369,539k (± 0.03%) ~ 369,464k 369,726k p=0.298 n=6
Parse Time 2.76s (± 0.50%) 2.79s (± 0.97%) +0.03s (+ 1.15%) 2.76s 2.83s p=0.029 n=6
Bind Time 1.60s (± 0.83%) 1.60s (± 1.74%) ~ 1.58s 1.65s p=0.402 n=6
Check Time 15.66s (± 0.30%) 15.65s (± 0.35%) ~ 15.59s 15.74s p=0.808 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 20.02s (± 0.25%) 20.04s (± 0.29%) ~ 19.96s 20.09s p=0.872 n=6
vscode - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 2,853,842 2,853,842 ~ ~ ~ p=1.000 n=6
Types 968,167 968,167 ~ ~ ~ p=1.000 n=6
Memory used 3,020,759k (± 0.00%) 3,020,800k (± 0.00%) ~ 3,020,736k 3,020,891k p=0.335 n=6
Parse Time 16.77s (± 0.24%) 16.79s (± 0.34%) ~ 16.70s 16.84s p=0.226 n=6
Bind Time 5.11s (± 1.72%) 5.10s (± 0.26%) ~ 5.09s 5.12s p=0.252 n=6
Check Time 89.33s (± 0.34%) 89.67s (± 0.72%) ~ 88.87s 90.62s p=0.471 n=6
Emit Time 29.25s (± 0.56%) 29.19s (± 1.65%) ~ 28.37s 29.56s p=0.378 n=6
Total Time 140.45s (± 0.32%) 140.75s (± 0.43%) ~ 139.85s 141.45s p=0.378 n=6
webpack - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 266,914 266,914 ~ ~ ~ p=1.000 n=6
Types 108,685 108,685 ~ ~ ~ p=1.000 n=6
Memory used 411,357k (± 0.02%) 411,340k (± 0.01%) ~ 411,285k 411,416k p=1.000 n=6
Parse Time 3.18s (± 0.26%) 3.17s (± 0.37%) ~ 3.15s 3.18s p=0.666 n=6
Bind Time 1.41s (± 0.78%) 1.42s (± 0.59%) ~ 1.41s 1.43s p=0.652 n=6
Check Time 14.39s (± 0.56%) 14.41s (± 0.34%) ~ 14.35s 14.46s p=0.572 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 18.97s (± 0.41%) 19.00s (± 0.26%) ~ 18.94s 19.05s p=0.574 n=6
xstate-main - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 523,429 523,429 ~ ~ ~ p=1.000 n=6
Types 177,955 177,955 ~ ~ ~ p=1.000 n=6
Memory used 461,442k (± 0.07%) 461,515k (± 0.07%) ~ 461,209k 461,958k p=0.378 n=6
Parse Time 3.15s (± 0.84%) 3.16s (± 0.77%) ~ 3.11s 3.17s p=0.934 n=6
Bind Time 1.19s (± 0.43%) 1.19s (± 0.83%) ~ 1.18s 1.20s p=0.931 n=6
Check Time 18.13s (± 0.36%) 18.11s (± 0.60%) ~ 17.98s 18.23s p=0.936 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 22.47s (± 0.33%) 22.45s (± 0.45%) ~ 22.34s 22.59s p=0.873 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

@@ -1084,6 +1093,7 @@ export interface IncrementalBuildInfoBase extends BuildInfo {
// Because this is only output file in the program, we dont need fileId to deduplicate name
latestChangedDtsFile?: string | undefined;
errors: true | undefined;
checkPending: true | undefined;
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this exactly derived from the options? Like, isn't this just options.noCheck? Eveywhere I'm looking in this PR, this is either set if options.noCheck in the buildinfo is present, or unset if it isn't. I guess NonIncrementalBuildInfo doesn't have options stored, but honestly, we should probably just always store them all.

Copy link
Member Author

Choose a reason for hiding this comment

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

No its not same as options.noCheck since it takes into account run with --noCheck, one without noCheck and then --noCheck without any updates in between does not update tsbuildInfo to mark it as pending. So its really if we havent done semanticdiagnostics calculation

Copy link
Member

Choose a reason for hiding this comment

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

Right, it just seems like that's the same check we do for differing diagnostics-affecting options anyway? Like this is kinda redundant? (Though technically isn't since it's not using that mechanism with this PR.)

You run once without <flag> set, those options get cached into the .buildinfo, then you do a run with <flag> set - we compare the old <flag> value (nonextant) with the new <flag> value (present), and if <flag> affects diagnostics, mark the build as needing a .buildinfo update, minimally, and some subset of diagnostics and emit updated (as appropriate for the flag). At least for --incremental. Adding noCheck would, then, trigger a typecheck, yes, but it'd be a basically free no-op typecheck (since the flag's function is to skip it). Removing the flag then, would, naturally, also trigger a new typecheck (and you'd get the errors back). Just seems weird we wouldn't reuse that logic for non-incremental, and instead special-case the option like this. Doesn't seem like it's actually skipping anything beyond a few function calls that'd skip their work internally with the flag set anyway, and is duplicating what already happens inside createBuilderProgramState so long as the options from the old non-incremental build are actually serialized - which is why it seems so much like we're just hoisting the option out of the options list and into the root buildinfo.

Copy link
Member Author

Choose a reason for hiding this comment

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

That’s because we don’t want to cached diagnostics that happened as part of checking when running with no check..

This helps with keeping the cache .. if you see the diff of second commit you should see that we are now able to retain diagnostics of unchanged files

we do exactly same thing as part of pending emit so we don’t have to emit already emitted files

Copy link
Member

@weswigham weswigham Jun 14, 2024

Choose a reason for hiding this comment

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

I think I get what we're doing here that's special - we're trying to reuse the .buildinfo from an old non-noCheck build for another non-noCheck without a noCheck build in the middle clobbering it.

That feels kinda weird, since it's basically like we're ignoring the noCheck build even happened and not updating the state, but I kinda get why you'd want that - so long as the state on disk is from the non-noCheck build, you can start a noCheck (for emit) and non-noCheck (for checking) build in parallel off it.

Personally, I assumed you'd want separate .buildinfos for you non-noCheck and noCheck build parts if you were trying to ensure they didn't clobber one another as you parallelized things. This kinda feels like it's trying to enable running the two builds with different options collaboratively off of a single .buildinfo (since if the noCheck runs first, it'll leave the diagnostics part to the next build, while if the noEmit part runs first, it'll leave the emit part for the next build to fill in), which feels kinda odd. Both orders work in serial under this scheme, but if you actually parallelize it, one very likely could clobber the other's .buildinfo output regardless. So I guess it's kinda neat that we can do this, but I'm not sure why we'd need to. If you are running them in serial, the options themselves are going to skip the relevant work, so skipping them at the orchestrator level is a bit redundant and just lets you run them in arbitrary order repeatedly without being penalized with a rebuild when you toggle emit/check on and then off again, but in parallel, you need separate buildinfos to prevent race conditions between the processes anyway, which were never going to trigger a rebuild unless there was an actual substantive change in the first place.

I guess the TL;DR is:
Do we actually care if

tsc -b . --noCheck
tsc -b . --noEmit
tsc -b . --noCheck
tsc -b . --noEmit

reuses diagnostics from the first --noEmit run on the second --noEmit line? These kind of partial output builds are only useful in parallel, and in parallel, you need separate .buildinfos for safety anyway. I'd expect we'd wanna enable and recommend something like

tsc -b . --noCheck
tsc -b . --noEmit --tsBuildInfoFile ${configDir}/noemit.buildinfo
tsc -b . --noCheck
tsc -b . --noEmit --tsBuildInfoFile ${configDir}/noemit.buildinfo

instead, since that'll work even if you spawn the differently-option'd tsc -bs in parallel.

Copy link
Member Author

Choose a reason for hiding this comment

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

We do care about that and there is buildInfo fidelity built into it. Eg currenly we do support tsc -b --noEmit followed by tsc -b so it doesnt typecheck again.

Copy link
Member Author

Choose a reason for hiding this comment

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

We are not doing this for parallel builds but subsequent builds. Eg imagine running tsc -b --noCheck -w while debugging and once done last running tsc -b

Copy link
Member

Choose a reason for hiding this comment

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

I guess it's fine to have this support, I'm just not sure it's gonna help many people in ways that aren't gonna lead them to a pit of failure. Like you see the sequential builds with different options smartly don't trigger rebuilds, so then naturally if you're a watch user you spawn one window with tsc -b --noCheck -w and one with tsc -b --noEmit -w as your super simple easy top-level parallelization, and that bricks the state, since the two builds will repeatedly clobber one another, rather than cooperate to build a single more complete state like the sequential builds do.

@typescript-bot
Copy link
Collaborator

@sheetalkamat Here are the results of running the top 400 repos with tsc comparing main and refs/pull/58839/merge:

Everything looks good!

@@ -1084,6 +1093,7 @@ export interface IncrementalBuildInfoBase extends BuildInfo {
// Because this is only output file in the program, we dont need fileId to deduplicate name
latestChangedDtsFile?: string | undefined;
errors: true | undefined;
checkPending: true | undefined;
Copy link
Member

Choose a reason for hiding this comment

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

I guess it's fine to have this support, I'm just not sure it's gonna help many people in ways that aren't gonna lead them to a pit of failure. Like you see the sequential builds with different options smartly don't trigger rebuilds, so then naturally if you're a watch user you spawn one window with tsc -b --noCheck -w and one with tsc -b --noEmit -w as your super simple easy top-level parallelization, and that bricks the state, since the two builds will repeatedly clobber one another, rather than cooperate to build a single more complete state like the sequential builds do.

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.

5 participants