From 8b8f330a90c49d505e741f4db2a22eef02dbd53f Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Thu, 20 Oct 2022 13:05:08 -0700 Subject: [PATCH] improve code lens provider performance (#11696) * store localized text * improved telemetry for code lens perf * don't register code lens provider for notebook or cell documents * added news * undo scheme registration filter, filter code folding provider to match --- TELEMETRY.csv | 5 +- TELEMETRY.md | 14 ++ news/3 Code Health/11433.md | 1 + src/gdpr.ts | 11 ++ .../editor-integration/codeLensFactory.ts | 152 +++++++++--------- .../editor-integration/codelensprovider.ts | 11 +- .../editor-integration/codewatcher.ts | 10 +- .../pythonCellFoldingProvider.ts | 6 +- .../editor-integration/types.ts | 7 + src/platform/common/constants.ts | 1 + src/telemetry.ts | 30 ++++ 11 files changed, 169 insertions(+), 79 deletions(-) create mode 100644 news/3 Code Health/11433.md diff --git a/TELEMETRY.csv b/TELEMETRY.csv index 5adabd13903..0b64768bc6e 100644 --- a/TELEMETRY.csv +++ b/TELEMETRY.csv @@ -683,7 +683,8 @@ Used to detect the popularity of a mime type, that would help determine which mi E.g. if we see widget mimetype, then we know how many use ipywidgets and the like and helps us prioritize widget issues, or prioritize rendering of widgets when opening an existing notebook or the like.","Telemetry.CellOutputMimeType","donjayamanne","N/A","","","when","Whether the package was detected in an existing file (upon open, upon save, upon close) or when it was being used during execution.","","'onExecution' 'onOpenCloseOrSave' ",false -"DS_INTERNAL.CODE_LENS_ACQ_TIME","How long on average we spent parsing code lens. Sent on shutdown.","Telemetry.CodeLensAverageAcquisitionTime","amunger","InteractiveWindow","","","duration","Duration of a measure in milliseconds. +"DS_INTERNAL.CODE_LENS_ACQ_TIME","How long on average we spent parsing code lens. Sent on shutdown. +We should be able to deprecate in favor of DocumentWithCodeCells, but we should compare the numbers first.","Telemetry.CodeLensAverageAcquisitionTime","amunger","InteractiveWindow","","","duration","Duration of a measure in milliseconds. Common measurement used across a number of events.","number","",false "DS_INTERNAL.COMMAND_EXECUTED","A command that the extension contributes is executed.","Telemetry.CommandExecuted","amunger","N/A","","","command","Name of the command executed.","string","",false "DS_INTERNAL.CONNECTFAILEDJUPYTER","Sent when we have failed to connect to the local Jupyter server we started.","Telemetry.ConnectFailedJupyter","donjayamanne","N/A","KernelStartup","","failed","Whether there was a failure. @@ -717,6 +718,8 @@ Common to most of the events.","string","",true Common to most of the events.","string","",true "DS_INTERNAL.CONNECTREMOTEJUPYTER_VIA_LOCALHOST","Connecting to an existing Jupyter server, but connecting to localhost.","Telemetry.ConnectRemoteJupyterViaLocalHost","donjayamanne","N/A","KernelStartup","","","","","","" "DS_INTERNAL.CONNECTREMOTESELFCERTFAILEDJUPYTER","Jupyter server's certificate is not from a trusted authority.","Telemetry.ConnectRemoteSelfCertFailedJupyter","donjayamanne","N/A","KernelStartup","","","","","","" +"DS_INTERNAL.DOCUMENT_WITH_CODE_CELLS","Info about code lenses, count and average time to parse the document.","Telemetry.DocumentWithCodeCells","amunger","InteractiveWindow","","","codeLensUpdateTime","Average time taken to aquire code lenses for a document without using the cache","number","",false +"DS_INTERNAL.DOCUMENT_WITH_CODE_CELLS","Info about code lenses, count and average time to parse the document.","Telemetry.DocumentWithCodeCells","amunger","InteractiveWindow","","","maxCellCount","Maximum number of code lenses returned for the document","number","",false "DS_INTERNAL.FAILED_TO_UPDATE_JUPYTER_KERNEL_SPEC","Sent when we fail to update the kernel spec json file.","Telemetry.FailedToUpdateKernelSpec","donjayamanne","N/A","KernelStartup","","failed","Whether there was a failure. Common to most of the events.","true","",false "DS_INTERNAL.FAILED_TO_UPDATE_JUPYTER_KERNEL_SPEC","Sent when we fail to update the kernel spec json file.","Telemetry.FailedToUpdateKernelSpec","donjayamanne","N/A","KernelStartup","","failureCategory","A reason that we generate (e.g. kerneldied, noipykernel, etc), more like a category of the error. diff --git a/TELEMETRY.md b/TELEMETRY.md index c5fa3ca1c5d..2530081e1b8 100644 --- a/TELEMETRY.md +++ b/TELEMETRY.md @@ -1698,6 +1698,7 @@ Expand each section to see more information about that event. Owner: [@amunger](https://github.com/amunger) ``` How long on average we spent parsing code lens. Sent on shutdown. + We should be able to deprecate in favor of DocumentWithCodeCells, but we should compare the numbers first. ``` - Measures: @@ -1801,6 +1802,19 @@ Expand each section to see more information about that event. +* DS_INTERNAL.DOCUMENT_WITH_CODE_CELLS (Telemetry.DocumentWithCodeCells) + Owner: [@amunger](https://github.com/amunger) + ``` + Info about code lenses, count and average time to parse the document. + ``` + + - Measures: + - `codeLensUpdateTime`: `number` + Average time taken to aquire code lenses for a document without using the cache + - `maxCellCount`: `number` + Maximum number of code lenses returned for the document + + * DS_INTERNAL.FAILED_TO_UPDATE_JUPYTER_KERNEL_SPEC (Telemetry.FailedToUpdateKernelSpec) Owner: [@donjayamanne](https://github.com/donjayamanne) ``` diff --git a/news/3 Code Health/11433.md b/news/3 Code Health/11433.md new file mode 100644 index 00000000000..79dd4dabaf4 --- /dev/null +++ b/news/3 Code Health/11433.md @@ -0,0 +1 @@ +Reduce the amount of work done for each code lens creation to help performance. diff --git a/src/gdpr.ts b/src/gdpr.ts index ce9e4f1cce2..631b6236061 100644 --- a/src/gdpr.ts +++ b/src/gdpr.ts @@ -1080,6 +1080,17 @@ "${include}": [ "${F1}" + ] + } + */ +//Telemetry.DocumentWithCodeCells +/* __GDPR__ + "DS_INTERNAL.DOCUMENT_WITH_CODE_CELLS" : { + "codeLensUpdateTime": {"classification":"SystemMetaData","purpose":"PerformanceAndHealth","comment":"Average time taken to aquire code lenses for a document without using the cache","owner":"amunger","isMeasurement":true}, + "maxCellCount": {"classification":"SystemMetaData","purpose":"FeatureInsight","comment":"Maximum number of code lenses returned for the document","owner":"amunger","isMeasurement":true}, + "${include}": [ + "${F1}" + ] } */ diff --git a/src/interactive-window/editor-integration/codeLensFactory.ts b/src/interactive-window/editor-integration/codeLensFactory.ts index 87a88a9f906..fdef60e5c9a 100644 --- a/src/interactive-window/editor-integration/codeLensFactory.ts +++ b/src/interactive-window/editor-integration/codeLensFactory.ts @@ -11,12 +11,11 @@ import { NotebookCellExecutionState, NotebookCellExecutionStateChangeEvent, Range, - TextDocument, - workspace + TextDocument } from 'vscode'; import { IDocumentManager, IVSCodeNotebook, IWorkspaceService } from '../../platform/common/application/types'; -import { traceWarning, traceInfoIfCI } from '../../platform/logging'; +import { traceWarning, traceInfoIfCI, traceVerbose } from '../../platform/logging'; import { ICellRange, IConfigurationService, IDisposableRegistry, Resource } from '../../platform/common/types'; import * as localize from '../../platform/common/utils/localize'; @@ -24,7 +23,8 @@ import { getInteractiveCellMetadata } from '../helpers'; import { IKernelProvider } from '../../kernels/types'; import { CodeLensCommands, Commands, InteractiveWindowView } from '../../platform/common/constants'; import { generateCellRangesFromDocument } from './cellFactory'; -import { ICodeLensFactory, IGeneratedCode, IGeneratedCodeStorageFactory } from './types'; +import { CodeLensPerfMeasures, ICodeLensFactory, IGeneratedCode, IGeneratedCodeStorageFactory } from './types'; +import { StopWatch } from '../../platform/common/utils/stopWatch'; type CodeLensCacheData = { cachedDocumentVersion: number | undefined; @@ -39,6 +39,20 @@ type PerNotebookData = { documentExecutionCounts: Map; }; +// localized code lense text +const runCurrentandAllBelowTitle = localize.DataScience.runCurrentCellAndAddBelow(); +const addCellBelowTitle = localize.DataScience.addCellBelowCommandTitle(); +const debugCurrentCellTitle = localize.DataScience.debugCellCommandTitle(); +const debugCellTitle = localize.DataScience.debugCellCommandTitle(); +const debugStepOverTitle = localize.DataScience.debugStepOverCommandTitle(); +const DebugContinueTitle = localize.DataScience.debugContinueCommandTitle(); +const debugStopTitle = localize.DataScience.debugStopCommandTitle(); +const runCellTitle = localize.DataScience.runCellLensCommandTitle(); +const runAllCellsTitle = localize.DataScience.runAllCellsLensCommandTitle(); +const runAllAboveTitle = localize.DataScience.runAllCellsAboveLensCommandTitle(); +const runAllBelowTitle = localize.DataScience.runCellAndAllBelowLensCommandTitle(); +const scrollToCellFormat = localize.DataScience.scrollToCellTitleFormatMessage(); + /** * This class is a singleton that generates code lenses for any document the user opens. It listens * to cells being execute so it can add 'goto' lenses on cells that have already been run. @@ -48,6 +62,10 @@ export class CodeLensFactory implements ICodeLensFactory { private updateEvent: EventEmitter = new EventEmitter(); private notebookData = new Map(); private codeLensCache = new Map(); + private totalCodeLensUpdateTimeInMs: number = 0; + private codeLensUpdateCount: number = 0; + private maxCellCount: number = 0; + constructor( @inject(IConfigurationService) private configService: IConfigurationService, @inject(IDocumentManager) private documentManager: IDocumentManager, @@ -70,6 +88,15 @@ export class CodeLensFactory implements ICodeLensFactory { disposables ); } + + public getPerfMeasures(): CodeLensPerfMeasures { + return { + totalCodeLensUpdateTimeInMs: this.totalCodeLensUpdateTimeInMs, + codeLensUpdateCount: this.codeLensUpdateCount, + maxCellCount: this.maxCellCount + }; + } + public get updateRequired(): Event { return this.updateEvent.event; } @@ -85,6 +112,9 @@ export class CodeLensFactory implements ICodeLensFactory { } private getCodeLensCacheData(document: TextDocument): CodeLensCacheData { + const stopWatch = new StopWatch(); + let updated = false; + // See if we have a cached version of the code lenses for this document const key = document.uri.toString(); let cache = this.codeLensCache.get(key); @@ -127,19 +157,22 @@ export class CodeLensFactory implements ICodeLensFactory { // Generate our code lenses if necessary if (cache.documentLenses.length === 0 && needUpdate && cache.cellRanges.length) { - traceInfoIfCI(`Generating new code lenses for version ${document.version} of document ${document.uri}`); + updated = true; // Enumerate the possible commands for the document based code lenses const commands = this.enumerateCommands(document.uri); - traceInfoIfCI(`Enumerating commands for ${document.uri.toString()}, ${commands.join(', ')}`); + traceVerbose( + `CodeLensFactory: Generating new code lenses for version ${document.version} of document ${ + document.uri + } for commands ${commands.join(', ')}` + ); - // Then iterate over all of the cell ranges and generate code lenses for each possible - // commands + // Then iterate over all of the cell ranges and generate code lenses for each enabled command let firstCell = true; cache.cellRanges.forEach((r) => { commands.forEach((c) => { const codeLens = this.createCodeLens(document, r, c, firstCell); if (codeLens) { - cache!.documentLenses.push(codeLens); // NOSONAR + cache!.documentLenses.push(codeLens); } }); firstCell = false; @@ -171,6 +204,12 @@ export class CodeLensFactory implements ICodeLensFactory { } } + if (updated) { + this.totalCodeLensUpdateTimeInMs += stopWatch.elapsedTime; + this.codeLensUpdateCount += 1; + this.maxCellCount = Math.max(this.maxCellCount, cache.cellRanges.length); + } + return cache; } private getDocumentExecutionCounts(key: string): number[] { @@ -270,42 +309,27 @@ export class CodeLensFactory implements ICodeLensFactory { commandName: string, isFirst: boolean ): CodeLens | undefined { - // Do not generate interactive window codelenses for TextDocuments which are part of NotebookDocuments - if (workspace.notebookDocuments.find((notebook) => notebook.uri.toString() === document.uri.toString())) { - return; - } - traceInfoIfCI(`Generating code lens for command ${commandName} in ${document.uri.toString()}`); // We only support specific commands // Be careful here. These arguments will be serialized during liveshare sessions // and so shouldn't reference local objects. const { range, cell_type } = cellRange; switch (commandName) { case Commands.RunCurrentCellAndAddBelow: - return this.generateCodeLens( - range, - Commands.RunCurrentCellAndAddBelow, - localize.DataScience.runCurrentCellAndAddBelow() - ); + return this.generateCodeLens(range, Commands.RunCurrentCellAndAddBelow, runCurrentandAllBelowTitle); case Commands.AddCellBelow: - return this.generateCodeLens( - range, - Commands.AddCellBelow, - localize.DataScience.addCellBelowCommandTitle(), - [document.uri, range.start.line] - ); + return this.generateCodeLens(range, Commands.AddCellBelow, addCellBelowTitle, [ + document.uri, + range.start.line + ]); case Commands.DebugCurrentCellPalette: - return this.generateCodeLens( - range, - Commands.DebugCurrentCellPalette, - localize.DataScience.debugCellCommandTitle() - ); + return this.generateCodeLens(range, Commands.DebugCurrentCellPalette, debugCurrentCellTitle); case Commands.DebugCell: // If it's not a code cell (e.g. markdown), don't add the "Debug cell" action. if (cell_type !== 'code') { break; } - return this.generateCodeLens(range, Commands.DebugCell, localize.DataScience.debugCellCommandTitle(), [ + return this.generateCodeLens(range, Commands.DebugCell, debugCellTitle, [ document.uri, range.start.line, range.start.character, @@ -318,37 +342,25 @@ export class CodeLensFactory implements ICodeLensFactory { if (cell_type !== 'code') { break; } - return this.generateCodeLens( - range, - Commands.DebugStepOver, - localize.DataScience.debugStepOverCommandTitle(), - [document.uri] - ); + return this.generateCodeLens(range, Commands.DebugStepOver, debugStepOverTitle, [document.uri]); case Commands.DebugContinue: // Only code cells get debug actions if (cell_type !== 'code') { break; } - return this.generateCodeLens( - range, - Commands.DebugContinue, - localize.DataScience.debugContinueCommandTitle(), - [document.uri] - ); + return this.generateCodeLens(range, Commands.DebugContinue, DebugContinueTitle, [document.uri]); case Commands.DebugStop: // Only code cells get debug actions if (cell_type !== 'code') { break; } - return this.generateCodeLens(range, Commands.DebugStop, localize.DataScience.debugStopCommandTitle(), [ - document.uri - ]); + return this.generateCodeLens(range, Commands.DebugStop, debugStopTitle, [document.uri]); case Commands.RunCurrentCell: case Commands.RunCell: - return this.generateCodeLens(range, Commands.RunCell, localize.DataScience.runCellLensCommandTitle(), [ + return this.generateCodeLens(range, Commands.RunCell, runCellTitle, [ document.uri, range.start.line, range.start.character, @@ -357,39 +369,35 @@ export class CodeLensFactory implements ICodeLensFactory { ]); case Commands.RunAllCells: - return this.generateCodeLens( - range, - Commands.RunAllCells, - localize.DataScience.runAllCellsLensCommandTitle(), - [document.uri, range.start.line, range.start.character] - ); + return this.generateCodeLens(range, Commands.RunAllCells, runAllCellsTitle, [ + document.uri, + range.start.line, + range.start.character + ]); case Commands.RunAllCellsAbovePalette: case Commands.RunAllCellsAbove: if (!isFirst) { - return this.generateCodeLens( - range, - Commands.RunAllCellsAbove, - localize.DataScience.runAllCellsAboveLensCommandTitle(), - [document.uri, range.start.line, range.start.character] - ); + return this.generateCodeLens(range, Commands.RunAllCellsAbove, runAllAboveTitle, [ + document.uri, + range.start.line, + range.start.character + ]); } else { - return this.generateCodeLens( - range, - Commands.RunCellAndAllBelow, - localize.DataScience.runCellAndAllBelowLensCommandTitle(), - [document.uri, range.start.line, range.start.character] - ); + return this.generateCodeLens(range, Commands.RunCellAndAllBelow, runAllBelowTitle, [ + document.uri, + range.start.line, + range.start.character + ]); } break; case Commands.RunCellAndAllBelowPalette: case Commands.RunCellAndAllBelow: - return this.generateCodeLens( - range, - Commands.RunCellAndAllBelow, - localize.DataScience.runCellAndAllBelowLensCommandTitle(), - [document.uri, range.start.line, range.start.character] - ); + return this.generateCodeLens(range, Commands.RunCellAndAllBelow, runAllBelowTitle, [ + document.uri, + range.start.line, + range.start.character + ]); default: traceWarning(`Invalid command for code lens ${commandName}`); @@ -418,7 +426,7 @@ export class CodeLensFactory implements ICodeLensFactory { return this.generateCodeLens( range, Commands.ScrollToCell, - localize.DataScience.scrollToCellTitleFormatMessage().format(matchingExecutionCount.toString()), + scrollToCellFormat.format(matchingExecutionCount.toString()), [document.uri, rangeMatch.id] ); } diff --git a/src/interactive-window/editor-integration/codelensprovider.ts b/src/interactive-window/editor-integration/codelensprovider.ts index 7e98a9df537..f6845cf7881 100644 --- a/src/interactive-window/editor-integration/codelensprovider.ts +++ b/src/interactive-window/editor-integration/codelensprovider.ts @@ -19,7 +19,7 @@ import { noop } from '../../platform/common/utils/misc'; import { StopWatch } from '../../platform/common/utils/stopWatch'; import { IServiceContainer } from '../../platform/ioc/types'; import { sendTelemetryEvent } from '../../telemetry'; -import { traceInfoIfCI } from '../../platform/logging'; +import { traceInfoIfCI, traceVerbose } from '../../platform/logging'; import { CodeLensCommands, EditorContexts, @@ -42,6 +42,7 @@ export class DataScienceCodeLensProvider implements IDataScienceCodeLensProvider private totalGetCodeLensCalls: number = 0; private activeCodeWatchers: ICodeWatcher[] = []; private didChangeCodeLenses: vscode.EventEmitter = new vscode.EventEmitter(); + constructor( @inject(IServiceContainer) private serviceContainer: IServiceContainer, @inject(IDebugLocationTracker) @optional() private debugLocationTracker: IDebugLocationTracker | undefined, @@ -74,6 +75,7 @@ export class DataScienceCodeLensProvider implements IDataScienceCodeLensProvider duration: this.totalExecutionTimeInMs / this.totalGetCodeLensCalls }); } + disposeAllDisposables(this.activeCodeWatchers); } public get onDidChangeCodeLenses(): vscode.Event { @@ -106,7 +108,8 @@ export class DataScienceCodeLensProvider implements IDataScienceCodeLensProvider private onDidCloseTextDocument(e: vscode.TextDocument) { const index = this.activeCodeWatchers.findIndex((item) => item.uri && item.uri.toString() === e.uri.toString()); if (index >= 0) { - this.activeCodeWatchers.splice(index, 1); + const codewatcher = this.activeCodeWatchers.splice(index, 1); + codewatcher[0].dispose(); } } @@ -192,7 +195,7 @@ export class DataScienceCodeLensProvider implements IDataScienceCodeLensProvider return codeWatcher.getCodeLenses(); } - traceInfoIfCI(`Creating a new watcher for document ${document.uri}`); + traceVerbose(`Creating a new watcher for document ${document.uri}`); const newCodeWatcher = this.createNewCodeWatcher(document); return newCodeWatcher.getCodeLenses(); } @@ -206,7 +209,7 @@ export class DataScienceCodeLensProvider implements IDataScienceCodeLensProvider // Create a new watcher for this file if we can find a matching document const possibleDocuments = this.documentManager.textDocuments.filter((d) => d.uri.toString() === uri.toString()); if (possibleDocuments && possibleDocuments.length > 0) { - traceInfoIfCI(`creating new code watcher with matching document ${uri}`); + traceVerbose(`creating new code watcher with matching document ${uri}`); return this.createNewCodeWatcher(possibleDocuments[0]); } diff --git a/src/interactive-window/editor-integration/codewatcher.ts b/src/interactive-window/editor-integration/codewatcher.ts index 2e98b0afeba..1c5d2f680c6 100644 --- a/src/interactive-window/editor-integration/codewatcher.ts +++ b/src/interactive-window/editor-integration/codewatcher.ts @@ -21,7 +21,7 @@ import { import { IDocumentManager } from '../../platform/common/application/types'; import { ICellRange, IConfigurationService, IDisposable, Resource } from '../../platform/common/types'; import { isUri, noop } from '../../platform/common/utils/misc'; -import { capturePerfTelemetry, captureUsageTelemetry } from '../../telemetry'; +import { capturePerfTelemetry, captureUsageTelemetry, sendTelemetryEvent } from '../../telemetry'; import { ICodeExecutionHelper } from '../../platform/terminals/types'; import { InteractiveCellResultError } from '../../platform/errors/interactiveCellResultError'; import { Telemetry, Commands, Identifiers } from '../../platform/common/constants'; @@ -124,6 +124,14 @@ export class CodeWatcher implements ICodeWatcher { return this.runMatchingCell(this.documentManager.activeTextEditor.selection, false, true); } public dispose() { + let perfMeasures = this.codeLensFactory.getPerfMeasures(); + if (perfMeasures && perfMeasures.codeLensUpdateCount > 0) { + sendTelemetryEvent(Telemetry.DocumentWithCodeCells, { + codeLensUpdateTime: perfMeasures.totalCodeLensUpdateTimeInMs / perfMeasures.codeLensUpdateCount, + maxCellCount: perfMeasures.maxCellCount + }); + } + this.codeLensUpdatedEvent.dispose(); this.closeDocumentDisposable?.dispose(); // NOSONAR this.updateRequiredDisposable?.dispose(); // NOSONAR diff --git a/src/interactive-window/editor-integration/pythonCellFoldingProvider.ts b/src/interactive-window/editor-integration/pythonCellFoldingProvider.ts index 2f7f34cbddb..c6d04a3139b 100644 --- a/src/interactive-window/editor-integration/pythonCellFoldingProvider.ts +++ b/src/interactive-window/editor-integration/pythonCellFoldingProvider.ts @@ -13,7 +13,7 @@ import { languages } from 'vscode'; import { IExtensionSyncActivationService } from '../../platform/activation/types'; -import { PYTHON_FILE_ANY_SCHEME } from '../../platform/common/constants'; +import { InteractiveInputScheme, NotebookCellScheme, PYTHON_FILE_ANY_SCHEME } from '../../platform/common/constants'; import { IExtensionContext } from '../../platform/common/types'; import { IDataScienceCodeLensProvider } from './types'; @@ -35,6 +35,10 @@ export class PythonCellFoldingProvider implements IExtensionSyncActivationServic _context: FoldingContext, token: CancellationToken ): ProviderResult { + if ([NotebookCellScheme, InteractiveInputScheme].includes(document.uri.scheme)) { + return []; + } + const codeWatcher = this.dataScienceCodeLensProvider.getCodeWatcher(document); if (codeWatcher) { const codeLenses = codeWatcher.getCodeLenses(); diff --git a/src/interactive-window/editor-integration/types.ts b/src/interactive-window/editor-integration/types.ts index 3d09daa5ebc..43d40eb8fdf 100644 --- a/src/interactive-window/editor-integration/types.ts +++ b/src/interactive-window/editor-integration/types.ts @@ -12,6 +12,12 @@ export interface IDataScienceCodeLensProvider extends CodeLensProvider { getCodeWatcher(document: TextDocument): ICodeWatcher | undefined; } +export type CodeLensPerfMeasures = { + totalCodeLensUpdateTimeInMs: number; + codeLensUpdateCount: number; + maxCellCount: number; +}; + // Wraps the Code Watcher API export const ICodeWatcher = Symbol('ICodeWatcher'); export interface ICodeWatcher extends IDisposable { @@ -56,6 +62,7 @@ export interface ICodeLensFactory { updateRequired: Event; createCodeLenses(document: TextDocument): CodeLens[]; getCellRanges(document: TextDocument): ICellRange[]; + getPerfMeasures(): CodeLensPerfMeasures; } export interface IGeneratedCode { diff --git a/src/platform/common/constants.ts b/src/platform/common/constants.ts index c6036d7c338..d0e208de2ae 100644 --- a/src/platform/common/constants.ts +++ b/src/platform/common/constants.ts @@ -441,6 +441,7 @@ export enum Telemetry { OpenPlotViewer = 'DATASCIENCE.OPEN_PLOT_VIEWER', DebugCurrentCell = 'DATASCIENCE.DEBUG_CURRENT_CELL', CodeLensAverageAcquisitionTime = 'DS_INTERNAL.CODE_LENS_ACQ_TIME', + DocumentWithCodeCells = 'DS_INTERNAL.DOCUMENT_WITH_CODE_CELLS', /** * Telemetry sent when user selects an interpreter to be used for starting of Jupyter server. */ diff --git a/src/telemetry.ts b/src/telemetry.ts index 09a28514ff3..933f7ab051c 100644 --- a/src/telemetry.ts +++ b/src/telemetry.ts @@ -698,6 +698,7 @@ export class IEventNamePropertyMapping { }; /** * How long on average we spent parsing code lens. Sent on shutdown. + * We should be able to deprecate in favor of DocumentWithCodeCells, but we should compare the numbers first. **/ [Telemetry.CodeLensAverageAcquisitionTime]: TelemetryEventInfo = { owner: 'amunger', @@ -705,6 +706,35 @@ export class IEventNamePropertyMapping { source: 'User Action', measures: commonClassificationForDurationProperties() }; + /** + * Info about code lenses, count and average time to parse the document. + **/ + [Telemetry.DocumentWithCodeCells]: TelemetryEventInfo<{ + /** + * Average time taken to aquire code lenses for a document without using the cache + **/ + codeLensUpdateTime: number; + /** + * Maximum number of code lenses returned for the document + **/ + maxCellCount: number; + }> = { + owner: 'amunger', + feature: ['InteractiveWindow'], + source: 'N/A', + measures: { + codeLensUpdateTime: { + classification: 'SystemMetaData', + purpose: 'PerformanceAndHealth', + isMeasurement: true + }, + maxCellCount: { + classification: 'SystemMetaData', + purpose: 'FeatureInsight', + isMeasurement: true + } + } + }; /** * Sent when we have failed to connect to the local Jupyter server we started. */