mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 18:49:00 +01:00
[typescript-language-features] Add diagnostics performance telemetry (#220127)
* WIP * invalidate diagnostics in range * check whether should use region based diagnostics * add ts-expect-errors * make region opt off by default * bump to expected 5.6 * update comments to refer to 5.6 * make region diagnostics on by default for insiders * add telemetry for diagnostics performance * add file line count * remove comment * use block on case * add ts-expect-error * declare interface earlier in file * address review comments
This commit is contained in:
committed by
GitHub
parent
a0599a9e2f
commit
14cf5001ec
@@ -11,6 +11,8 @@ import { ResourceMap } from '../utils/resourceMap';
|
||||
import { TelemetryReporter } from '../logging/telemetry';
|
||||
import { TypeScriptServiceConfiguration } from '../configuration/configuration';
|
||||
import { equals } from '../utils/objects';
|
||||
// @ts-expect-error until ts 5.6
|
||||
import { DiagnosticPerformanceData as TsDiagnosticPerformanceData } from '../tsServer/protocol/protocol';
|
||||
|
||||
function diagnosticsEquals(a: vscode.Diagnostic, b: vscode.Diagnostic): boolean {
|
||||
if (a === b) {
|
||||
@@ -173,6 +175,10 @@ class DiagnosticSettings {
|
||||
}
|
||||
}
|
||||
|
||||
interface DiagnosticPerformanceData extends TsDiagnosticPerformanceData {
|
||||
fileLineCount?: number;
|
||||
}
|
||||
|
||||
class DiagnosticsTelemetryManager extends Disposable {
|
||||
|
||||
private readonly _diagnosticCodesMap = new Map<number, number>();
|
||||
@@ -194,6 +200,37 @@ class DiagnosticsTelemetryManager extends Disposable {
|
||||
this._registerTelemetryEventEmitter();
|
||||
}
|
||||
|
||||
public logDiagnosticsPerformanceTelemetry(performanceData: DiagnosticPerformanceData[]): void {
|
||||
for (const data of performanceData) {
|
||||
/* __GDPR__
|
||||
"diagnostics.performance" : {
|
||||
"owner": "mjbvz",
|
||||
"syntaxDiagDuration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"semanticDiagDuration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"suggestionDiagDuration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"regionSemanticDiagDuration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"fileLineCount" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"${include}": [
|
||||
"${TypeScriptCommonProperties}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this._telemetryReporter.logTelemetry('diagnostics.performance',
|
||||
{
|
||||
// @ts-expect-error until ts 5.6
|
||||
syntaxDiagDuration: data.syntaxDiag,
|
||||
// @ts-expect-error until ts 5.6
|
||||
semanticDiagDuration: data.semanticDiag,
|
||||
// @ts-expect-error until ts 5.6
|
||||
suggestionDiagDuration: data.suggestionDiag,
|
||||
// @ts-expect-error until ts 5.6
|
||||
regionSemanticDiagDuration: data.regionSemanticDiag,
|
||||
fileLineCount: data.fileLineCount,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _updateAllDiagnosticCodesAfterTimeout() {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = setTimeout(() => this._updateDiagnosticCodes(), 5000);
|
||||
@@ -257,6 +294,8 @@ export class DiagnosticsManager extends Disposable {
|
||||
|
||||
private readonly _updateDelay = 50;
|
||||
|
||||
private readonly _diagnosticsTelemetryManager: DiagnosticsTelemetryManager | undefined;
|
||||
|
||||
constructor(
|
||||
owner: string,
|
||||
configuration: TypeScriptServiceConfiguration,
|
||||
@@ -270,7 +309,7 @@ export class DiagnosticsManager extends Disposable {
|
||||
this._currentDiagnostics = this._register(vscode.languages.createDiagnosticCollection(owner));
|
||||
// Here we are selecting only 1 user out of 1000 to send telemetry diagnostics
|
||||
if (Math.random() * 1000 <= 1 || configuration.enableDiagnosticsTelemetry) {
|
||||
this._register(new DiagnosticsTelemetryManager(telemetryReporter, this._currentDiagnostics));
|
||||
this._diagnosticsTelemetryManager = this._register(new DiagnosticsTelemetryManager(telemetryReporter, this._currentDiagnostics));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,6 +388,10 @@ export class DiagnosticsManager extends Disposable {
|
||||
return this._currentDiagnostics.get(file) || [];
|
||||
}
|
||||
|
||||
public logDiagnosticsPerformanceTelemetry(performanceData: DiagnosticPerformanceData[]): void {
|
||||
this._diagnosticsTelemetryManager?.logDiagnosticsPerformanceTelemetry(performanceData);
|
||||
}
|
||||
|
||||
private scheduleDiagnosticsUpdate(file: vscode.Uri) {
|
||||
if (!this._pendingUpdates.has(file)) {
|
||||
this._pendingUpdates.set(file, setTimeout(() => this.updateCurrentDiagnostics(file), this._updateDelay));
|
||||
|
||||
@@ -662,6 +662,10 @@ export default class BufferSyncSupport extends Disposable {
|
||||
this.synchronizer.beforeCommand(command);
|
||||
}
|
||||
|
||||
public lineCount(resource: vscode.Uri): number | undefined {
|
||||
return this.syncedBuffers.get(resource)?.lineCount;
|
||||
}
|
||||
|
||||
private onDidCloseTextDocument(document: vscode.TextDocument): void {
|
||||
this.closeResource(document.uri);
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ export enum EventName {
|
||||
createFileWatcher = 'createFileWatcher',
|
||||
createDirectoryWatcher = 'createDirectoryWatcher',
|
||||
closeFileWatcher = 'closeFileWatcher',
|
||||
requestCompleted = 'requestCompleted',
|
||||
}
|
||||
|
||||
export enum OrganizeImportsMode {
|
||||
|
||||
@@ -166,6 +166,10 @@ export class SingleTsServer extends Disposable implements ITypeScriptServer {
|
||||
this._tracer.traceRequestCompleted(this._serverId, 'requestCompleted', seq, callback);
|
||||
callback.onSuccess(undefined);
|
||||
}
|
||||
// @ts-expect-error until ts 5.6
|
||||
if ((event as Proto.RequestCompletedEvent).body.performanceData) {
|
||||
this._onEvent.fire(event);
|
||||
}
|
||||
} else {
|
||||
this._tracer.traceEvent(this._serverId, event);
|
||||
this._onEvent.fire(event);
|
||||
|
||||
@@ -141,7 +141,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
||||
|
||||
constructor(
|
||||
private readonly context: vscode.ExtensionContext,
|
||||
onCaseInsenitiveFileSystem: boolean,
|
||||
onCaseInsensitiveFileSystem: boolean,
|
||||
services: {
|
||||
pluginManager: PluginManager;
|
||||
logDirectoryProvider: ILogDirectoryProvider;
|
||||
@@ -191,7 +191,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
||||
this.restartTsServer();
|
||||
}));
|
||||
|
||||
this.bufferSyncSupport = new BufferSyncSupport(this, allModeIds, onCaseInsenitiveFileSystem);
|
||||
this.bufferSyncSupport = new BufferSyncSupport(this, allModeIds, onCaseInsensitiveFileSystem);
|
||||
this.onReady(() => { this.bufferSyncSupport.listen(); });
|
||||
|
||||
this.bufferSyncSupport.onDelete(resource => {
|
||||
@@ -232,7 +232,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
||||
return this.apiVersion.fullVersionString;
|
||||
});
|
||||
|
||||
this.diagnosticsManager = new DiagnosticsManager('typescript', this._configuration, this.telemetryReporter, onCaseInsenitiveFileSystem);
|
||||
this.diagnosticsManager = new DiagnosticsManager('typescript', this._configuration, this.telemetryReporter, onCaseInsensitiveFileSystem);
|
||||
this.typescriptServerSpawner = new TypeScriptServerSpawner(this.versionProvider, this._versionManager, this._nodeVersionManager, this.logDirectoryProvider, this.pluginPathsProvider, this.logger, this.telemetryReporter, this.tracer, this.processFactory);
|
||||
|
||||
this._register(this.pluginManager.onDidUpdateConfig(update => {
|
||||
@@ -1038,6 +1038,24 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
||||
case EventName.closeFileWatcher:
|
||||
this.closeFileSystemWatcher(event.body.id);
|
||||
break;
|
||||
|
||||
case EventName.requestCompleted: {
|
||||
// @ts-expect-error until ts 5.6
|
||||
const diagnosticsDuration = (event.body as Proto.RequestCompletedEventBody).performanceData?.diagnosticsDuration;
|
||||
if (diagnosticsDuration) {
|
||||
this.diagnosticsManager.logDiagnosticsPerformanceTelemetry(
|
||||
// @ts-expect-error until ts 5.6
|
||||
diagnosticsDuration.map(fileData => {
|
||||
const resource = this.toResource(fileData.file);
|
||||
return {
|
||||
...fileData,
|
||||
lineCount: this.bufferSyncSupport.lineCount(resource),
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user