diff --git a/src/bootstrap-esm.ts b/src/bootstrap-esm.ts index f2cf101bb90e8..8640ba96eab2b 100644 --- a/src/bootstrap-esm.ts +++ b/src/bootstrap-esm.ts @@ -38,7 +38,7 @@ if (process.env['ELECTRON_RUN_AS_NODE'] || process.versions['electron']) { globalThis._VSCODE_PRODUCT_JSON = { ...product }; if (process.env['VSCODE_DEV']) { try { - const overrides = require('../product.overrides.json'); + const overrides: unknown = require('../product.overrides.json'); globalThis._VSCODE_PRODUCT_JSON = Object.assign(globalThis._VSCODE_PRODUCT_JSON, overrides); } catch (error) { /* ignore */ } } diff --git a/src/bootstrap-fork.ts b/src/bootstrap-fork.ts index 85c831f9f612f..a92290a213dc6 100644 --- a/src/bootstrap-fork.ts +++ b/src/bootstrap-fork.ts @@ -19,7 +19,7 @@ function pipeLoggingToParent(): void { * Prevent circular stringify and convert arguments to real array */ function safeToString(args: ArrayLike): string { - const seen: string[] = []; + const seen: unknown[] = []; const argsArray: unknown[] = []; // Massage some arguments with special treatment @@ -50,7 +50,7 @@ function pipeLoggingToParent(): void { } try { - const res = JSON.stringify(argsArray, function (key, value) { + const res = JSON.stringify(argsArray, function (key, value: unknown) { // Objects get special treatment to prevent circles if (isObject(value) || Array.isArray(value)) { diff --git a/src/main.ts b/src/main.ts index 62ddd5f0cae15..ff9a5e89296c3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,6 +6,7 @@ import * as path from 'path'; import * as fs from 'original-fs'; import * as os from 'os'; +import { performance } from 'perf_hooks'; import { configurePortable } from './bootstrap-node.js'; import { bootstrapESM } from './bootstrap-esm.js'; import { fileURLToPath } from 'url'; @@ -24,6 +25,14 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); perf.mark('code/didStartMain'); +perf.mark('code/willLoadMainBundle', { + // When built, the main bundle is a single JS file with all + // dependencies inlined. As such, we mark `willLoadMainBundle` + // as the start of the main bundle loading process. + startTime: Math.floor(performance.timeOrigin) +}); +perf.mark('code/didLoadMainBundle'); + // Enable portable support const portable = configurePortable(product); @@ -177,9 +186,8 @@ async function startup(codeCachePath: string | undefined, nlsConfig: INLSConfigu await bootstrapESM(); // Load Main - perf.mark('code/willLoadMainBundle'); await import('./vs/code/electron-main/main.js'); - perf.mark('code/didLoadMainBundle'); + perf.mark('code/didRunMainBundle'); } function configureCommandlineSwitchesSync(cliArgs: NativeParsedArgs) { diff --git a/src/vs/base/common/performance.ts b/src/vs/base/common/performance.ts index 121b47104845d..26cd624136b80 100644 --- a/src/vs/base/common/performance.ts +++ b/src/vs/base/common/performance.ts @@ -11,8 +11,8 @@ function _definePolyfillMarks(timeOrigin?: number) { _data.push('code/timeOrigin', timeOrigin); } - function mark(name: string) { - _data.push(name, Date.now()); + function mark(name: string, markOptions?: { startTime?: number }) { + _data.push(name, markOptions?.startTime ?? Date.now()); } function getMarks() { const result = []; @@ -45,8 +45,8 @@ function _define() { } else { // use "native" performance for mark and getMarks return { - mark(name: string) { - performance.mark(name); + mark(name: string, markOptions?: { startTime?: number }) { + performance.mark(name, markOptions); }, getMarks() { let timeOrigin = performance.timeOrigin; @@ -89,7 +89,7 @@ function _factory(sharedObj: any) { const perf = _factory(globalThis); -export const mark: (name: string) => void = perf.mark; +export const mark: (name: string, markOptions?: { startTime?: number }) => void = perf.mark; export interface PerformanceMark { readonly name: string; diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index bb5f41975b285..d3c4d5104d8a4 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -146,7 +146,7 @@ export async function main(argv: string[]): Promise { let source: string | undefined; let target: string | undefined; try { - const argsContents = JSON.parse(readFileSync(argsFile, 'utf8')); + const argsContents: { source: string; target: string } = JSON.parse(readFileSync(argsFile, 'utf8')); source = argsContents.source; target = argsContents.target; } catch (error) { diff --git a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts index 37559fe0aa3ee..20518d6be9bb7 100644 --- a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts @@ -195,7 +195,8 @@ class PerfModelContentProvider implements ITextModelContentProvider { const table: Array> = []; table.push(['start => app.isReady', metrics.timers.ellapsedAppReady, '[main]', `initial startup: ${metrics.initialStartup}`]); table.push(['nls:start => nls:end', metrics.timers.ellapsedNlsGeneration, '[main]', `initial startup: ${metrics.initialStartup}`]); - table.push(['import(main.bundle.js)', metrics.timers.ellapsedLoadMainBundle, '[main]', `initial startup: ${metrics.initialStartup}`]); + table.push(['import(main.js)', metrics.timers.ellapsedLoadMainBundle, '[main]', `initial startup: ${metrics.initialStartup}`]); + table.push(['run main.js', metrics.timers.ellapsedRunMainBundle, '[main]', `initial startup: ${metrics.initialStartup}`]); table.push(['start crash reporter', metrics.timers.ellapsedCrashReporter, '[main]', `initial startup: ${metrics.initialStartup}`]); table.push(['serve main IPC handle', metrics.timers.ellapsedMainServer, '[main]', `initial startup: ${metrics.initialStartup}`]); table.push(['create window', metrics.timers.ellapsedWindowCreate, '[main]', `initial startup: ${metrics.initialStartup}, ${metrics.initialStartup ? `state: ${metrics.timers.ellapsedWindowRestoreState}ms, widget: ${metrics.timers.ellapsedBrowserWindowCreate}ms, show: ${metrics.timers.ellapsedWindowMaximize}ms` : ''}`]); diff --git a/src/vs/workbench/services/timer/browser/timerService.ts b/src/vs/workbench/services/timer/browser/timerService.ts index 77f0d8152bcc3..f880c4940d61a 100644 --- a/src/vs/workbench/services/timer/browser/timerService.ts +++ b/src/vs/workbench/services/timer/browser/timerService.ts @@ -49,6 +49,7 @@ export interface IMemoryInfo { "timers.ellapsedAppReady" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedNlsGeneration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedLoadMainBundle" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "timers.ellapsedRunMainBundle" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedCrashReporter" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedMainServer" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedWindowCreate" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, @@ -188,6 +189,14 @@ export interface IStartupMetrics { */ readonly ellapsedLoadMainBundle?: number; + /** + * The time it took to run the main bundle. + * + * * Happens in the main-process + * * Measured with the `didStartMain` and `didRunMainBundle` performance marks. + */ + readonly ellapsedRunMainBundle?: number; + /** * The time it took to start the crash reporter. * @@ -692,6 +701,7 @@ export abstract class AbstractTimerService implements ITimerService { ellapsedAppReady: initialStartup ? this._marks.getDuration('code/didStartMain', 'code/mainAppReady') : undefined, ellapsedNlsGeneration: initialStartup ? this._marks.getDuration('code/willGenerateNls', 'code/didGenerateNls') : undefined, ellapsedLoadMainBundle: initialStartup ? this._marks.getDuration('code/willLoadMainBundle', 'code/didLoadMainBundle') : undefined, + ellapsedRunMainBundle: initialStartup ? this._marks.getDuration('code/didStartMain', 'code/didRunMainBundle') : undefined, ellapsedCrashReporter: initialStartup ? this._marks.getDuration('code/willStartCrashReporter', 'code/didStartCrashReporter') : undefined, ellapsedMainServer: initialStartup ? this._marks.getDuration('code/willStartMainServer', 'code/didStartMainServer') : undefined, ellapsedWindowCreate: initialStartup ? this._marks.getDuration('code/willCreateCodeWindow', 'code/didCreateCodeWindow') : undefined,