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

Trace key operations #40063

Merged
merged 6 commits into from
Sep 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -317,6 +317,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 @@ -360,6 +362,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 @@ -374,6 +377,7 @@ namespace ts {
getMergedSymbol,
getDiagnostics,
getGlobalDiagnostics,
getRecursionIdentity,
getTypeOfSymbolAtLocation: (symbol, locationIn) => {
const location = getParseTreeNode(locationIn);
return location ? getTypeOfSymbolAtLocation(symbol, location) : errorType;
Expand Down Expand Up @@ -3661,6 +3665,7 @@ namespace ts {
const result = new Type(checker, flags);
typeCount++;
result.id = typeCount;
typeCatalog.push(result);
return result;
}

Expand Down Expand Up @@ -10799,6 +10804,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 @@ -12873,6 +12879,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 @@ -14935,6 +14942,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 @@ -16031,6 +16039,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 @@ -16052,6 +16061,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 @@ -16093,6 +16103,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 @@ -16870,6 +16882,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 @@ -16895,6 +16918,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 @@ -17343,6 +17373,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 @@ -18082,6 +18113,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 @@ -18116,6 +18148,7 @@ namespace ts {
variances.push(variance);
}
cache.variances = variances;
tracing.end();
}
return variances;
}
Expand Down Expand Up @@ -18264,7 +18297,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 @@ -19369,6 +19404,7 @@ namespace ts {
inferFromTypes(originalSource, originalTarget);

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

if (!couldContainTypeVariables(target)) {
return;
}
Expand Down Expand Up @@ -21071,6 +21107,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 @@ -30257,6 +30294,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 @@ -30266,6 +30304,7 @@ namespace ts {
checkConstEnumAccess(node, type);
}
currentNode = saveCurrentNode;
tracing.end();
return type;
}

Expand Down Expand Up @@ -33032,8 +33071,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 @@ -36069,10 +36110,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 @@ -4486,6 +4486,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 @@ -604,6 +604,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 @@ -618,6 +619,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