Path: blob/main/src/vs/workbench/contrib/performance/browser/inputLatencyContrib.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { inputLatency } from '../../../../base/browser/performance.js';6import { RunOnceScheduler } from '../../../../base/common/async.js';7import { Event } from '../../../../base/common/event.js';8import { Disposable, MutableDisposable } from '../../../../base/common/lifecycle.js';9import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';10import { IWorkbenchContribution } from '../../../common/contributions.js';11import { IEditorService } from '../../../services/editor/common/editorService.js';1213export class InputLatencyContrib extends Disposable implements IWorkbenchContribution {14private readonly _listener = this._register(new MutableDisposable());15private readonly _scheduler: RunOnceScheduler;1617constructor(18@IEditorService private readonly _editorService: IEditorService,19@ITelemetryService private readonly _telemetryService: ITelemetryService20) {21super();2223// The current sampling strategy is when the active editor changes, start sampling and24// report the results after 60 seconds. It's done this way as we don't want to sample25// everything, just somewhat randomly, and using an interval would utilize CPU when the26// application is inactive.27this._scheduler = this._register(new RunOnceScheduler(() => {28this._logSamples();29this._setupListener();30}, 60000));313233// Only log 1% of users selected randomly to reduce the volume of data34if (Math.random() <= 0.01) {35this._setupListener();36}3738}3940private _setupListener(): void {41this._listener.value = Event.once(this._editorService.onDidActiveEditorChange)(() => this._scheduler.schedule());42}4344private _logSamples(): void {45const measurements = inputLatency.getAndClearMeasurements();46if (!measurements) {47return;48}4950type InputLatencyStatisticFragment = {51owner: 'tyriar';52comment: 'Represents a set of statistics collected about input latencies';53average: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The average time it took to execute.' };54max: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The maximum time it took to execute.' };55min: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The minimum time it took to execute.' };56};5758type PerformanceInputLatencyClassification = {59owner: 'tyriar';60comment: 'This is a set of samples of the time (in milliseconds) that various events took when typing in the editor';61keydown: InputLatencyStatisticFragment;62input: InputLatencyStatisticFragment;63render: InputLatencyStatisticFragment;64total: InputLatencyStatisticFragment;65sampleCount: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The number of samples measured.' };66};6768type PerformanceInputLatencyEvent = inputLatency.IInputLatencyMeasurements;6970this._telemetryService.publicLog2<PerformanceInputLatencyEvent, PerformanceInputLatencyClassification>('performance.inputLatency', {71keydown: measurements.keydown,72input: measurements.input,73render: measurements.render,74total: measurements.total,75sampleCount: measurements.sampleCount76});77}78}798081