mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Re-do tracing initialization and tests around calls
Make `tracing` either `undefined` or the same namespace as before.
Switching all calls to `tracing?.___` means that there is no cost for
a call or the arguments when tracing is not used. Comparing two runs
without tracing (27 runs, drop 5+5, avg rest) I get:
master:
42.59s user 1.00s system 165% cpu 26.372 total
changed:
42.01s user 0.982 system 165% cpu 26.039 total
(Makes it all private, so no api changes.)
This commit is contained in:
@@ -174,14 +174,14 @@ namespace ts {
|
||||
const binder = createBinder();
|
||||
|
||||
export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
|
||||
tracing.push(tracing.Phase.Bind, "bindSourceFile", { path: file.path }, /*separateBeginAndEnd*/ true);
|
||||
tracing?.push(tracing.Phase.Bind, "bindSourceFile", { path: file.path }, /*separateBeginAndEnd*/ true);
|
||||
performance.mark("beforeBind");
|
||||
perfLogger.logStartBindFile("" + file.fileName);
|
||||
binder(file, options);
|
||||
perfLogger.logStopBindFile();
|
||||
performance.mark("afterBind");
|
||||
performance.measure("Bind", "beforeBind", "afterBind");
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
}
|
||||
|
||||
function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
|
||||
|
||||
+20
-20
@@ -13338,7 +13338,7 @@ namespace ts {
|
||||
// caps union types at 1000 unique object types.
|
||||
const estimatedCount = (count / (len - i)) * len;
|
||||
if (estimatedCount > 1000000) {
|
||||
tracing.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
|
||||
tracing?.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
|
||||
error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
|
||||
return false;
|
||||
}
|
||||
@@ -13817,7 +13817,7 @@ namespace ts {
|
||||
function checkCrossProductUnion(types: readonly Type[]) {
|
||||
const size = getCrossProductUnionSize(types);
|
||||
if (size >= 100000) {
|
||||
tracing.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_DepthLimit", { typeIds: types.map(t => t.id), size });
|
||||
tracing?.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_DepthLimit", { typeIds: types.map(t => t.id), size });
|
||||
error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
|
||||
return false;
|
||||
}
|
||||
@@ -15751,7 +15751,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.CheckTypes, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount });
|
||||
tracing?.instant(tracing.Phase.CheckTypes, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount });
|
||||
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
|
||||
return errorType;
|
||||
}
|
||||
@@ -16881,7 +16881,7 @@ namespace ts {
|
||||
reportIncompatibleStack();
|
||||
}
|
||||
if (overflow) {
|
||||
tracing.instant(tracing.Phase.CheckTypes, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth });
|
||||
tracing?.instant(tracing.Phase.CheckTypes, "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);
|
||||
@@ -17368,7 +17368,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function traceUnionsOrIntersectionsTooLarge(source: Type, target: Type): void {
|
||||
if (!tracing.isTracing()) {
|
||||
if (!tracing) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -17730,7 +17730,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (expandingFlags === ExpandingFlags.Both) {
|
||||
tracing.instant(tracing.Phase.CheckTypes, "recursiveTypeRelatedTo_DepthLimit", {
|
||||
tracing?.instant(tracing.Phase.CheckTypes, "recursiveTypeRelatedTo_DepthLimit", {
|
||||
sourceId: source.id,
|
||||
sourceIdStack: sourceStack.map(t => t.id),
|
||||
targetId: target.id,
|
||||
@@ -17767,9 +17767,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
|
||||
tracing.push(tracing.Phase.CheckTypes, "structuredTypeRelatedTo", { sourceId: source.id, targetId: target.id });
|
||||
tracing?.push(tracing.Phase.CheckTypes, "structuredTypeRelatedTo", { sourceId: source.id, targetId: target.id });
|
||||
const result = structuredTypeRelatedToWorker(source, target, reportErrors, intersectionState);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -18294,7 +18294,7 @@ namespace ts {
|
||||
numCombinations *= countTypes(getTypeOfSymbol(sourceProperty));
|
||||
if (numCombinations > 25) {
|
||||
// We've reached the complexity limit.
|
||||
tracing.instant(tracing.Phase.CheckTypes, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations });
|
||||
tracing?.instant(tracing.Phase.CheckTypes, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations });
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
@@ -19073,7 +19073,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.push(tracing.Phase.CheckTypes, "getVariancesWorker", { arity: typeParameters.length, id: (cache as any).id ?? (cache as any).declaredType?.id ?? -1 });
|
||||
tracing?.push(tracing.Phase.CheckTypes, "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 = [];
|
||||
@@ -19108,7 +19108,7 @@ namespace ts {
|
||||
variances.push(variance);
|
||||
}
|
||||
cache.variances = variances;
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
}
|
||||
return variances;
|
||||
}
|
||||
@@ -22199,7 +22199,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.CheckTypes, "getTypeAtFlowNode_DepthLimit", { flowId: flow.id });
|
||||
tracing?.instant(tracing.Phase.CheckTypes, "getTypeAtFlowNode_DepthLimit", { flowId: flow.id });
|
||||
flowAnalysisDisabled = true;
|
||||
reportFlowControlError(reference);
|
||||
return errorType;
|
||||
@@ -31673,7 +31673,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
|
||||
tracing.push(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end });
|
||||
tracing?.push(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end });
|
||||
const saveCurrentNode = currentNode;
|
||||
currentNode = node;
|
||||
instantiationCount = 0;
|
||||
@@ -31683,7 +31683,7 @@ namespace ts {
|
||||
checkConstEnumAccess(node, type);
|
||||
}
|
||||
currentNode = saveCurrentNode;
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -34489,10 +34489,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkVariableDeclaration(node: VariableDeclaration) {
|
||||
tracing.push(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end });
|
||||
tracing?.push(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end });
|
||||
checkGrammarVariableDeclaration(node);
|
||||
checkVariableLikeDeclaration(node);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
}
|
||||
|
||||
function checkBindingElement(node: BindingElement) {
|
||||
@@ -37570,7 +37570,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkDeferredNode(node: Node) {
|
||||
tracing.push(tracing.Phase.Check, "checkDeferredNode", { kind: node.kind, pos: node.pos, end: node.end });
|
||||
tracing?.push(tracing.Phase.Check, "checkDeferredNode", { kind: node.kind, pos: node.pos, end: node.end });
|
||||
const saveCurrentNode = currentNode;
|
||||
currentNode = node;
|
||||
instantiationCount = 0;
|
||||
@@ -37606,16 +37606,16 @@ namespace ts {
|
||||
break;
|
||||
}
|
||||
currentNode = saveCurrentNode;
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
}
|
||||
|
||||
function checkSourceFile(node: SourceFile) {
|
||||
tracing.push(tracing.Phase.Check, "checkSourceFile", { path: node.path }, /*separateBeginAndEnd*/ true);
|
||||
tracing?.push(tracing.Phase.Check, "checkSourceFile", { path: node.path }, /*separateBeginAndEnd*/ true);
|
||||
performance.mark("beforeCheck");
|
||||
checkSourceFileWorker(node);
|
||||
performance.mark("afterCheck");
|
||||
performance.measure("Check", "beforeCheck", "afterCheck");
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
}
|
||||
|
||||
function unusedIsError(kind: UnusedKind, isAmbient: boolean): boolean {
|
||||
|
||||
@@ -340,17 +340,17 @@ namespace ts {
|
||||
sourceFiles: sourceFileOrBundle.sourceFiles.map(file => relativeToBuildInfo(getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory())))
|
||||
};
|
||||
}
|
||||
tracing.push(tracing.Phase.Emit, "emitJsFileOrBundle", { jsFilePath });
|
||||
tracing?.push(tracing.Phase.Emit, "emitJsFileOrBundle", { jsFilePath });
|
||||
emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath, relativeToBuildInfo);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
|
||||
tracing.push(tracing.Phase.Emit, "emitDeclarationFileOrBundle", { declarationFilePath });
|
||||
tracing?.push(tracing.Phase.Emit, "emitDeclarationFileOrBundle", { declarationFilePath });
|
||||
emitDeclarationFileOrBundle(sourceFileOrBundle, declarationFilePath, declarationMapPath, relativeToBuildInfo);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
|
||||
tracing.push(tracing.Phase.Emit, "emitBuildInfo", { buildInfoPath });
|
||||
tracing?.push(tracing.Phase.Emit, "emitBuildInfo", { buildInfoPath });
|
||||
emitBuildInfo(bundleBuildInfo, buildInfoPath);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
|
||||
if (!emitSkipped && emittedFilesList) {
|
||||
if (!emitOnlyDtsFiles) {
|
||||
|
||||
@@ -607,7 +607,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
|
||||
tracing.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true);
|
||||
tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true);
|
||||
performance.mark("beforeParse");
|
||||
let result: SourceFile;
|
||||
|
||||
@@ -622,7 +622,7 @@ namespace ts {
|
||||
|
||||
performance.mark("afterParse");
|
||||
performance.measure("Parse", "beforeParse", "afterParse");
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+22
-22
@@ -833,7 +833,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.push(tracing.Phase.Program, "createProgram", { configFilePath: options.configFilePath, rootDir: options.rootDir }, /*separateBeginAndEnd*/ true);
|
||||
tracing?.push(tracing.Phase.Program, "createProgram", { configFilePath: options.configFilePath, rootDir: options.rootDir }, /*separateBeginAndEnd*/ true);
|
||||
performance.mark("beforeProgram");
|
||||
|
||||
const host = createProgramOptions.host || createCompilerHost(options);
|
||||
@@ -919,15 +919,15 @@ namespace ts {
|
||||
forEachResolvedProjectReference
|
||||
});
|
||||
|
||||
tracing.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram });
|
||||
tracing?.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram });
|
||||
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
// We set `structuralIsReused` to `undefined` because `tryReuseStructureFromOldProgram` calls `tryReuseStructureFromOldProgram` which checks
|
||||
// `structuralIsReused`, which would be a TDZ violation if it was not set in advance to `undefined`.
|
||||
let structureIsReused: StructureIsReused;
|
||||
tracing.push(tracing.Phase.Program, "tryReuseStructureFromOldProgram", {});
|
||||
tracing?.push(tracing.Phase.Program, "tryReuseStructureFromOldProgram", {});
|
||||
structureIsReused = tryReuseStructureFromOldProgram(); // eslint-disable-line prefer-const
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
if (structureIsReused !== StructureIsReused.Completely) {
|
||||
processingDefaultLibFiles = [];
|
||||
processingOtherFiles = [];
|
||||
@@ -964,15 +964,15 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
tracing.push(tracing.Phase.Program, "processRootFiles", { count: rootNames.length });
|
||||
tracing?.push(tracing.Phase.Program, "processRootFiles", { count: rootNames.length });
|
||||
forEach(rootNames, (name, index) => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.RootFile, index }));
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
|
||||
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
|
||||
const typeReferences: string[] = rootNames.length ? getAutomaticTypeDirectiveNames(options, host) : emptyArray;
|
||||
|
||||
if (typeReferences.length) {
|
||||
tracing.push(tracing.Phase.Program, "processTypeReferences", { count: typeReferences.length });
|
||||
tracing?.push(tracing.Phase.Program, "processTypeReferences", { count: typeReferences.length });
|
||||
// This containingFilename needs to match with the one used in managed-side
|
||||
const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : host.getCurrentDirectory();
|
||||
const containingFilename = combinePaths(containingDirectory, inferredTypesContainingFile);
|
||||
@@ -980,7 +980,7 @@ namespace ts {
|
||||
for (let i = 0; i < typeReferences.length; i++) {
|
||||
processTypeReferenceDirective(typeReferences[i], resolutions[i], { kind: FileIncludeKind.AutomaticTypeDirectiveFile, typeReference: typeReferences[i], packageId: resolutions[i]?.packageId });
|
||||
}
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
}
|
||||
|
||||
// Do not process the default library if:
|
||||
@@ -1108,7 +1108,7 @@ namespace ts {
|
||||
verifyCompilerOptions();
|
||||
performance.mark("afterProgram");
|
||||
performance.measure("Program", "beforeProgram", "afterProgram");
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
|
||||
return program;
|
||||
|
||||
@@ -1116,12 +1116,12 @@ namespace ts {
|
||||
if (!moduleNames.length) return emptyArray;
|
||||
const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
|
||||
const redirectedReference = getRedirectReferenceForResolution(containingFile);
|
||||
tracing.push(tracing.Phase.Program, "resolveModuleNamesWorker", { containingFileName });
|
||||
tracing?.push(tracing.Phase.Program, "resolveModuleNamesWorker", { containingFileName });
|
||||
performance.mark("beforeResolveModule");
|
||||
const result = actualResolveModuleNamesWorker(moduleNames, containingFileName, reusedNames, redirectedReference);
|
||||
performance.mark("afterResolveModule");
|
||||
performance.measure("ResolveModule", "beforeResolveModule", "afterResolveModule");
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1129,12 +1129,12 @@ namespace ts {
|
||||
if (!typeDirectiveNames.length) return [];
|
||||
const containingFileName = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile;
|
||||
const redirectedReference = !isString(containingFile) ? getRedirectReferenceForResolution(containingFile) : undefined;
|
||||
tracing.push(tracing.Phase.Program, "resolveTypeReferenceDirectiveNamesWorker", { containingFileName });
|
||||
tracing?.push(tracing.Phase.Program, "resolveTypeReferenceDirectiveNamesWorker", { containingFileName });
|
||||
performance.mark("beforeResolveTypeReference");
|
||||
const result = actualResolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFileName, redirectedReference);
|
||||
performance.mark("afterResolveTypeReference");
|
||||
performance.measure("ResolveTypeReference", "beforeResolveTypeReference", "afterResolveTypeReference");
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1655,7 +1655,7 @@ namespace ts {
|
||||
|
||||
function emitBuildInfo(writeFileCallback?: WriteFileCallback): EmitResult {
|
||||
Debug.assert(!outFile(options));
|
||||
tracing.push(tracing.Phase.Emit, "emitBuildInfo", {}, /*separateBeginAndEnd*/ true);
|
||||
tracing?.push(tracing.Phase.Emit, "emitBuildInfo", {}, /*separateBeginAndEnd*/ true);
|
||||
performance.mark("beforeEmit");
|
||||
const emitResult = emitFiles(
|
||||
notImplementedResolver,
|
||||
@@ -1668,7 +1668,7 @@ namespace ts {
|
||||
|
||||
performance.mark("afterEmit");
|
||||
performance.measure("Emit", "beforeEmit", "afterEmit");
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
return emitResult;
|
||||
}
|
||||
|
||||
@@ -1729,9 +1729,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, transformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
|
||||
tracing.push(tracing.Phase.Emit, "emit", { path: sourceFile?.path }, /*separateBeginAndEnd*/ true);
|
||||
tracing?.push(tracing.Phase.Emit, "emit", { path: sourceFile?.path }, /*separateBeginAndEnd*/ true);
|
||||
const result = runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers, forceDtsEmit));
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2485,13 +2485,13 @@ namespace ts {
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
tracing.push(tracing.Phase.Program, "findSourceFile", {
|
||||
tracing?.push(tracing.Phase.Program, "findSourceFile", {
|
||||
fileName,
|
||||
isDefaultLib: isDefaultLib || undefined,
|
||||
fileIncludeKind: (FileIncludeKind as any)[reason.kind],
|
||||
});
|
||||
const result = findSourceFileWorker(fileName, path, isDefaultLib, ignoreNoDefaultLib, reason, packageId);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2792,9 +2792,9 @@ namespace ts {
|
||||
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined,
|
||||
reason: FileIncludeReason
|
||||
): void {
|
||||
tracing.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolveModuleNamesReusingOldState, refKind: reason.kind, refPath: isReferencedFile(reason) ? reason.file : undefined });
|
||||
tracing?.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolveModuleNamesReusingOldState, refKind: reason.kind, refPath: isReferencedFile(reason) ? reason.file : undefined });
|
||||
processTypeReferenceDirectiveWorker(typeReferenceDirective, resolvedTypeReferenceDirective, reason);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
}
|
||||
|
||||
function processTypeReferenceDirectiveWorker(
|
||||
|
||||
+30
-36
@@ -1,16 +1,25 @@
|
||||
/* Tracing events for the compiler. */
|
||||
|
||||
/*@internal*/
|
||||
/** Tracing events for the compiler. */
|
||||
namespace ts.tracing {
|
||||
namespace ts { // eslint-disable-line one-namespace-per-file
|
||||
// should be used as tracing?.___
|
||||
export let tracing: typeof tracingEnabled | undefined;
|
||||
// enable the above using startTracing()
|
||||
}
|
||||
|
||||
// `tracingEnabled` should never be used directly, only through the above
|
||||
/* @internal */
|
||||
namespace ts.tracingEnabled { // eslint-disable-line one-namespace-per-file
|
||||
export const enum Mode {
|
||||
Project,
|
||||
Build,
|
||||
Server,
|
||||
}
|
||||
|
||||
let fs: typeof import("fs") | false | undefined;
|
||||
let fs: typeof import("fs");
|
||||
|
||||
let traceCount = 0;
|
||||
let traceFd: number | undefined;
|
||||
let traceFd = 0;
|
||||
|
||||
let mode: Mode;
|
||||
|
||||
@@ -22,23 +31,19 @@ namespace ts.tracing {
|
||||
[key: string]: string | number | boolean | null | undefined | Args | readonly (string | number | boolean | null | undefined | Args)[];
|
||||
};
|
||||
|
||||
/** Starts tracing for the given project (unless the `fs` module is unavailable). */
|
||||
/** Starts tracing for the given project. */
|
||||
export function startTracing(tracingMode: Mode, traceDir: string, configFilePath?: string) {
|
||||
Debug.assert(!traceFd, "Tracing already started");
|
||||
Debug.assert(!tracing, "Tracing already started");
|
||||
|
||||
if (fs === undefined) {
|
||||
try {
|
||||
fs = require("fs");
|
||||
}
|
||||
catch {
|
||||
fs = false;
|
||||
catch (e) {
|
||||
throw new Error(`tracing requires having fs\n(original error: ${e.message || e})`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fs) {
|
||||
return;
|
||||
}
|
||||
|
||||
mode = tracingMode;
|
||||
|
||||
if (legendPath === undefined) {
|
||||
@@ -51,9 +56,9 @@ namespace ts.tracing {
|
||||
}
|
||||
|
||||
const countPart =
|
||||
mode === Mode.Build ? `.${process.pid}-${++traceCount}` :
|
||||
mode === Mode.Server ? `.${process.pid}` :
|
||||
``;
|
||||
mode === Mode.Build ? `.${process.pid}-${++traceCount}`
|
||||
: mode === Mode.Server ? `.${process.pid}`
|
||||
: ``;
|
||||
const tracePath = combinePaths(traceDir, `trace${countPart}.json`);
|
||||
const typesPath = combinePaths(traceDir, `types${countPart}.json`);
|
||||
|
||||
@@ -64,6 +69,7 @@ namespace ts.tracing {
|
||||
});
|
||||
|
||||
traceFd = fs.openSync(tracePath, "w");
|
||||
tracing = tracingEnabled; // only when traceFd is properly set
|
||||
|
||||
// Start with a prefix that contains some metadata that the devtools profiler expects (also avoids a warning on import)
|
||||
const meta = { cat: "__metadata", ph: "M", ts: 1000 * timestamp(), pid: 1, tid: 1 };
|
||||
@@ -75,19 +81,14 @@ namespace ts.tracing {
|
||||
.map(v => JSON.stringify(v)).join(",\n"));
|
||||
}
|
||||
|
||||
/** Stops tracing for the in-progress project and dumps the type catalog (unless the `fs` module is unavailable). */
|
||||
/** Stops tracing for the in-progress project and dumps the type catalog. */
|
||||
export function stopTracing(typeCatalog?: readonly Type[]) {
|
||||
if (!traceFd) {
|
||||
Debug.assert(!fs, "Tracing is not in progress");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.assert(fs);
|
||||
Debug.assert(tracing, "Tracing is not in progress");
|
||||
Debug.assert(!!typeCatalog === (mode !== Mode.Server)); // Have a type catalog iff not in server mode
|
||||
|
||||
fs.writeSync(traceFd, `\n]\n`);
|
||||
fs.closeSync(traceFd);
|
||||
traceFd = undefined;
|
||||
tracing = undefined;
|
||||
|
||||
if (typeCatalog) {
|
||||
dumpTypes(typeCatalog);
|
||||
@@ -99,10 +100,6 @@ namespace ts.tracing {
|
||||
}
|
||||
}
|
||||
|
||||
export function isTracing() {
|
||||
return !!traceFd;
|
||||
}
|
||||
|
||||
export const enum Phase {
|
||||
Parse = "parse",
|
||||
Program = "program",
|
||||
@@ -114,7 +111,6 @@ namespace ts.tracing {
|
||||
}
|
||||
|
||||
export function instant(phase: Phase, name: string, args?: Args) {
|
||||
if (!traceFd) return;
|
||||
writeEvent("I", phase, name, args, `"s":"g"`);
|
||||
}
|
||||
|
||||
@@ -127,20 +123,17 @@ namespace ts.tracing {
|
||||
* these operations.
|
||||
*/
|
||||
export function push(phase: Phase, name: string, args?: Args, separateBeginAndEnd = false) {
|
||||
if (!traceFd) return;
|
||||
if (separateBeginAndEnd) {
|
||||
writeEvent("B", phase, name, args);
|
||||
}
|
||||
eventStack.push({ phase, name, args, time: 1000 * timestamp(), separateBeginAndEnd });
|
||||
}
|
||||
export function pop() {
|
||||
if (!traceFd) return;
|
||||
Debug.assert(eventStack.length > 0);
|
||||
writeStackEvent(eventStack.length - 1, 1000 * timestamp());
|
||||
eventStack.length--;
|
||||
}
|
||||
export function popAll() {
|
||||
if (!traceFd) return;
|
||||
const endTime = 1000 * timestamp();
|
||||
for (let i = eventStack.length - 1; i >= 0; i--) {
|
||||
writeStackEvent(i, endTime);
|
||||
@@ -159,8 +152,6 @@ namespace ts.tracing {
|
||||
|
||||
function writeEvent(eventType: string, phase: Phase, name: string, args: Args | undefined, extras?: string,
|
||||
time: number = 1000 * timestamp()) {
|
||||
Debug.assert(traceFd);
|
||||
Debug.assert(fs);
|
||||
|
||||
// In server mode, there's no easy way to dump type information, so we drop events that would require it.
|
||||
if (mode === Mode.Server && phase === Phase.CheckTypes) return;
|
||||
@@ -182,8 +173,6 @@ namespace ts.tracing {
|
||||
}
|
||||
|
||||
function dumpTypes(types: readonly Type[]) {
|
||||
Debug.assert(fs);
|
||||
|
||||
performance.mark("beginDumpTypes");
|
||||
|
||||
const typesPath = legend[legend.length - 1].typesPath!;
|
||||
@@ -293,7 +282,6 @@ namespace ts.tracing {
|
||||
if (!legendPath) {
|
||||
return;
|
||||
}
|
||||
Debug.assert(fs);
|
||||
|
||||
fs.writeFileSync(legendPath, JSON.stringify(legend));
|
||||
}
|
||||
@@ -304,3 +292,9 @@ namespace ts.tracing {
|
||||
typesPath?: string;
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
namespace ts { // eslint-disable-line one-namespace-per-file
|
||||
// define after tracingEnabled is initialized
|
||||
export const startTracing = tracingEnabled.startTracing;
|
||||
}
|
||||
|
||||
@@ -223,9 +223,9 @@ namespace ts {
|
||||
// Transform each node.
|
||||
const transformed: T[] = [];
|
||||
for (const node of nodes) {
|
||||
tracing.push(tracing.Phase.Emit, "transformNodes", node.kind === SyntaxKind.SourceFile ? { path: (node as any as SourceFile).path } : { kind: node.kind, pos: node.pos, end: node.end });
|
||||
tracing?.push(tracing.Phase.Emit, "transformNodes", node.kind === SyntaxKind.SourceFile ? { path: (node as any as SourceFile).path } : { kind: node.kind, pos: node.pos, end: node.end });
|
||||
transformed.push((allowDtsFiles ? transformation : transformRoot)(node));
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
}
|
||||
|
||||
// prevent modification of the lexical environment.
|
||||
|
||||
@@ -5643,7 +5643,7 @@ namespace ts {
|
||||
|
||||
function Type(this: Type, checker: TypeChecker, flags: TypeFlags) {
|
||||
this.flags = flags;
|
||||
if (Debug.isDebugging || tracing.isTracing()) {
|
||||
if (Debug.isDebugging || tracing) {
|
||||
this.checker = checker;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +501,7 @@ namespace ts {
|
||||
updateSolutionBuilderHost(sys, cb, buildHost);
|
||||
const builder = createSolutionBuilder(buildHost, projects, buildOptions);
|
||||
const exitStatus = buildOptions.clean ? builder.clean() : builder.build();
|
||||
tracing.dumpLegend();
|
||||
tracing?.dumpLegend();
|
||||
return sys.exit(exitStatus);
|
||||
}
|
||||
|
||||
@@ -666,7 +666,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (canTrace(system, compilerOptions)) {
|
||||
tracing.startTracing(isBuildMode ? tracing.Mode.Build : tracing.Mode.Project, compilerOptions.generateTrace!, compilerOptions.configFilePath);
|
||||
startTracing(isBuildMode ? tracingEnabled.Mode.Build : tracingEnabled.Mode.Project,
|
||||
compilerOptions.generateTrace!, compilerOptions.configFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,7 +675,7 @@ namespace ts {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
|
||||
if (canTrace(sys, compilerOptions)) {
|
||||
tracing.stopTracing(program.getTypeCatalog());
|
||||
tracing?.stopTracing(program.getTypeCatalog());
|
||||
}
|
||||
|
||||
let statistics: Statistic[];
|
||||
|
||||
+14
-14
@@ -208,25 +208,25 @@ namespace ts.server {
|
||||
try {
|
||||
if (this.operationHost.isCancellationRequested()) {
|
||||
stop = true;
|
||||
tracing.instant(tracing.Phase.Session, "stepCanceled", { seq: this.requestId, early: true });
|
||||
tracing?.instant(tracing.Phase.Session, "stepCanceled", { seq: this.requestId, early: true });
|
||||
}
|
||||
else {
|
||||
tracing.push(tracing.Phase.Session, "stepAction", { seq: this.requestId });
|
||||
tracing?.push(tracing.Phase.Session, "stepAction", { seq: this.requestId });
|
||||
action(this);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// Cancellation or an error may have left incomplete events on the tracing stack.
|
||||
tracing.popAll();
|
||||
tracing?.popAll();
|
||||
|
||||
stop = true;
|
||||
// ignore cancellation request
|
||||
if (e instanceof OperationCanceledException) {
|
||||
tracing.instant(tracing.Phase.Session, "stepCanceled", { seq: this.requestId });
|
||||
tracing?.instant(tracing.Phase.Session, "stepCanceled", { seq: this.requestId });
|
||||
}
|
||||
else {
|
||||
tracing.instant(tracing.Phase.Session, "stepError", { seq: this.requestId, message: (<Error>e).message });
|
||||
tracing?.instant(tracing.Phase.Session, "stepError", { seq: this.requestId, message: (<Error>e).message });
|
||||
this.operationHost.logError(e, `delayed processing of request ${this.requestId}`);
|
||||
}
|
||||
}
|
||||
@@ -947,7 +947,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
public event<T extends object>(body: T, eventName: string): void {
|
||||
tracing.instant(tracing.Phase.Session, "event", { eventName });
|
||||
tracing?.instant(tracing.Phase.Session, "event", { eventName });
|
||||
this.send(toEvent(eventName, body));
|
||||
}
|
||||
|
||||
@@ -2962,12 +2962,12 @@ namespace ts.server {
|
||||
request = this.parseMessage(message);
|
||||
relevantFile = request.arguments && (request as protocol.FileRequest).arguments.file ? (request as protocol.FileRequest).arguments : undefined;
|
||||
|
||||
tracing.instant(tracing.Phase.Session, "request", { seq: request.seq, command: request.command });
|
||||
tracing?.instant(tracing.Phase.Session, "request", { seq: request.seq, command: request.command });
|
||||
perfLogger.logStartCommand("" + request.command, this.toStringMessage(message).substring(0, 100));
|
||||
|
||||
tracing.push(tracing.Phase.Session, "executeCommand", { seq: request.seq, command: request.command }, /*separateBeginAndEnd*/ true);
|
||||
tracing?.push(tracing.Phase.Session, "executeCommand", { seq: request.seq, command: request.command }, /*separateBeginAndEnd*/ true);
|
||||
const { response, responseRequired } = this.executeCommand(request);
|
||||
tracing.pop();
|
||||
tracing?.pop();
|
||||
|
||||
if (this.logger.hasLevel(LogLevel.requestTime)) {
|
||||
const elapsedTime = hrTimeToMilliseconds(this.hrtime(start)).toFixed(4);
|
||||
@@ -2981,7 +2981,7 @@ namespace ts.server {
|
||||
|
||||
// Note: Log before writing the response, else the editor can complete its activity before the server does
|
||||
perfLogger.logStopCommand("" + request.command, "Success");
|
||||
tracing.instant(tracing.Phase.Session, "response", { seq: request.seq, command: request.command, success: !!response });
|
||||
tracing?.instant(tracing.Phase.Session, "response", { seq: request.seq, command: request.command, success: !!response });
|
||||
if (response) {
|
||||
this.doOutput(response, request.command, request.seq, /*success*/ true);
|
||||
}
|
||||
@@ -2991,19 +2991,19 @@ namespace ts.server {
|
||||
}
|
||||
catch (err) {
|
||||
// Cancellation or an error may have left incomplete events on the tracing stack.
|
||||
tracing.popAll();
|
||||
tracing?.popAll();
|
||||
|
||||
if (err instanceof OperationCanceledException) {
|
||||
// Handle cancellation exceptions
|
||||
perfLogger.logStopCommand("" + (request && request.command), "Canceled: " + err);
|
||||
tracing.instant(tracing.Phase.Session, "commandCanceled", { seq: request?.seq, command: request?.command });
|
||||
tracing?.instant(tracing.Phase.Session, "commandCanceled", { seq: request?.seq, command: request?.command });
|
||||
this.doOutput({ canceled: true }, request!.command, request!.seq, /*success*/ true);
|
||||
return;
|
||||
}
|
||||
|
||||
this.logErrorWorker(err, this.toStringMessage(message), relevantFile);
|
||||
perfLogger.logStopCommand("" + (request && request.command), "Error: " + err);
|
||||
tracing.instant(tracing.Phase.Session, "commandError", { seq: request?.seq, command: request?.command, message: (<Error>err).message });
|
||||
tracing?.instant(tracing.Phase.Session, "commandError", { seq: request?.seq, command: request?.command, message: (<Error>err).message });
|
||||
|
||||
this.doOutput(
|
||||
/*info*/ undefined,
|
||||
|
||||
@@ -1143,7 +1143,7 @@ namespace ts {
|
||||
|
||||
public throwIfCancellationRequested(): void {
|
||||
if (this.isCancellationRequested()) {
|
||||
tracing.instant(tracing.Phase.Session, "cancellationThrown", { kind: "CancellationTokenObject" });
|
||||
tracing?.instant(tracing.Phase.Session, "cancellationThrown", { kind: "CancellationTokenObject" });
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
}
|
||||
@@ -1174,7 +1174,7 @@ namespace ts {
|
||||
|
||||
public throwIfCancellationRequested(): void {
|
||||
if (this.isCancellationRequested()) {
|
||||
tracing.instant(tracing.Phase.Session, "cancellationThrown", { kind: "ThrottledCancellationToken" });
|
||||
tracing?.instant(tracing.Phase.Session, "cancellationThrown", { kind: "ThrottledCancellationToken" });
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -833,9 +833,7 @@ namespace ts.server {
|
||||
exit() {
|
||||
this.logger.info("Exiting...");
|
||||
this.projectService.closeLog();
|
||||
if (traceDir) {
|
||||
tracing.stopTracing(ts.emptyArray);
|
||||
}
|
||||
tracing?.stopTracing(ts.emptyArray);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -863,7 +861,7 @@ namespace ts.server {
|
||||
? stripQuotes(commandLineTraceDir)
|
||||
: process.env.TSS_TRACE;
|
||||
if (traceDir) {
|
||||
tracing.startTracing(tracing.Mode.Server, traceDir);
|
||||
startTracing(tracingEnabled.Mode.Server, traceDir);
|
||||
}
|
||||
|
||||
const ioSession = new IOSession();
|
||||
|
||||
Reference in New Issue
Block a user