From 99444d624f6efa82098eec5febdc1ea465fa80a7 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Fri, 11 Mar 2022 16:47:26 -0800 Subject: [PATCH 1/7] Trace project creation, loading, and updateGraph --- src/server/editorServices.ts | 3 +++ src/server/project.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 149332bb6f646..60b5845cb7710 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -2062,6 +2062,7 @@ namespace ts.server { /* @internal */ createConfiguredProject(configFileName: NormalizedPath) { + tracing?.instant(tracing.Phase.Session, "createConfiguredProject", { path: configFileName }); this.logger.info(`Creating configuration project ${configFileName}`); const canonicalConfigFilePath = asNormalizedPath(this.toCanonicalFileName(configFileName)); let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); @@ -2119,6 +2120,7 @@ namespace ts.server { */ /* @internal */ private loadConfiguredProject(project: ConfiguredProject, reason: string) { + tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { args: project.canonicalConfigFilePath }); this.sendProjectLoadingStartEvent(project, reason); // Read updated contents from disk @@ -2160,6 +2162,7 @@ namespace ts.server { project.enablePluginsWithOptions(compilerOptions, this.currentPluginConfigOverrides); const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles()); this.updateRootAndOptionsOfNonInferredProject(project, filesToAdd, fileNamePropertyReader, compilerOptions, parsedCommandLine.typeAcquisition!, parsedCommandLine.compileOnSave, parsedCommandLine.watchOptions); + tracing?.pop(); } /*@internal*/ diff --git a/src/server/project.ts b/src/server/project.ts index 91bc1e639a355..04d71ad2ee143 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -2273,6 +2273,7 @@ namespace ts.server { * @returns: true if set of files in the project stays the same and false - otherwise. */ updateGraph(): boolean { + tracing?.push(tracing.Phase.Session, "updateGraph", { path: this.canonicalConfigFilePath }); const isInitialLoad = this.isInitialLoadPending(); this.isInitialLoadPending = returnFalse; const reloadLevel = this.pendingReload; @@ -2296,6 +2297,7 @@ namespace ts.server { this.compilerHost = undefined; this.projectService.sendProjectLoadingFinishEvent(this); this.projectService.sendProjectTelemetry(this); + tracing?.pop(); return result; } From 62d41da8845187f1ea99527e952ca35234708db6 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Fri, 11 Mar 2022 16:48:44 -0800 Subject: [PATCH 2/7] Drop generic event tracing --- src/server/session.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/server/session.ts b/src/server/session.ts index c2f8670088665..0b893c9d844b4 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -897,7 +897,6 @@ namespace ts.server { } public event(body: T, eventName: string): void { - tracing?.instant(tracing.Phase.Session, "event", { eventName }); this.send(toEvent(eventName, body)); } From 62e64c79b5557b2bd07c64250a0b715c0c835103 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Fri, 11 Mar 2022 17:15:23 -0800 Subject: [PATCH 3/7] Make argument names more consistent --- src/server/editorServices.ts | 4 ++-- src/server/project.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 60b5845cb7710..5a81aff9cc461 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -2062,7 +2062,7 @@ namespace ts.server { /* @internal */ createConfiguredProject(configFileName: NormalizedPath) { - tracing?.instant(tracing.Phase.Session, "createConfiguredProject", { path: configFileName }); + tracing?.instant(tracing.Phase.Session, "createConfiguredProject", { configFilePath: configFileName }); this.logger.info(`Creating configuration project ${configFileName}`); const canonicalConfigFilePath = asNormalizedPath(this.toCanonicalFileName(configFileName)); let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); @@ -2120,7 +2120,7 @@ namespace ts.server { */ /* @internal */ private loadConfiguredProject(project: ConfiguredProject, reason: string) { - tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { args: project.canonicalConfigFilePath }); + tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { configFilePath: project.canonicalConfigFilePath }); this.sendProjectLoadingStartEvent(project, reason); // Read updated contents from disk diff --git a/src/server/project.ts b/src/server/project.ts index 04d71ad2ee143..087ef06e5aa86 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -2273,7 +2273,7 @@ namespace ts.server { * @returns: true if set of files in the project stays the same and false - otherwise. */ updateGraph(): boolean { - tracing?.push(tracing.Phase.Session, "updateGraph", { path: this.canonicalConfigFilePath }); + tracing?.push(tracing.Phase.Session, "updateGraph", { configFilePath: this.canonicalConfigFilePath }); const isInitialLoad = this.isInitialLoadPending(); this.isInitialLoadPending = returnFalse; const reloadLevel = this.pendingReload; From 314358279512601ba09b935be1b4b4dd53add584 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Fri, 11 Mar 2022 17:21:29 -0800 Subject: [PATCH 4/7] Trace diagnostics to make steps easier to interpret --- src/server/session.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server/session.ts b/src/server/session.ts index 0b893c9d844b4..07a972298e639 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -948,18 +948,24 @@ namespace ts.server { } private semanticCheck(file: NormalizedPath, project: Project) { + tracing?.push(tracing.Phase.Session, "semanticCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails const diags = isDeclarationFileInJSOnlyNonConfiguredProject(project, file) ? emptyArray : project.getLanguageService().getSemanticDiagnostics(file).filter(d => !!d.file); this.sendDiagnosticsEvent(file, project, diags, "semanticDiag"); + tracing?.pop(); } private syntacticCheck(file: NormalizedPath, project: Project) { + tracing?.push(tracing.Phase.Session, "syntacticCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSyntacticDiagnostics(file), "syntaxDiag"); + tracing?.pop(); } private suggestionCheck(file: NormalizedPath, project: Project) { + tracing?.push(tracing.Phase.Session, "suggestionCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSuggestionDiagnostics(file), "suggestionDiag"); + tracing?.pop(); } private sendDiagnosticsEvent(file: NormalizedPath, project: Project, diagnostics: readonly Diagnostic[], kind: protocol.DiagnosticEventKind): void { From ee080f5687d853791b5b00400810bd5e8b9e02ac Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Mon, 14 Mar 2022 16:54:03 -0700 Subject: [PATCH 5/7] Fill an unexplained gap in updateGraph --- src/server/project.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/server/project.ts b/src/server/project.ts index 087ef06e5aa86..9053bd187aed1 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1128,7 +1128,9 @@ namespace ts.server { this.resolutionCache.startCachingPerDirectoryResolution(); this.program = this.languageService.getProgram(); // TODO: GH#18217 this.dirty = false; + tracing?.push(tracing.Phase.Session, "finishCachingPerDirectoryResolution"); this.resolutionCache.finishCachingPerDirectoryResolution(); + tracing?.pop(); Debug.assert(oldProgram === undefined || this.program !== undefined); From dd2570bf845c4aeb5768b3d1553df83a31e934a9 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 15 Mar 2022 10:58:43 -0700 Subject: [PATCH 6/7] Move updateGraph tracing into base type --- src/server/project.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/project.ts b/src/server/project.ts index 9053bd187aed1..16fc0888a2121 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1045,6 +1045,7 @@ namespace ts.server { * @returns: true if set of files in the project stays the same and false - otherwise. */ updateGraph(): boolean { + tracing?.push(tracing.Phase.Session, "updateGraph", { name: this.projectName, kind: ProjectKind[this.projectKind] }); perfLogger.logStartUpdateGraph(); this.resolutionCache.startRecordingFilesWithChangedResolutions(); @@ -1092,6 +1093,7 @@ namespace ts.server { this.getPackageJsonAutoImportProvider(); } perfLogger.logStopUpdateGraph(); + tracing?.pop(); return !hasNewProgram; } @@ -2275,7 +2277,6 @@ namespace ts.server { * @returns: true if set of files in the project stays the same and false - otherwise. */ updateGraph(): boolean { - tracing?.push(tracing.Phase.Session, "updateGraph", { configFilePath: this.canonicalConfigFilePath }); const isInitialLoad = this.isInitialLoadPending(); this.isInitialLoadPending = returnFalse; const reloadLevel = this.pendingReload; @@ -2299,7 +2300,6 @@ namespace ts.server { this.compilerHost = undefined; this.projectService.sendProjectLoadingFinishEvent(this); this.projectService.sendProjectTelemetry(this); - tracing?.pop(); return result; } From c85ff1156f2fc5a67984cd91a76fcd15c6d10152 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 15 Mar 2022 14:55:33 -0700 Subject: [PATCH 7/7] Fill the gaps in updateGraph --- src/compiler/commandLineParser.ts | 5 ++++- src/server/project.ts | 9 ++++++++- src/services/services.ts | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 757ae3bba2501..ba798525e7d7f 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -2591,7 +2591,10 @@ namespace ts { * file to. e.g. outDir */ export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: readonly FileExtensionInfo[], extendedConfigCache?: Map, existingWatchOptions?: WatchOptions): ParsedCommandLine { - return parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); + tracing?.push(tracing.Phase.Parse, "parseJsonSourceFileConfigFileContent", { path: sourceFile.fileName }); + const result = parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); + tracing?.pop(); + return result; } /*@internal*/ diff --git a/src/server/project.ts b/src/server/project.ts index 16fc0888a2121..3ecd20cf76fec 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1751,13 +1751,16 @@ namespace ts.server { const dependencySelection = this.includePackageJsonAutoImports(); if (dependencySelection) { + tracing?.push(tracing.Phase.Session, "getPackageJsonAutoImportProvider"); const start = timestamp(); this.autoImportProviderHost = AutoImportProviderProject.create(dependencySelection, this, this.getModuleResolutionHostForAutoImportProvider(), this.documentRegistry); if (this.autoImportProviderHost) { updateProjectIfDirty(this.autoImportProviderHost); this.sendPerformanceEvent("CreatePackageJsonAutoImportProvider", timestamp() - start); + tracing?.pop(); return this.autoImportProviderHost.getCurrentProgram(); } + tracing?.pop(); } } @@ -1780,9 +1783,13 @@ namespace ts.server { } function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile: ESMap): SortedReadonlyArray { + const sourceFiles = program.getSourceFiles(); + tracing?.push(tracing.Phase.Session, "getUnresolvedImports", { count: sourceFiles.length }); const ambientModules = program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName())); - return sortAndDeduplicate(flatMap(program.getSourceFiles(), sourceFile => + const result = sortAndDeduplicate(flatMap(sourceFiles, sourceFile => extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile))); + tracing?.pop(); + return result; } function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: readonly string[], cachedUnresolvedImportsPerFile: ESMap): readonly string[] { return getOrUpdate(cachedUnresolvedImportsPerFile, file.path, () => { diff --git a/src/services/services.ts b/src/services/services.ts index 503482d63c7a8..efb31f257970e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1004,9 +1004,11 @@ namespace ts { // Initialize the list with the root file names const rootFileNames = host.getScriptFileNames(); + tracing?.push(tracing.Phase.Session, "initializeHostCache", { count: rootFileNames.length }); for (const fileName of rootFileNames) { this.createEntry(fileName, toPath(fileName, this.currentDirectory, getCanonicalFileName)); } + tracing?.pop(); } private createEntry(fileName: string, path: Path) {