Skip to content

Commit

Permalink
Merge pull request #40063 from amcasey/ChromeTracing
Browse files Browse the repository at this point in the history
Trace key operations
  • Loading branch information
amcasey committed Sep 10, 2020
2 parents 0a5f533 + ef1481c commit 45dedd6
Show file tree
Hide file tree
Showing 17 changed files with 377 additions and 11 deletions.
2 changes: 2 additions & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,14 @@ namespace ts {
const binder = createBinder();

export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
tracing.begin(tracing.Phase.Bind, "bindSourceFile", { path: file.path });
performance.mark("beforeBind");
perfLogger.logStartBindFile("" + file.fileName);
binder(file, options);
perfLogger.logStopBindFile();
performance.mark("afterBind");
performance.measure("Bind", "beforeBind", "afterBind");
tracing.end();
}

function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
Expand Down
47 changes: 45 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ namespace ts {
let constraintDepth = 0;
let currentNode: Node | undefined;

const typeCatalog: Type[] = []; // NB: id is index + 1

const emptySymbols = createSymbolTable();
const arrayVariances = [VarianceFlags.Covariant];

Expand Down Expand Up @@ -366,6 +368,7 @@ namespace ts {
getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + symbolCount,
getTypeCatalog: () => typeCatalog,
getTypeCount: () => typeCount,
getInstantiationCount: () => totalInstantiationCount,
getRelationCacheSizes: () => ({
Expand All @@ -380,6 +383,7 @@ namespace ts {
getMergedSymbol,
getDiagnostics,
getGlobalDiagnostics,
getRecursionIdentity,
getTypeOfSymbolAtLocation: (symbol, locationIn) => {
const location = getParseTreeNode(locationIn);
return location ? getTypeOfSymbolAtLocation(symbol, location) : errorType;
Expand Down Expand Up @@ -3674,6 +3678,7 @@ namespace ts {
const result = new Type(checker, flags);
typeCount++;
result.id = typeCount;
typeCatalog.push(result);
return result;
}

Expand Down Expand Up @@ -10847,6 +10852,7 @@ namespace ts {
// very high likelihood we're dealing with an infinite generic type that perpetually generates
// new type identities as we descend into it. We stop the recursion here and mark this type
// and the outer types as having circular constraints.
tracing.instant(tracing.Phase.Check, "getImmediateBaseConstraint_DepthLimit", { typeId: t.id, originalTypeId: type.id, depth: constraintDepth });
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
nonTerminating = true;
return t.immediateBaseConstraint = noConstraintType;
Expand Down Expand Up @@ -12936,6 +12942,7 @@ namespace ts {
// caps union types at 5000 unique literal types and 1000 unique object types.
const estimatedCount = (count / (len - i)) * len;
if (estimatedCount > (primitivesOnly ? 25000000 : 1000000)) {
tracing.instant(tracing.Phase.Check, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
return false;
}
Expand Down Expand Up @@ -15096,6 +15103,7 @@ namespace ts {
// We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
// with a combination of infinite generic types that perpetually generate new type identities. We stop
// the recursion here by yielding the error type.
tracing.instant(tracing.Phase.Check, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount });
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
return errorType;
}
Expand Down Expand Up @@ -16195,6 +16203,7 @@ namespace ts {
containingMessageChain?: () => DiagnosticMessageChain | undefined,
errorOutputContainer?: { errors?: Diagnostic[], skipLogging?: boolean },
): boolean {

let errorInfo: DiagnosticMessageChain | undefined;
let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined;
let maybeKeys: string[];
Expand All @@ -16216,6 +16225,7 @@ namespace ts {
reportIncompatibleStack();
}
if (overflow) {
tracing.instant(tracing.Phase.Check, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth });
const diag = error(errorNode || currentNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
if (errorOutputContainer) {
(errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag);
Expand Down Expand Up @@ -16257,6 +16267,8 @@ namespace ts {
if (errorNode && errorOutputContainer && errorOutputContainer.skipLogging && result === Ternary.False) {
Debug.assert(!!errorOutputContainer.errors, "missed opportunity to interact with error.");
}


return result !== Ternary.False;

function resetErrorInfo(saved: ReturnType<typeof captureErrorCalculationState>) {
Expand Down Expand Up @@ -17034,6 +17046,17 @@ namespace ts {
return originalHandler!(onlyUnreliable);
};
}

if (expandingFlags === ExpandingFlags.Both) {
tracing.instant(tracing.Phase.Check, "recursiveTypeRelatedTo_DepthLimit", {
sourceId: source.id,
sourceIdStack: sourceStack.map(t => t.id),
targetId: target.id,
targetIdStack: targetStack.map(t => t.id),
depth,
});
}

const result = expandingFlags !== ExpandingFlags.Both ? structuredTypeRelatedTo(source, target, reportErrors, intersectionState) : Ternary.Maybe;
if (outofbandVarianceMarkerHandler) {
outofbandVarianceMarkerHandler = originalHandler;
Expand All @@ -17059,6 +17082,13 @@ namespace ts {
}

function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
tracing.begin(tracing.Phase.Check, "structuredTypeRelatedTo", { sourceId: source.id, targetId: target.id });
const result = structuredTypeRelatedToWorker(source, target, reportErrors, intersectionState);
tracing.end();
return result;
}

function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
if (intersectionState & IntersectionState.PropertyCheck) {
return propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None);
}
Expand Down Expand Up @@ -17517,6 +17547,7 @@ namespace ts {
numCombinations *= countTypes(getTypeOfSymbol(sourceProperty));
if (numCombinations > 25) {
// We've reached the complexity limit.
tracing.instant(tracing.Phase.Check, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations });
return Ternary.False;
}
}
Expand Down Expand Up @@ -18267,6 +18298,7 @@ namespace ts {
function getVariancesWorker<TCache extends { variances?: VarianceFlags[] }>(typeParameters: readonly TypeParameter[] = emptyArray, cache: TCache, createMarkerType: (input: TCache, param: TypeParameter, marker: Type) => Type): VarianceFlags[] {
let variances = cache.variances;
if (!variances) {
tracing.begin(tracing.Phase.Check, "getVariancesWorker", { arity: typeParameters.length, id: (cache as any).id ?? (cache as any).declaredType?.id ?? -1 });
// The emptyArray singleton is used to signal a recursive invocation.
cache.variances = emptyArray;
variances = [];
Expand Down Expand Up @@ -18301,6 +18333,7 @@ namespace ts {
variances.push(variance);
}
cache.variances = variances;
tracing.end();
}
return variances;
}
Expand Down Expand Up @@ -18449,7 +18482,9 @@ namespace ts {
for (let i = 0; i < depth; i++) {
if (getRecursionIdentity(stack[i]) === identity) {
count++;
if (count >= 5) return true;
if (count >= 5) {
return true;
}
}
}
}
Expand Down Expand Up @@ -19554,6 +19589,7 @@ namespace ts {
inferFromTypes(originalSource, originalTarget);

function inferFromTypes(source: Type, target: Type): void {

if (!couldContainTypeVariables(target)) {
return;
}
Expand Down Expand Up @@ -21296,6 +21332,7 @@ namespace ts {
if (flowDepth === 2000) {
// We have made 2000 recursive invocations. To avoid overflowing the call stack we report an error
// and disable further control flow analysis in the containing function or module body.
tracing.instant(tracing.Phase.Check, "getTypeAtFlowNode_DepthLimit", { flowId: flow.id });
flowAnalysisDisabled = true;
reportFlowControlError(reference);
return errorType;
Expand Down Expand Up @@ -30504,6 +30541,7 @@ namespace ts {
}

function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
tracing.begin(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end });
const saveCurrentNode = currentNode;
currentNode = node;
instantiationCount = 0;
Expand All @@ -30513,6 +30551,7 @@ namespace ts {
checkConstEnumAccess(node, type);
}
currentNode = saveCurrentNode;
tracing.end();
return type;
}

Expand Down Expand Up @@ -33306,8 +33345,10 @@ namespace ts {
}

function checkVariableDeclaration(node: VariableDeclaration) {
tracing.begin(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end });
checkGrammarVariableDeclaration(node);
return checkVariableLikeDeclaration(node);
checkVariableLikeDeclaration(node);
tracing.end();
}

function checkBindingElement(node: BindingElement) {
Expand Down Expand Up @@ -36348,10 +36389,12 @@ namespace ts {
}

function checkSourceFile(node: SourceFile) {
tracing.begin(tracing.Phase.Check, "checkSourceFile", { path: node.path });
performance.mark("beforeCheck");
checkSourceFileWorker(node);
performance.mark("afterCheck");
performance.measure("Check", "beforeCheck", "afterCheck");
tracing.end();
}

function unusedIsError(kind: UnusedKind, isAmbient: boolean): boolean {
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,15 @@ namespace ts {
category: Diagnostics.Advanced_Options,
description: Diagnostics.Generates_a_CPU_profile
},
{
name: "generateTrace",
type: "string",
isFilePath: true,
isCommandLineOnly: true,
paramType: Diagnostics.DIRECTORY,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Generates_an_event_trace_and_a_list_of_types
},
{
name: "incremental",
shortName: "i",
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -4497,6 +4497,10 @@
"category": "Error",
"code": 6236
},
"Generates an event trace and a list of types.": {
"category": "Message",
"code": 6237
},

"Projects to reference": {
"category": "Message",
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,17 @@ namespace ts {
sourceFiles: sourceFileOrBundle.sourceFiles.map(file => relativeToBuildInfo(getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory())))
};
}
tracing.begin(tracing.Phase.Emit, "emitJsFileOrBundle", { jsFilePath });
emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath, relativeToBuildInfo);
tracing.end();

tracing.begin(tracing.Phase.Emit, "emitDeclarationFileOrBundle", { declarationFilePath });
emitDeclarationFileOrBundle(sourceFileOrBundle, declarationFilePath, declarationMapPath, relativeToBuildInfo);
tracing.end();

tracing.begin(tracing.Phase.Emit, "emitBuildInfo", { buildInfoPath });
emitBuildInfo(bundleBuildInfo, buildInfoPath);
tracing.end();

if (!emitSkipped && emittedFilesList) {
if (!emitOnlyDtsFiles) {
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ namespace ts {
}

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

Expand All @@ -628,6 +629,7 @@ namespace ts {

performance.mark("afterParse");
performance.measure("Parse", "beforeParse", "afterParse");
tracing.end();
return result;
}

Expand Down
10 changes: 9 additions & 1 deletion src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ namespace ts {
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
const sourceFilesFoundSearchingNodeModules = new Map<string, boolean>();

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

const host = createProgramOptions.host || createCompilerHost(options);
Expand Down Expand Up @@ -948,6 +949,7 @@ namespace ts {
getNodeCount: () => getDiagnosticsProducingTypeChecker().getNodeCount(),
getIdentifierCount: () => getDiagnosticsProducingTypeChecker().getIdentifierCount(),
getSymbolCount: () => getDiagnosticsProducingTypeChecker().getSymbolCount(),
getTypeCatalog: () => getDiagnosticsProducingTypeChecker().getTypeCatalog(),
getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(),
getInstantiationCount: () => getDiagnosticsProducingTypeChecker().getInstantiationCount(),
getRelationCacheSizes: () => getDiagnosticsProducingTypeChecker().getRelationCacheSizes(),
Expand Down Expand Up @@ -982,6 +984,7 @@ namespace ts {
verifyCompilerOptions();
performance.mark("afterProgram");
performance.measure("Program", "beforeProgram", "afterProgram");
tracing.end();

return program;

Expand Down Expand Up @@ -1505,6 +1508,7 @@ namespace ts {

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

performance.mark("afterEmit");
performance.measure("Emit", "beforeEmit", "afterEmit");
tracing.end();
return emitResult;
}

Expand Down Expand Up @@ -1577,7 +1582,10 @@ namespace ts {
}

function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, transformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
return runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers, forceDtsEmit));
tracing.begin(tracing.Phase.Emit, "emit", { path: sourceFile?.path });
const result = runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers, forceDtsEmit));
tracing.end();
return result;
}

function isEmitBlocked(emitFileName: string): boolean {
Expand Down
Loading

0 comments on commit 45dedd6

Please sign in to comment.