From 57ea0b640308caa795c43e86616d3a385bc1910d Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 19 Feb 2020 12:40:45 -0800 Subject: [PATCH 1/3] Add telemetry to capture perceived time taken to start jupyter and run cell (#10217) * Add telemetry * Only for nb For #10098 For #10212 --- news/3 Code Health/10098.md | 1 + news/3 Code Health/10212.md | 1 + src/client/datascience/constants.ts | 3 +++ .../interactive-common/interactiveBase.ts | 16 ++++++++++++++-- .../datascience/jupyter/jupyterExecution.ts | 5 +++++ src/client/telemetry/index.ts | 12 ++++++++++++ 6 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 news/3 Code Health/10098.md create mode 100644 news/3 Code Health/10212.md diff --git a/news/3 Code Health/10098.md b/news/3 Code Health/10098.md new file mode 100644 index 000000000000..057ae06fa5e2 --- /dev/null +++ b/news/3 Code Health/10098.md @@ -0,0 +1 @@ +Telemetry to capture connections to `localhost` using the connect to remote Jupyter server feature. diff --git a/news/3 Code Health/10212.md b/news/3 Code Health/10212.md new file mode 100644 index 000000000000..4bf0014f1470 --- /dev/null +++ b/news/3 Code Health/10212.md @@ -0,0 +1 @@ +Telemetry to capture perceived startup times of Jupyter and time to execute a cell. diff --git a/src/client/datascience/constants.ts b/src/client/datascience/constants.ts index 07f4e8959013..6bd07eeed2c5 100644 --- a/src/client/datascience/constants.ts +++ b/src/client/datascience/constants.ts @@ -160,6 +160,7 @@ export enum Telemetry { SubmitCellThroughInput = 'DATASCIENCE.SUBMITCELLFROMREPL', ConnectLocalJupyter = 'DS_INTERNAL.CONNECTLOCALJUPYTER', ConnectRemoteJupyter = 'DS_INTERNAL.CONNECTREMOTEJUPYTER', + ConnectRemoteJupyterViaLocalHost = 'DS_INTERNAL.CONNECTREMOTEJUPYTER_VIA_LOCALHOST', ConnectFailedJupyter = 'DS_INTERNAL.CONNECTFAILEDJUPYTER', ConnectRemoteFailedJupyter = 'DS_INTERNAL.CONNECTREMOTEFAILEDJUPYTER', StartSessionFailedJupyter = 'DS_INTERNAL.START_SESSION_FAILED_JUPYTER', @@ -209,6 +210,8 @@ export enum Telemetry { ExecuteCell = 'DATASCIENCE.EXECUTE_CELL_TIME', ExecuteCellPerceivedCold = 'DS_INTERNAL.EXECUTE_CELL_PERCEIVED_COLD', ExecuteCellPerceivedWarm = 'DS_INTERNAL.EXECUTE_CELL_PERCEIVED_WARM', + PerceivedJupyterStartupNotebook = 'DS_INTERNAL.PERCEIVED_JUPYTER_STARTUP_NOTEBOOK', + StartExecuteNotebookCellPerceivedCold = 'DS_INTERNAL.START_EXECUTE_NOTEBOOK_CELL_PERCEIVED_COLD', WebviewStartup = 'DS_INTERNAL.WEBVIEW_STARTUP', VariableExplorerFetchTime = 'DS_INTERNAL.VARIABLE_EXPLORER_FETCH_TIME', WebviewStyleUpdate = 'DS_INTERNAL.WEBVIEW_STYLE_UPDATE', diff --git a/src/client/datascience/interactive-common/interactiveBase.ts b/src/client/datascience/interactive-common/interactiveBase.ts index 7c89937cefb9..8e2635aa9c9b 100644 --- a/src/client/datascience/interactive-common/interactiveBase.ts +++ b/src/client/datascience/interactive-common/interactiveBase.ts @@ -20,6 +20,7 @@ import { IFileSystem } from '../../common/platform/types'; import { IConfigurationService, IDisposableRegistry, IExperimentsManager } from '../../common/types'; import { createDeferred, Deferred } from '../../common/utils/async'; import * as localize from '../../common/utils/localize'; +import { StopWatch } from '../../common/utils/stopWatch'; import { IInterpreterService, PythonInterpreter } from '../../interpreter/contracts'; import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; import { generateCellRangesFromDocument } from '../cellFactory'; @@ -78,6 +79,7 @@ import { InteractiveWindowMessageListener } from './interactiveWindowMessageList export abstract class InteractiveBase extends WebViewHost implements IInteractiveBase { private unfinishedCells: ICell[] = []; private restartingKernel: boolean = false; + private perceivedJupyterStartupTelemetryCaptured: boolean = false; private potentiallyUnfinishedStatus: Disposable[] = []; private addSysInfoPromise: Deferred | undefined; private _notebook: INotebook | undefined; @@ -457,8 +459,9 @@ export abstract class InteractiveBase extends WebViewHost { traceInfo(`Submitting code for ${this.id}`); + const stopWatch = + this._notebook && !this.perceivedJupyterStartupTelemetryCaptured ? new StopWatch() : undefined; let result = true; - // Do not execute or render empty code cells const cellMatcher = new CellMatcher(this.configService.getSettings().datascience); if (cellMatcher.stripFirstMarker(code).length === 0) { @@ -511,7 +514,16 @@ export abstract class InteractiveBase extends WebViewHost { + if (e === ServerStatus.Busy) { + sendTelemetryEvent(Telemetry.StartExecuteNotebookCellPerceivedCold, stopWatch?.elapsedTime); + disposable.dispose(); + } + }); + } const observable = this._notebook.executeObservable(code, file, line, id, false); // Indicate we executed some code diff --git a/src/client/datascience/jupyter/jupyterExecution.ts b/src/client/datascience/jupyter/jupyterExecution.ts index 3fbe3fdf1cd3..312018fdcdd8 100644 --- a/src/client/datascience/jupyter/jupyterExecution.ts +++ b/src/client/datascience/jupyter/jupyterExecution.ts @@ -31,6 +31,8 @@ import { JupyterWaitForIdleError } from './jupyterWaitForIdleError'; import { KernelSelector, KernelSpecInterpreter } from './kernels/kernelSelector'; import { NotebookStarter } from './notebookStarter'; +const LocalHosts = ['localhost', '127.0.0.1', '::1']; + export class JupyterExecutionBase implements IJupyterExecution { private usablePythonInterpreter: PythonInterpreter | undefined; private eventEmitter: EventEmitter = new EventEmitter(); @@ -143,6 +145,9 @@ export class JupyterExecutionBase implements IJupyterExecution { try { // Start or connect to the process [connection, kernelSpecInterpreter] = await Promise.all([this.startOrConnect(options, cancelToken), kernelSpecInterpreterPromise]); + if (!connection.localLaunch && LocalHosts.includes(connection.hostName.toLowerCase())) { + sendTelemetryEvent(Telemetry.ConnectRemoteJupyterViaLocalHost); + } // Create a server tha t we will then attempt to connect to. result = this.serviceContainer.get(INotebookServer); diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index c0c212d3abb2..d280af20dade 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -1436,6 +1436,10 @@ export interface IEventNamePropertyMapping { [Telemetry.ConnectFailedJupyter]: never | undefined; [Telemetry.ConnectLocalJupyter]: never | undefined; [Telemetry.ConnectRemoteJupyter]: never | undefined; + /** + * Connecting to an existing Jupyter server, but connecting to localhost. + */ + [Telemetry.ConnectRemoteJupyterViaLocalHost]: never | undefined; [Telemetry.ConnectRemoteFailedJupyter]: never | undefined; [Telemetry.ConnectRemoteSelfCertFailedJupyter]: never | undefined; [Telemetry.RegisterAndUseInterpreterAsKernel]: never | undefined; @@ -1469,6 +1473,14 @@ export interface IEventNamePropertyMapping { * If `notebook = true`, this its telemetry for native editor/notebooks. */ [Telemetry.ExecuteCellPerceivedWarm]: undefined | { notebook: boolean }; + /** + * Time take for jupyter server to start and be ready to run first user cell. + */ + [Telemetry.PerceivedJupyterStartupNotebook]: never | undefined; + /** + * Time take for jupyter server to be busy from the time user first hit `run` cell until jupyter reports it is busy running a cell. + */ + [Telemetry.StartExecuteNotebookCellPerceivedCold]: never | undefined; [Telemetry.ExecuteNativeCell]: never | undefined; [Telemetry.ExpandAll]: never | undefined; [Telemetry.ExportNotebook]: never | undefined; From 2e3e2bff205c97e1ca7cc5928d1612158f94769e Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 19 Feb 2020 12:43:22 -0800 Subject: [PATCH 2/3] Fix change log --- CHANGELOG.md | 4 ++++ news/3 Code Health/10098.md | 1 - news/3 Code Health/10212.md | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) delete mode 100644 news/3 Code Health/10098.md delete mode 100644 news/3 Code Health/10212.md diff --git a/CHANGELOG.md b/CHANGELOG.md index e28e586470ee..e231721de64e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,10 @@ ([#10049](https://github.com/Microsoft/vscode-python/issues/10049)) 1. Track cold/warm times to execute notebook cells. ([#10176](https://github.com/Microsoft/vscode-python/issues/10176)) +1. Telemetry to capture connections to `localhost` using the connect to remote Jupyter server feature. + ([#10098](https://github.com/Microsoft/vscode-python/issues/10098)) +1. Telemetry to capture perceived startup times of Jupyter and time to execute a cell. + ([#10212](https://github.com/Microsoft/vscode-python/issues/10212)) ### Thanks diff --git a/news/3 Code Health/10098.md b/news/3 Code Health/10098.md deleted file mode 100644 index 057ae06fa5e2..000000000000 --- a/news/3 Code Health/10098.md +++ /dev/null @@ -1 +0,0 @@ -Telemetry to capture connections to `localhost` using the connect to remote Jupyter server feature. diff --git a/news/3 Code Health/10212.md b/news/3 Code Health/10212.md deleted file mode 100644 index 4bf0014f1470..000000000000 --- a/news/3 Code Health/10212.md +++ /dev/null @@ -1 +0,0 @@ -Telemetry to capture perceived startup times of Jupyter and time to execute a cell. From 86845cf9aee92d5677c04116b65f8f32f204e4fb Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 19 Feb 2020 12:50:04 -0800 Subject: [PATCH 3/3] Fix linter --- src/client/datascience/interactive-common/interactiveBase.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/datascience/interactive-common/interactiveBase.ts b/src/client/datascience/interactive-common/interactiveBase.ts index 8e2635aa9c9b..a678ac389400 100644 --- a/src/client/datascience/interactive-common/interactiveBase.ts +++ b/src/client/datascience/interactive-common/interactiveBase.ts @@ -459,8 +459,7 @@ export abstract class InteractiveBase extends WebViewHost { traceInfo(`Submitting code for ${this.id}`); - const stopWatch = - this._notebook && !this.perceivedJupyterStartupTelemetryCaptured ? new StopWatch() : undefined; + const stopWatch = this._notebook && !this.perceivedJupyterStartupTelemetryCaptured ? new StopWatch() : undefined; let result = true; // Do not execute or render empty code cells const cellMatcher = new CellMatcher(this.configService.getSettings().datascience);