Skip to content

Commit 45dedd6

Browse files
authored
Merge pull request microsoft#40063 from amcasey/ChromeTracing
Trace key operations
2 parents 0a5f533 + ef1481c commit 45dedd6

File tree

17 files changed

+377
-11
lines changed

17 files changed

+377
-11
lines changed

src/compiler/binder.ts

+2
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,14 @@ namespace ts {
174174
const binder = createBinder();
175175

176176
export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
177+
tracing.begin(tracing.Phase.Bind, "bindSourceFile", { path: file.path });
177178
performance.mark("beforeBind");
178179
perfLogger.logStartBindFile("" + file.fileName);
179180
binder(file, options);
180181
perfLogger.logStopBindFile();
181182
performance.mark("afterBind");
182183
performance.measure("Bind", "beforeBind", "afterBind");
184+
tracing.end();
183185
}
184186

185187
function createBinder(): (file: SourceFile, options: CompilerOptions) => void {

src/compiler/checker.ts

+45-2
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ namespace ts {
323323
let constraintDepth = 0;
324324
let currentNode: Node | undefined;
325325

326+
const typeCatalog: Type[] = []; // NB: id is index + 1
327+
326328
const emptySymbols = createSymbolTable();
327329
const arrayVariances = [VarianceFlags.Covariant];
328330

@@ -366,6 +368,7 @@ namespace ts {
366368
getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
367369
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
368370
getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + symbolCount,
371+
getTypeCatalog: () => typeCatalog,
369372
getTypeCount: () => typeCount,
370373
getInstantiationCount: () => totalInstantiationCount,
371374
getRelationCacheSizes: () => ({
@@ -380,6 +383,7 @@ namespace ts {
380383
getMergedSymbol,
381384
getDiagnostics,
382385
getGlobalDiagnostics,
386+
getRecursionIdentity,
383387
getTypeOfSymbolAtLocation: (symbol, locationIn) => {
384388
const location = getParseTreeNode(locationIn);
385389
return location ? getTypeOfSymbolAtLocation(symbol, location) : errorType;
@@ -3674,6 +3678,7 @@ namespace ts {
36743678
const result = new Type(checker, flags);
36753679
typeCount++;
36763680
result.id = typeCount;
3681+
typeCatalog.push(result);
36773682
return result;
36783683
}
36793684

@@ -10847,6 +10852,7 @@ namespace ts {
1084710852
// very high likelihood we're dealing with an infinite generic type that perpetually generates
1084810853
// new type identities as we descend into it. We stop the recursion here and mark this type
1084910854
// and the outer types as having circular constraints.
10855+
tracing.instant(tracing.Phase.Check, "getImmediateBaseConstraint_DepthLimit", { typeId: t.id, originalTypeId: type.id, depth: constraintDepth });
1085010856
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
1085110857
nonTerminating = true;
1085210858
return t.immediateBaseConstraint = noConstraintType;
@@ -12936,6 +12942,7 @@ namespace ts {
1293612942
// caps union types at 5000 unique literal types and 1000 unique object types.
1293712943
const estimatedCount = (count / (len - i)) * len;
1293812944
if (estimatedCount > (primitivesOnly ? 25000000 : 1000000)) {
12945+
tracing.instant(tracing.Phase.Check, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
1293912946
error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
1294012947
return false;
1294112948
}
@@ -15096,6 +15103,7 @@ namespace ts {
1509615103
// We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
1509715104
// with a combination of infinite generic types that perpetually generate new type identities. We stop
1509815105
// the recursion here by yielding the error type.
15106+
tracing.instant(tracing.Phase.Check, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount });
1509915107
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
1510015108
return errorType;
1510115109
}
@@ -16195,6 +16203,7 @@ namespace ts {
1619516203
containingMessageChain?: () => DiagnosticMessageChain | undefined,
1619616204
errorOutputContainer?: { errors?: Diagnostic[], skipLogging?: boolean },
1619716205
): boolean {
16206+
1619816207
let errorInfo: DiagnosticMessageChain | undefined;
1619916208
let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined;
1620016209
let maybeKeys: string[];
@@ -16216,6 +16225,7 @@ namespace ts {
1621616225
reportIncompatibleStack();
1621716226
}
1621816227
if (overflow) {
16228+
tracing.instant(tracing.Phase.Check, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth });
1621916229
const diag = error(errorNode || currentNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
1622016230
if (errorOutputContainer) {
1622116231
(errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag);
@@ -16257,6 +16267,8 @@ namespace ts {
1625716267
if (errorNode && errorOutputContainer && errorOutputContainer.skipLogging && result === Ternary.False) {
1625816268
Debug.assert(!!errorOutputContainer.errors, "missed opportunity to interact with error.");
1625916269
}
16270+
16271+
1626016272
return result !== Ternary.False;
1626116273

1626216274
function resetErrorInfo(saved: ReturnType<typeof captureErrorCalculationState>) {
@@ -17034,6 +17046,17 @@ namespace ts {
1703417046
return originalHandler!(onlyUnreliable);
1703517047
};
1703617048
}
17049+
17050+
if (expandingFlags === ExpandingFlags.Both) {
17051+
tracing.instant(tracing.Phase.Check, "recursiveTypeRelatedTo_DepthLimit", {
17052+
sourceId: source.id,
17053+
sourceIdStack: sourceStack.map(t => t.id),
17054+
targetId: target.id,
17055+
targetIdStack: targetStack.map(t => t.id),
17056+
depth,
17057+
});
17058+
}
17059+
1703717060
const result = expandingFlags !== ExpandingFlags.Both ? structuredTypeRelatedTo(source, target, reportErrors, intersectionState) : Ternary.Maybe;
1703817061
if (outofbandVarianceMarkerHandler) {
1703917062
outofbandVarianceMarkerHandler = originalHandler;
@@ -17059,6 +17082,13 @@ namespace ts {
1705917082
}
1706017083

1706117084
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
17085+
tracing.begin(tracing.Phase.Check, "structuredTypeRelatedTo", { sourceId: source.id, targetId: target.id });
17086+
const result = structuredTypeRelatedToWorker(source, target, reportErrors, intersectionState);
17087+
tracing.end();
17088+
return result;
17089+
}
17090+
17091+
function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
1706217092
if (intersectionState & IntersectionState.PropertyCheck) {
1706317093
return propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None);
1706417094
}
@@ -17517,6 +17547,7 @@ namespace ts {
1751717547
numCombinations *= countTypes(getTypeOfSymbol(sourceProperty));
1751817548
if (numCombinations > 25) {
1751917549
// We've reached the complexity limit.
17550+
tracing.instant(tracing.Phase.Check, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations });
1752017551
return Ternary.False;
1752117552
}
1752217553
}
@@ -18267,6 +18298,7 @@ namespace ts {
1826718298
function getVariancesWorker<TCache extends { variances?: VarianceFlags[] }>(typeParameters: readonly TypeParameter[] = emptyArray, cache: TCache, createMarkerType: (input: TCache, param: TypeParameter, marker: Type) => Type): VarianceFlags[] {
1826818299
let variances = cache.variances;
1826918300
if (!variances) {
18301+
tracing.begin(tracing.Phase.Check, "getVariancesWorker", { arity: typeParameters.length, id: (cache as any).id ?? (cache as any).declaredType?.id ?? -1 });
1827018302
// The emptyArray singleton is used to signal a recursive invocation.
1827118303
cache.variances = emptyArray;
1827218304
variances = [];
@@ -18301,6 +18333,7 @@ namespace ts {
1830118333
variances.push(variance);
1830218334
}
1830318335
cache.variances = variances;
18336+
tracing.end();
1830418337
}
1830518338
return variances;
1830618339
}
@@ -18449,7 +18482,9 @@ namespace ts {
1844918482
for (let i = 0; i < depth; i++) {
1845018483
if (getRecursionIdentity(stack[i]) === identity) {
1845118484
count++;
18452-
if (count >= 5) return true;
18485+
if (count >= 5) {
18486+
return true;
18487+
}
1845318488
}
1845418489
}
1845518490
}
@@ -19554,6 +19589,7 @@ namespace ts {
1955419589
inferFromTypes(originalSource, originalTarget);
1955519590

1955619591
function inferFromTypes(source: Type, target: Type): void {
19592+
1955719593
if (!couldContainTypeVariables(target)) {
1955819594
return;
1955919595
}
@@ -21296,6 +21332,7 @@ namespace ts {
2129621332
if (flowDepth === 2000) {
2129721333
// We have made 2000 recursive invocations. To avoid overflowing the call stack we report an error
2129821334
// and disable further control flow analysis in the containing function or module body.
21335+
tracing.instant(tracing.Phase.Check, "getTypeAtFlowNode_DepthLimit", { flowId: flow.id });
2129921336
flowAnalysisDisabled = true;
2130021337
reportFlowControlError(reference);
2130121338
return errorType;
@@ -30504,6 +30541,7 @@ namespace ts {
3050430541
}
3050530542

3050630543
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
30544+
tracing.begin(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end });
3050730545
const saveCurrentNode = currentNode;
3050830546
currentNode = node;
3050930547
instantiationCount = 0;
@@ -30513,6 +30551,7 @@ namespace ts {
3051330551
checkConstEnumAccess(node, type);
3051430552
}
3051530553
currentNode = saveCurrentNode;
30554+
tracing.end();
3051630555
return type;
3051730556
}
3051830557

@@ -33306,8 +33345,10 @@ namespace ts {
3330633345
}
3330733346

3330833347
function checkVariableDeclaration(node: VariableDeclaration) {
33348+
tracing.begin(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end });
3330933349
checkGrammarVariableDeclaration(node);
33310-
return checkVariableLikeDeclaration(node);
33350+
checkVariableLikeDeclaration(node);
33351+
tracing.end();
3331133352
}
3331233353

3331333354
function checkBindingElement(node: BindingElement) {
@@ -36348,10 +36389,12 @@ namespace ts {
3634836389
}
3634936390

3635036391
function checkSourceFile(node: SourceFile) {
36392+
tracing.begin(tracing.Phase.Check, "checkSourceFile", { path: node.path });
3635136393
performance.mark("beforeCheck");
3635236394
checkSourceFileWorker(node);
3635336395
performance.mark("afterCheck");
3635436396
performance.measure("Check", "beforeCheck", "afterCheck");
36397+
tracing.end();
3635536398
}
3635636399

3635736400
function unusedIsError(kind: UnusedKind, isAmbient: boolean): boolean {

src/compiler/commandLineParser.ts

+9
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,15 @@ namespace ts {
197197
category: Diagnostics.Advanced_Options,
198198
description: Diagnostics.Generates_a_CPU_profile
199199
},
200+
{
201+
name: "generateTrace",
202+
type: "string",
203+
isFilePath: true,
204+
isCommandLineOnly: true,
205+
paramType: Diagnostics.DIRECTORY,
206+
category: Diagnostics.Advanced_Options,
207+
description: Diagnostics.Generates_an_event_trace_and_a_list_of_types
208+
},
200209
{
201210
name: "incremental",
202211
shortName: "i",

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -4497,6 +4497,10 @@
44974497
"category": "Error",
44984498
"code": 6236
44994499
},
4500+
"Generates an event trace and a list of types.": {
4501+
"category": "Message",
4502+
"code": 6237
4503+
},
45004504

45014505
"Projects to reference": {
45024506
"category": "Message",

src/compiler/emitter.ts

+8
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,17 @@ namespace ts {
300300
sourceFiles: sourceFileOrBundle.sourceFiles.map(file => relativeToBuildInfo(getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory())))
301301
};
302302
}
303+
tracing.begin(tracing.Phase.Emit, "emitJsFileOrBundle", { jsFilePath });
303304
emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath, relativeToBuildInfo);
305+
tracing.end();
306+
307+
tracing.begin(tracing.Phase.Emit, "emitDeclarationFileOrBundle", { declarationFilePath });
304308
emitDeclarationFileOrBundle(sourceFileOrBundle, declarationFilePath, declarationMapPath, relativeToBuildInfo);
309+
tracing.end();
310+
311+
tracing.begin(tracing.Phase.Emit, "emitBuildInfo", { buildInfoPath });
305312
emitBuildInfo(bundleBuildInfo, buildInfoPath);
313+
tracing.end();
306314

307315
if (!emitSkipped && emittedFilesList) {
308316
if (!emitOnlyDtsFiles) {

src/compiler/parser.ts

+2
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ namespace ts {
614614
}
615615

616616
export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
617+
tracing.begin(tracing.Phase.Parse, "createSourceFile", { path: fileName });
617618
performance.mark("beforeParse");
618619
let result: SourceFile;
619620

@@ -628,6 +629,7 @@ namespace ts {
628629

629630
performance.mark("afterParse");
630631
performance.measure("Parse", "beforeParse", "afterParse");
632+
tracing.end();
631633
return result;
632634
}
633635

src/compiler/program.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ namespace ts {
734734
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
735735
const sourceFilesFoundSearchingNodeModules = new Map<string, boolean>();
736736

737+
tracing.begin(tracing.Phase.Program, "createProgram", {});
737738
performance.mark("beforeProgram");
738739

739740
const host = createProgramOptions.host || createCompilerHost(options);
@@ -948,6 +949,7 @@ namespace ts {
948949
getNodeCount: () => getDiagnosticsProducingTypeChecker().getNodeCount(),
949950
getIdentifierCount: () => getDiagnosticsProducingTypeChecker().getIdentifierCount(),
950951
getSymbolCount: () => getDiagnosticsProducingTypeChecker().getSymbolCount(),
952+
getTypeCatalog: () => getDiagnosticsProducingTypeChecker().getTypeCatalog(),
951953
getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(),
952954
getInstantiationCount: () => getDiagnosticsProducingTypeChecker().getInstantiationCount(),
953955
getRelationCacheSizes: () => getDiagnosticsProducingTypeChecker().getRelationCacheSizes(),
@@ -982,6 +984,7 @@ namespace ts {
982984
verifyCompilerOptions();
983985
performance.mark("afterProgram");
984986
performance.measure("Program", "beforeProgram", "afterProgram");
987+
tracing.end();
985988

986989
return program;
987990

@@ -1505,6 +1508,7 @@ namespace ts {
15051508

15061509
function emitBuildInfo(writeFileCallback?: WriteFileCallback): EmitResult {
15071510
Debug.assert(!outFile(options));
1511+
tracing.begin(tracing.Phase.Emit, "emitBuildInfo", {});
15081512
performance.mark("beforeEmit");
15091513
const emitResult = emitFiles(
15101514
notImplementedResolver,
@@ -1517,6 +1521,7 @@ namespace ts {
15171521

15181522
performance.mark("afterEmit");
15191523
performance.measure("Emit", "beforeEmit", "afterEmit");
1524+
tracing.end();
15201525
return emitResult;
15211526
}
15221527

@@ -1577,7 +1582,10 @@ namespace ts {
15771582
}
15781583

15791584
function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, transformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
1580-
return runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers, forceDtsEmit));
1585+
tracing.begin(tracing.Phase.Emit, "emit", { path: sourceFile?.path });
1586+
const result = runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers, forceDtsEmit));
1587+
tracing.end();
1588+
return result;
15811589
}
15821590

15831591
function isEmitBlocked(emitFileName: string): boolean {

0 commit comments

Comments
 (0)