Add server tracepoints (#48282)

* Trace project creation, loading, and updateGraph

* Drop generic event tracing

* Make argument names more consistent

* Trace diagnostics to make steps easier to interpret

* Fill an unexplained gap in updateGraph

* Move updateGraph tracing into base type

* Fill the gaps in updateGraph
This commit is contained in:
Andrew Casey
2022-03-17 13:56:42 -08:00
committed by GitHub
parent c1cf901997
commit 073ac920ad
5 changed files with 27 additions and 3 deletions

View File

@@ -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<ExtendedConfigCacheEntry>, 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*/

View File

@@ -2062,6 +2062,7 @@ namespace ts.server {
/* @internal */
createConfiguredProject(configFileName: NormalizedPath) {
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);
@@ -2119,6 +2120,7 @@ namespace ts.server {
*/
/* @internal */
private loadConfiguredProject(project: ConfiguredProject, reason: string) {
tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { configFilePath: 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*/

View File

@@ -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;
}
@@ -1128,7 +1130,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);
@@ -1747,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();
}
}
@@ -1776,9 +1783,13 @@ namespace ts.server {
}
function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile: ESMap<Path, readonly string[]>): SortedReadonlyArray<string> {
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<Path, readonly string[]>): readonly string[] {
return getOrUpdate(cachedUnresolvedImportsPerFile, file.path, () => {

View File

@@ -903,7 +903,6 @@ namespace ts.server {
}
public event<T extends object>(body: T, eventName: string): void {
tracing?.instant(tracing.Phase.Session, "event", { eventName });
this.send(toEvent(eventName, body));
}
@@ -955,18 +954,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 {

View File

@@ -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) {