Skip to content

Commit 4093317

Browse files
authored
Metrics tracking launch times for native locator (#23854)
1 parent a45df21 commit 4093317

File tree

3 files changed

+105
-5
lines changed

3 files changed

+105
-5
lines changed

src/client/pythonEnvironments/base/locators/common/nativePythonFinder.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { createLogOutputChannel } from '../../../../common/vscodeApis/windowApis
2020
import { sendNativeTelemetry, NativePythonTelemetry } from './nativePythonTelemetry';
2121
import { NativePythonEnvironmentKind } from './nativePythonUtils';
2222
import type { IExtensionContext } from '../../../../common/types';
23+
import { StopWatch } from '../../../../common/utils/stopWatch';
2324

2425
const untildify = require('untildify');
2526

@@ -100,6 +101,12 @@ class NativePythonFinderImpl extends DisposableBase implements NativePythonFinde
100101

101102
private readonly outputChannel = this._register(createLogOutputChannel('Python Locator', { log: true }));
102103

104+
private initialRefreshMetrics = {
105+
timeToSpawn: 0,
106+
timeToConfigure: 0,
107+
timeToRefresh: 0,
108+
};
109+
103110
constructor(private readonly cacheDirectory?: Uri) {
104111
super();
105112
this.connection = this.start();
@@ -199,7 +206,9 @@ class NativePythonFinderImpl extends DisposableBase implements NativePythonFinde
199206
const writable = new PassThrough();
200207
const disposables: Disposable[] = [];
201208
try {
209+
const stopWatch = new StopWatch();
202210
const proc = ch.spawn(PYTHON_ENV_TOOLS_PATH, ['server'], { env: process.env });
211+
this.initialRefreshMetrics.timeToSpawn = stopWatch.elapsedTime;
203212
proc.stdout.pipe(readable, { end: false });
204213
proc.stderr.on('data', (data) => this.outputChannel.error(data.toString()));
205214
writable.pipe(proc.stdin, { end: false });
@@ -251,7 +260,9 @@ class NativePythonFinderImpl extends DisposableBase implements NativePythonFinde
251260
this.outputChannel.trace(data.message);
252261
}
253262
}),
254-
connection.onNotification('telemetry', (data: NativePythonTelemetry) => sendNativeTelemetry(data)),
263+
connection.onNotification('telemetry', (data: NativePythonTelemetry) =>
264+
sendNativeTelemetry(data, this.initialRefreshMetrics),
265+
),
255266
connection.onClose(() => {
256267
disposables.forEach((d) => d.dispose());
257268
}),
@@ -269,6 +280,7 @@ class NativePythonFinderImpl extends DisposableBase implements NativePythonFinde
269280
const discovered = disposable.add(new EventEmitter<NativeEnvInfo | NativeEnvManagerInfo>());
270281
const completed = createDeferred<void>();
271282
const pendingPromises: Promise<void>[] = [];
283+
const stopWatch = new StopWatch();
272284

273285
const notifyUponCompletion = () => {
274286
const initialCount = pendingPromises.length;
@@ -339,7 +351,10 @@ class NativePythonFinderImpl extends DisposableBase implements NativePythonFinde
339351
this.configure().then(() =>
340352
this.connection
341353
.sendRequest<{ duration: number }>('refresh', refreshOptions)
342-
.then(({ duration }) => this.outputChannel.info(`Refresh completed in ${duration}ms`))
354+
.then(({ duration }) => {
355+
this.outputChannel.info(`Refresh completed in ${duration}ms`);
356+
this.initialRefreshMetrics.timeToRefresh = stopWatch.elapsedTime;
357+
})
343358
.catch((ex) => this.outputChannel.error('Refresh error', ex)),
344359
),
345360
);
@@ -371,8 +386,10 @@ class NativePythonFinderImpl extends DisposableBase implements NativePythonFinde
371386
return;
372387
}
373388
try {
389+
const stopWatch = new StopWatch();
374390
this.lastConfiguration = options;
375391
await this.connection.sendRequest('configure', options);
392+
this.initialRefreshMetrics.timeToConfigure = stopWatch.elapsedTime;
376393
} catch (ex) {
377394
this.outputChannel.error('Refresh error', ex);
378395
}

