Skip to content

Commit b19741c

Browse files
Report aggregate statistics for solution as well as some solution perf numbers (microsoft#50267)
* Report aggregate statistics for solution as well as some solution perf numbers This change under --extendedDiagnostics aggregates the diagnostics from all projects built and reports it at the end. Apart from that it also outputs some measurements for work that happens in tsc --build like finding if projects are uptodate etc. Also removes unnecessary node count per suggestion * Apply suggestions from code review Co-authored-by: Ron Buckton <[email protected]> * Fix condition * Remove extra time Co-authored-by: Ron Buckton <[email protected]>
1 parent 075ee3d commit b19741c

File tree

4 files changed

+246
-63
lines changed

4 files changed

+246
-63
lines changed

src/compiler/performance.ts

+22
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,28 @@ namespace ts.performance {
107107
durations.forEach((duration, measureName) => cb(measureName, duration));
108108
}
109109

110+
export function forEachMark(cb: (markName: string) => void) {
111+
marks.forEach((_time, markName) => cb(markName));
112+
}
113+
114+
export function clearMeasures(name?: string) {
115+
if (name !== undefined) durations.delete(name);
116+
else durations.clear();
117+
performanceImpl?.clearMeasures(name);
118+
}
119+
120+
export function clearMarks(name?: string) {
121+
if (name !== undefined) {
122+
counts.delete(name);
123+
marks.delete(name);
124+
}
125+
else {
126+
counts.clear();
127+
marks.clear();
128+
}
129+
performanceImpl?.clearMarks(name);
130+
}
131+
110132
/**
111133
* Indicates whether the performance API is enabled.
112134
*/

src/compiler/performanceCore.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ namespace ts {
1313
export interface Performance {
1414
mark(name: string): void;
1515
measure(name: string, startMark?: string, endMark?: string): void;
16+
clearMeasures(name?: string): void;
17+
clearMarks(name?: string): void;
1618
now(): number;
1719
timeOrigin: number;
1820
}
@@ -50,6 +52,8 @@ namespace ts {
5052
typeof performance.mark === "function" &&
5153
typeof performance.measure === "function" &&
5254
typeof performance.now === "function" &&
55+
typeof performance.clearMarks === "function" &&
56+
typeof performance.clearMeasures === "function" &&
5357
typeof PerformanceObserver === "function";
5458
}
5559

@@ -73,8 +77,8 @@ namespace ts {
7377
try {
7478
let performance: Performance;
7579
const { performance: nodePerformance, PerformanceObserver } = require("perf_hooks") as typeof import("perf_hooks");
76-
if (hasRequiredAPI(nodePerformance, PerformanceObserver)) {
77-
performance = nodePerformance;
80+
if (hasRequiredAPI(nodePerformance as unknown as Performance, PerformanceObserver)) {
81+
performance = nodePerformance as unknown as Performance;
7882
// There is a bug in Node's performance.measure prior to 12.16.3/13.13.0 that does not
7983
// match the Web Performance API specification. Node's implementation did not allow
8084
// optional `start` and `end` arguments for `performance.measure`.
@@ -95,7 +99,9 @@ namespace ts {
9599
if (end === "__performance.measure-fix__") {
96100
nodePerformance.clearMarks("__performance.measure-fix__");
97101
}
98-
}
102+
},
103+
clearMarks(name) { return nodePerformance.clearMarks(name); },
104+
clearMeasures(name) { return (nodePerformance as unknown as Performance).clearMeasures(name); },
99105
};
100106
}
101107
return {

src/compiler/tsbuildPublic.ts

+38-2
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ namespace ts {
404404
return isParsedCommandLine(value) ? value : undefined;
405405
}
406406

407+
performance.mark("SolutionBuilder::beforeConfigFileParsing");
407408
let diagnostic: Diagnostic | undefined;
408409
const { parseConfigFileHost, baseCompilerOptions, baseWatchOptions, extendedConfigCache, host } = state;
409410
let parsed: ParsedCommandLine | undefined;
@@ -417,6 +418,8 @@ namespace ts {
417418
parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = noop;
418419
}
419420
configFileCache.set(configFilePath, parsed || diagnostic!);
421+
performance.mark("SolutionBuilder::afterConfigFileParsing");
422+
performance.measure("SolutionBuilder::Config file parsing", "SolutionBuilder::beforeConfigFileParsing", "SolutionBuilder::afterConfigFileParsing");
420423
return parsed;
421424
}
422425

@@ -734,6 +737,7 @@ namespace ts {
734737
if (updateOutputFileStampsPending) {
735738
updateOutputTimestamps(state, config, projectPath);
736739
}
740+
performance.mark("SolutionBuilder::Timestamps only updates");
737741
return doneInvalidatedProject(state, projectPath);
738742
}
739743
};
@@ -847,6 +851,8 @@ namespace ts {
847851

848852
function done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) {
849853
executeSteps(BuildStep.Done, cancellationToken, writeFile, customTransformers);
854+
if (kind === InvalidatedProjectKind.Build) performance.mark("SolutionBuilder::Projects built");
855+
else performance.mark("SolutionBuilder::Bundles updated");
850856
return doneInvalidatedProject(state, projectPath);
851857
}
852858

@@ -1809,7 +1815,10 @@ namespace ts {
18091815
return prior;
18101816
}
18111817

1818+
performance.mark("SolutionBuilder::beforeUpToDateCheck");
18121819
const actual = getUpToDateStatusWorker(state, project, resolvedPath);
1820+
performance.mark("SolutionBuilder::afterUpToDateCheck");
1821+
performance.measure("SolutionBuilder::Up-to-date check", "SolutionBuilder::beforeUpToDateCheck", "SolutionBuilder::afterUpToDateCheck");
18131822
state.projectStatus.set(resolvedPath, actual);
18141823
return actual;
18151824
}
@@ -1958,6 +1967,14 @@ namespace ts {
19581967
}
19591968

19601969
function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, getCustomTransformers?: (project: string) => CustomTransformers, onlyReferences?: boolean): ExitStatus {
1970+
performance.mark("SolutionBuilder::beforeBuild");
1971+
const result = buildWorker(state, project, cancellationToken, writeFile, getCustomTransformers, onlyReferences);
1972+
performance.mark("SolutionBuilder::afterBuild");
1973+
performance.measure("SolutionBuilder::Build", "SolutionBuilder::beforeBuild", "SolutionBuilder::afterBuild");
1974+
return result;
1975+
}
1976+
1977+
function buildWorker(state: SolutionBuilderState, project: string | undefined, cancellationToken: CancellationToken | undefined, writeFile: WriteFileCallback | undefined, getCustomTransformers: ((project: string) => CustomTransformers) | undefined, onlyReferences: boolean | undefined): ExitStatus {
19611978
const buildOrder = getBuildOrderFor(state, project, onlyReferences);
19621979
if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped;
19631980

@@ -1986,7 +2003,15 @@ namespace ts {
19862003
: ExitStatus.DiagnosticsPresent_OutputsSkipped;
19872004
}
19882005

1989-
function clean(state: SolutionBuilderState, project?: string, onlyReferences?: boolean) {
2006+
function clean(state: SolutionBuilderState, project?: string, onlyReferences?: boolean): ExitStatus {
2007+
performance.mark("SolutionBuilder::beforeClean");
2008+
const result = cleanWorker(state, project, onlyReferences);
2009+
performance.mark("SolutionBuilder::afterClean");
2010+
performance.measure("SolutionBuilder::Clean", "SolutionBuilder::beforeClean", "SolutionBuilder::afterClean");
2011+
return result;
2012+
}
2013+
2014+
function cleanWorker(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined) {
19902015
const buildOrder = getBuildOrderFor(state, project, onlyReferences);
19912016
if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped;
19922017

@@ -2063,6 +2088,14 @@ namespace ts {
20632088
}
20642089

20652090
function buildNextInvalidatedProject(state: SolutionBuilderState, changeDetected: boolean) {
2091+
performance.mark("SolutionBuilder::beforeBuild");
2092+
const buildOrder = buildNextInvalidatedProjectWorker(state, changeDetected);
2093+
performance.mark("SolutionBuilder::afterBuild");
2094+
performance.measure("SolutionBuilder::Build", "SolutionBuilder::beforeBuild", "SolutionBuilder::afterBuild");
2095+
if (buildOrder) reportErrorSummary(state, buildOrder);
2096+
}
2097+
2098+
function buildNextInvalidatedProjectWorker(state: SolutionBuilderState, changeDetected: boolean) {
20662099
state.timerToBuildInvalidatedProject = undefined;
20672100
if (state.reportFileChangeDetected) {
20682101
state.reportFileChangeDetected = false;
@@ -2092,7 +2125,7 @@ namespace ts {
20922125
}
20932126
}
20942127
disableCache(state);
2095-
reportErrorSummary(state, buildOrder);
2128+
return buildOrder;
20962129
}
20972130

20982131
function watchConfigFile(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) {
@@ -2199,6 +2232,7 @@ namespace ts {
21992232

22002233
function startWatching(state: SolutionBuilderState, buildOrder: AnyBuildOrder) {
22012234
if (!state.watchAllProjectsPending) return;
2235+
performance.mark("SolutionBuilder::beforeWatcherCreation");
22022236
state.watchAllProjectsPending = false;
22032237
for (const resolved of getBuildOrderFromAnyBuildOrder(buildOrder)) {
22042238
const resolvedPath = toResolvedConfigFilePath(state, resolved);
@@ -2217,6 +2251,8 @@ namespace ts {
22172251
watchPackageJsonFiles(state, resolved, resolvedPath, cfg);
22182252
}
22192253
}
2254+
performance.mark("SolutionBuilder::afterWatcherCreation");
2255+
performance.measure("SolutionBuilder::Watcher creation", "SolutionBuilder::beforeWatcherCreation", "SolutionBuilder::afterWatcherCreation");
22202256
}
22212257

22222258
function stopWatching(state: SolutionBuilderState) {

0 commit comments

Comments
 (0)