Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/performance/electron-browser/rendererAutoProfiler.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { timeout } from '../../../../base/common/async.js';
7
import { VSBuffer } from '../../../../base/common/buffer.js';
8
import { joinPath } from '../../../../base/common/resources.js';
9
import { generateUuid } from '../../../../base/common/uuid.js';
10
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
11
import { IFileService } from '../../../../platform/files/common/files.js';
12
import { ILogService } from '../../../../platform/log/common/log.js';
13
import { INativeHostService } from '../../../../platform/native/common/native.js';
14
import { IV8Profile } from '../../../../platform/profiling/common/profiling.js';
15
import { IProfileAnalysisWorkerService, ProfilingOutput } from '../../../../platform/profiling/electron-browser/profileAnalysisWorkerService.js';
16
import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js';
17
import { parseExtensionDevOptions } from '../../../services/extensions/common/extensionDevOptions.js';
18
import { ITimerService } from '../../../services/timer/browser/timerService.js';
19
20
export class RendererProfiling {
21
22
private _observer?: PerformanceObserver;
23
24
constructor(
25
@INativeWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService,
26
@IFileService private readonly _fileService: IFileService,
27
@ILogService private readonly _logService: ILogService,
28
@INativeHostService nativeHostService: INativeHostService,
29
@ITimerService timerService: ITimerService,
30
@IConfigurationService configService: IConfigurationService,
31
@IProfileAnalysisWorkerService profileAnalysisService: IProfileAnalysisWorkerService
32
) {
33
34
const devOpts = parseExtensionDevOptions(_environmentService);
35
if (devOpts.isExtensionDevTestFromCli) {
36
// disabled when running extension tests
37
return;
38
}
39
40
timerService.perfBaseline.then(perfBaseline => {
41
(_environmentService.isBuilt ? _logService.info : _logService.trace).apply(_logService, [`[perf] Render performance baseline is ${perfBaseline}ms`]);
42
43
if (perfBaseline < 0) {
44
// too slow
45
return;
46
}
47
48
// SLOW threshold
49
const slowThreshold = perfBaseline * 10; // ~10 frames at 64fps on MY machine
50
51
const obs = new PerformanceObserver(async list => {
52
53
obs.takeRecords();
54
const maxDuration = list.getEntries()
55
.map(e => e.duration)
56
.reduce((p, c) => Math.max(p, c), 0);
57
58
if (maxDuration < slowThreshold) {
59
return;
60
}
61
62
if (!configService.getValue('application.experimental.rendererProfiling')) {
63
_logService.debug(`[perf] SLOW task detected (${maxDuration}ms) but renderer profiling is disabled via 'application.experimental.rendererProfiling'`);
64
return;
65
}
66
67
const sessionId = generateUuid();
68
69
_logService.warn(`[perf] Renderer reported VERY LONG TASK (${maxDuration}ms), starting profiling session '${sessionId}'`);
70
71
// pause observation, we'll take a detailed look
72
obs.disconnect();
73
74
// profile renderer for 5secs, analyse, and take action depending on the result
75
for (let i = 0; i < 3; i++) {
76
77
try {
78
const profile = await nativeHostService.profileRenderer(sessionId, 5000);
79
const output = await profileAnalysisService.analyseBottomUp(profile, _url => '<<renderer>>', perfBaseline, true);
80
if (output === ProfilingOutput.Interesting) {
81
this._store(profile, sessionId);
82
break;
83
}
84
85
timeout(15000); // wait 15s
86
87
} catch (err) {
88
_logService.error(err);
89
break;
90
}
91
}
92
93
// reconnect the observer
94
obs.observe({ entryTypes: ['longtask'] });
95
});
96
97
obs.observe({ entryTypes: ['longtask'] });
98
this._observer = obs;
99
100
});
101
}
102
103
dispose(): void {
104
this._observer?.disconnect();
105
}
106
107
108
private async _store(profile: IV8Profile, sessionId: string): Promise<void> {
109
const path = joinPath(this._environmentService.tmpDir, `renderer-${Math.random().toString(16).slice(2, 8)}.cpuprofile.json`);
110
await this._fileService.writeFile(path, VSBuffer.fromString(JSON.stringify(profile)));
111
this._logService.info(`[perf] stored profile to DISK '${path}'`, sessionId);
112
}
113
}
114
115