Skip to content

Commit af0d904

Browse files
committed
Trace key operations
Produce output in Chrome's event tracing format so that it can be viewed in Chrome/Edge.
1 parent c95cffe commit af0d904

15 files changed

+270
-13
lines changed

Diff for: 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 {

Diff for: src/compiler/checker.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ namespace ts {
316316
let instantiationDepth = 0;
317317
let constraintDepth = 0;
318318
let currentNode: Node | undefined;
319+
let typeCatalog: Type[] = []; // NB: id is index + 1
319320

320321
const emptySymbols = createSymbolTable();
321322
const arrayVariances = [VarianceFlags.Covariant];
@@ -360,6 +361,7 @@ namespace ts {
360361
getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
361362
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
362363
getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + symbolCount,
364+
getTypeCatalog: () => typeCatalog,
363365
getTypeCount: () => typeCount,
364366
getInstantiationCount: () => totalInstantiationCount,
365367
getRelationCacheSizes: () => ({
@@ -3630,6 +3632,7 @@ namespace ts {
36303632
const result = new Type(checker, flags);
36313633
typeCount++;
36323634
result.id = typeCount;
3635+
typeCatalog.push(result);
36333636
return result;
36343637
}
36353638

@@ -15974,6 +15977,7 @@ namespace ts {
1597415977
containingMessageChain?: () => DiagnosticMessageChain | undefined,
1597515978
errorOutputContainer?: { errors?: Diagnostic[], skipLogging?: boolean },
1597615979
): boolean {
15980+
1597715981
let errorInfo: DiagnosticMessageChain | undefined;
1597815982
let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined;
1597915983
let maybeKeys: string[];
@@ -16036,6 +16040,8 @@ namespace ts {
1603616040
if (errorNode && errorOutputContainer && errorOutputContainer.skipLogging && result === Ternary.False) {
1603716041
Debug.assert(!!errorOutputContainer.errors, "missed opportunity to interact with error.");
1603816042
}
16043+
16044+
1603916045
return result !== Ternary.False;
1604016046

1604116047
function resetErrorInfo(saved: ReturnType<typeof captureErrorCalculationState>) {
@@ -16754,6 +16760,13 @@ namespace ts {
1675416760
// equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion
1675516761
// and issue an error. Otherwise, actually compare the structure of the two types.
1675616762
function recursiveTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
16763+
tracing.begin(tracing.Phase.Check, "recursiveTypeRelatedTo", { sourceId: source.id, targetId: target.id });
16764+
const result = recursiveTypeRelatedToWorker(source, target, reportErrors, intersectionState);
16765+
tracing.end();
16766+
return result;
16767+
}
16768+
16769+
function recursiveTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
1675716770
if (overflow) {
1675816771
return Ternary.False;
1675916772
}
@@ -18025,6 +18038,7 @@ namespace ts {
1802518038
function getVariancesWorker<TCache extends { variances?: VarianceFlags[] }>(typeParameters: readonly TypeParameter[] = emptyArray, cache: TCache, createMarkerType: (input: TCache, param: TypeParameter, marker: Type) => Type): VarianceFlags[] {
1802618039
let variances = cache.variances;
1802718040
if (!variances) {
18041+
tracing.begin(tracing.Phase.Check, "getVariancesWorker", { arity: typeParameters.length, id: (cache as any).id ?? (cache as any).declaredType?.id ?? -1 });
1802818042
// The emptyArray singleton is used to signal a recursive invocation.
1802918043
cache.variances = emptyArray;
1803018044
variances = [];
@@ -18059,6 +18073,7 @@ namespace ts {
1805918073
variances.push(variance);
1806018074
}
1806118075
cache.variances = variances;
18076+
tracing.end();
1806218077
}
1806318078
return variances;
1806418079
}
@@ -19317,6 +19332,7 @@ namespace ts {
1931719332
inferFromTypes(originalSource, originalTarget);
1931819333

1931919334
function inferFromTypes(source: Type, target: Type): void {
19335+
1932019336
if (!couldContainTypeVariables(target)) {
1932119337
return;
1932219338
}
@@ -30202,6 +30218,7 @@ namespace ts {
3020230218
}
3020330219

3020430220
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
30221+
tracing.begin(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end });
3020530222
const saveCurrentNode = currentNode;
3020630223
currentNode = node;
3020730224
instantiationCount = 0;
@@ -30211,6 +30228,7 @@ namespace ts {
3021130228
checkConstEnumAccess(node, type);
3021230229
}
3021330230
currentNode = saveCurrentNode;
30231+
tracing.end();
3021430232
return type;
3021530233
}
3021630234

@@ -32977,8 +32995,10 @@ namespace ts {
3297732995
}
3297832996

3297932997
function checkVariableDeclaration(node: VariableDeclaration) {
32998+
tracing.begin(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end });
3298032999
checkGrammarVariableDeclaration(node);
32981-
return checkVariableLikeDeclaration(node);
33000+
checkVariableLikeDeclaration(node);
33001+
tracing.end();
3298233002
}
3298333003

3298433004
function checkBindingElement(node: BindingElement) {
@@ -36010,10 +36030,12 @@ namespace ts {
3601036030
}
3601136031

3601236032
function checkSourceFile(node: SourceFile) {
36033+
tracing.begin(tracing.Phase.Check, "checkSourceFile", { path: node.path });
3601336034
performance.mark("beforeCheck");
3601436035
checkSourceFileWorker(node);
3601536036
performance.mark("afterCheck");
3601636037
performance.measure("Check", "beforeCheck", "afterCheck");
36038+
tracing.end();
3601736039
}
3601836040

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

Diff for: src/compiler/commandLineParser.ts

+8
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,14 @@ 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+
paramType: Diagnostics.FILE_OR_DIRECTORY,
205+
category: Diagnostics.Advanced_Options,
206+
description: Diagnostics.Generates_an_event_trace_and_a_list_of_types
207+
},
200208
{
201209
name: "incremental",
202210
shortName: "i",

Diff for: src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -4482,6 +4482,10 @@
44824482
"category": "Error",
44834483
"code": 6236
44844484
},
4485+
"Generates an event trace and a list of types.": {
4486+
"category": "Message",
4487+
"code": 6237
4488+
},
44854489

44864490
"Projects to reference": {
44874491
"category": "Message",

Diff for: 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) {

Diff for: src/compiler/parser.ts

+2
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,7 @@ namespace ts {
604604
}
605605

606606
export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
607+
tracing.begin(tracing.Phase.Parse, "createSourceFile", { path: fileName });
607608
performance.mark("beforeParse");
608609
let result: SourceFile;
609610

@@ -618,6 +619,7 @@ namespace ts {
618619

619620
performance.mark("afterParse");
620621
performance.measure("Parse", "beforeParse", "afterParse");
622+
tracing.end();
621623
return result;
622624
}
623625

Diff for: 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 {

Diff for: src/compiler/sys.ts

+25-3
Original file line numberDiff line numberDiff line change
@@ -1047,11 +1047,13 @@ namespace ts {
10471047
args: string[];
10481048
newLine: string;
10491049
useCaseSensitiveFileNames: boolean;
1050-
write(s: string): void;
1050+
write(s: string, fd?: number): void;
10511051
writeOutputIsTTY?(): boolean;
10521052
readFile(path: string, encoding?: string): string | undefined;
10531053
getFileSize?(path: string): number;
10541054
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
1055+
openFile(path: string, mode: "w"): number | undefined;
1056+
closeFile(fd: number): void;
10551057

10561058
/**
10571059
* @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that
@@ -1183,12 +1185,32 @@ namespace ts {
11831185
args: process.argv.slice(2),
11841186
newLine: _os.EOL,
11851187
useCaseSensitiveFileNames,
1186-
write(s: string): void {
1187-
process.stdout.write(s);
1188+
write(s: string, fd?: number): void {
1189+
if (fd) {
1190+
_fs.writeSync(fd, s);
1191+
}
1192+
else {
1193+
process.stdout.write(s);
1194+
}
11881195
},
11891196
writeOutputIsTTY() {
11901197
return process.stdout.isTTY;
11911198
},
1199+
openFile: (path, mode) => {
1200+
try {
1201+
return _fs.openSync(path, mode);
1202+
}
1203+
catch {
1204+
return undefined;
1205+
}
1206+
},
1207+
closeFile: (fd) => {
1208+
try {
1209+
_fs.closeSync(fd);
1210+
}
1211+
catch {
1212+
}
1213+
},
11921214
readFile,
11931215
writeFile,
11941216
watchFile,

0 commit comments

Comments
 (0)