src/client/pythonEnvironments/base/locators/common/nativePythonTelemetry.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,14 @@ export type RefreshPerformance = {
8181

8282
let refreshTelemetrySent = false;
8383

84-
export function sendNativeTelemetry(data: NativePythonTelemetry): void {
84+
export function sendNativeTelemetry(
85+
data: NativePythonTelemetry,
86+
initialRefreshMetrics: {
87+
timeToSpawn: number;
88+
timeToConfigure: number;
89+
timeToRefresh: number;
90+
},
91+
): void {
8592
switch (data.event) {
8693
case 'MissingCondaEnvironments': {
8794
sendTelemetryEvent(
@@ -124,6 +131,9 @@ export function sendNativeTelemetry(data: NativePythonTelemetry): void {
124131
locatorVirtualEnvWrapper: data.data.refreshPerformance.locators.VirtualEnvWrapper || 0,
125132
locatorWindowsRegistry: data.data.refreshPerformance.locators.WindowsRegistry || 0,
126133
locatorWindowsStore: data.data.refreshPerformance.locators.WindowsStore || 0,
134+
timeToSpawn: initialRefreshMetrics.timeToSpawn,
135+
timeToConfigure: initialRefreshMetrics.timeToConfigure,
136+
timeToRefresh: initialRefreshMetrics.timeToRefresh,
127137
});
128138
break;
129139
}

src/client/telemetry/index.ts

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,38 +1755,111 @@ export interface IEventNamePropertyMapping {
17551755
"locatorVirtualEnv" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
17561756
"locatorVirtualEnvWrapper" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
17571757
"locatorWindowsRegistry" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
1758-
"locatorWindowsStore" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" }
1758+
"locatorWindowsStore" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
1759+
"timeToSpawn" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
1760+
"timeToConfigure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
1761+
"timeToRefresh" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" }
17591762
}
17601763
*/
17611764
[EventName.NATIVE_FINDER_PERF]: {
17621765
/**
17631766
* Total duration to find envs using native locator.
1767+
* This is the time from the perspective of the Native Locator.
1768+
* I.e. starting from the time the request to refresh was received until the end of the refresh.
17641769
*/
17651770
duration: number;
1771+
/**
1772+
* Time taken by all locators to find the environments.
1773+
* I.e. time for Conda + Poetry + Pyenv, etc (note: all of them run in parallel).
1774+
*/
17661775
breakdownLocators?: number;
1776+
/**
1777+
* Time taken to find Python environments in the paths found in the PATH env variable.
1778+
*/
17671779
breakdownPath?: number;
1780+
/**
1781+
* Time taken to find Python environments in the global virtual env locations.
1782+
*/
17681783
breakdownGlobalVirtualEnvs?: number;
1784+
/**
1785+
* Time taken to find Python environments in the workspaces.
1786+
*/
17691787
breakdownWorkspaces?: number;
1788+
/**
1789+
* Time taken to find all global Conda environments.
1790+
*/
17701791
locatorConda?: number;
1792+
/**
1793+
* Time taken to find all Homebrew environments.
1794+
*/
17711795
locatorHomebrew?: number;
1796+
/**
1797+
* Time taken to find all global Python environments on Linux.
1798+
*/
17721799
locatorLinuxGlobalPython?: number;
1800+
/**
1801+
* Time taken to find all Python environments belonging to Mac Command Line Tools .
1802+
*/
17731803
locatorMacCmdLineTools?: number;
1804+
/**
1805+
* Time taken to find all Python environments belonging to Mac Python Org.
1806+
*/
17741807
locatorMacPythonOrg?: number;
1808+
/**
1809+
* Time taken to find all Python environments belonging to Mac XCode.
1810+
*/
17751811
locatorMacXCode?: number;
1812+
/**
1813+
* Time taken to find all Pipenv environments.
1814+
*/
17761815
locatorPipEnv?: number;
1816+
/**
1817+
* Time taken to find all Poetry environments.
1818+
*/
17771819
locatorPoetry?: number;
1820+
/**
1821+
* Time taken to find all Pyenv environments.
1822+
*/
17781823
locatorPyEnv?: number;
1824+
/**
1825+
* Time taken to find all Venv environments.
1826+
*/
17791827
locatorVenv?: number;
1828+
/**
1829+
* Time taken to find all VirtualEnv environments.
1830+
*/
17801831
locatorVirtualEnv?: number;
1832+
/**
1833+
* Time taken to find all VirtualEnvWrapper environments.
1834+
*/
17811835
locatorVirtualEnvWrapper?: number;
1836+
/**
1837+
* Time taken to find all Windows Registry environments.
1838+
*/
17821839
locatorWindowsRegistry?: number;
1840+
/**
1841+
* Time taken to find all Windows Store environments.
1842+
*/
17831843
locatorWindowsStore?: number;
1844+
/**
1845+
* Total time taken to spawn the Native Python finder process.
1846+
*/
1847+
timeToSpawn?: number;
1848+
/**
1849+
* Total time taken to configure the Native Python finder process.
1850+
*/
1851+
timeToConfigure?: number;
1852+
/**
1853+
* Total time taken to refresh the Environments (from perspective of Python extension).
1854+
* Time = total time taken to process the `refresh` request.
1855+
*/
1856+
timeToRefresh?: number;
17841857
};
17851858
/**
17861859
* Telemetry event sent when discovery of all python environments using the native locator(virtualenv, conda, pipenv etc.) finishes.
17871860
*/
17881861
/* __GDPR__
1789-
"python_interpreter_discovery_native" : {
1862+
"python_interpreter_discovery_invalid_native" : {
17901863
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
17911864
"invalidVersionsCondaEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
17921865
"invalidVersionsCustomEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },

0 commit comments

Comments
 (0)