diff --git a/src/main.js b/src/main.js index 9f7e2304720..b23c29dc50b 100644 --- a/src/main.js +++ b/src/main.js @@ -18,7 +18,6 @@ perf.mark('code/didStartMain'); const path = require('path'); const fs = require('fs'); const os = require('os'); -const { getNLSConfiguration } = require('./vs/base/node/languagePacks'); const bootstrap = require('./bootstrap'); const bootstrapNode = require('./bootstrap-node'); const { getUserDataPath } = require('./vs/platform/environment/node/userDataPath'); @@ -87,6 +86,7 @@ let nlsConfigurationPromise = undefined; const metaDataFile = path.join(__dirname, 'nls.metadata.json'); const locale = getUserDefinedLocale(argvConfig); if (locale) { + const { getNLSConfiguration } = require('./vs/base/node/languagePacks'); nlsConfigurationPromise = getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); } @@ -579,6 +579,7 @@ async function resolveNlsConfiguration() { // See above the comment about the loader and case sensitiviness appLocale = appLocale.toLowerCase(); + const { getNLSConfiguration } = require('./vs/base/node/languagePacks'); nlsConfiguration = await getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale); if (!nlsConfiguration) { nlsConfiguration = { locale: appLocale, availableLanguages: {} }; diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 761d20f3786..a34f03523b7 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -93,6 +93,7 @@ import { ISignService } from 'vs/platform/sign/common/sign'; * even if the user starts many instances (e.g. from the command line). */ export class CodeApplication extends Disposable { + private windowsMainService: IWindowsMainService | undefined; private nativeHostMainService: INativeHostMainService | undefined; diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 9f66c45a146..a2687622d9d 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -8,6 +8,7 @@ import { app, dialog } from 'electron'; import { promises, unlinkSync } from 'fs'; import { localize } from 'vs/nls'; import { isWindows, IProcessEnvironment, isMacintosh } from 'vs/base/common/platform'; +import { mark } from 'vs/base/common/performance'; import product from 'vs/platform/product/common/product'; import { parseMainProcessArgv, addArg } from 'vs/platform/environment/node/argvHelper'; import { createWaitMarkerFile } from 'vs/platform/environment/node/wait'; @@ -107,7 +108,7 @@ class CodeMain { // Create the main IPC server by trying to be the server // If this throws an error it means we are not the first // instance of VS Code running and so we would quit. - const mainProcessNodeIpcServer = await this.doStartup(logService, environmentService, lifecycleMainService, instantiationService, productService, true); + const mainProcessNodeIpcServer = await this.claimInstance(logService, environmentService, lifecycleMainService, instantiationService, productService, true); // Delay creation of spdlog for perf reasons (https://github.com/microsoft/vscode/issues/72906) bufferLogService.logger = new SpdLogLogger('main', join(environmentService.logsPath, 'main.log'), true, bufferLogService.getLevel()); @@ -221,14 +222,16 @@ class CodeMain { return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]); } - private async doStartup(logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, productService: IProductService, retry: boolean): Promise { + private async claimInstance(logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, productService: IProductService, retry: boolean): Promise { // Try to setup a server for running. If that succeeds it means // we are the first instance to startup. Otherwise it is likely // that another instance is already running. let mainProcessNodeIpcServer: NodeIPCServer; try { + mark('code/willStartMainServer'); mainProcessNodeIpcServer = await nodeIPCServe(environmentMainService.mainIPCHandle); + mark('code/didStartMainServer'); once(lifecycleMainService.onWillShutdown)(() => mainProcessNodeIpcServer.dispose()); } catch (error) { @@ -273,7 +276,7 @@ class CodeMain { throw error; } - return this.doStartup(logService, environmentMainService, lifecycleMainService, instantiationService, productService, false); + return this.claimInstance(logService, environmentMainService, lifecycleMainService, instantiationService, productService, false); } // Tests from CLI require to be the only instance currently diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 99bdc1713de..183b5324d11 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -678,7 +678,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi mark('code/didRestoreEditors'); })()); - // Restore default views + // Restore default views (only when `IDefaultLayout` is provided) const restoreDefaultViewsPromise = (async () => { if (this.state.views.defaults?.length) { mark('code/willOpenDefaultViews'); @@ -775,7 +775,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi mark('code/willRestorePanel'); - const panel = await this.panelService.openPanel(this.state.panel.panelToRestore!); + const panel = await this.panelService.openPanel(this.state.panel.panelToRestore); if (!panel) { await this.panelService.openPanel(Registry.as(PanelExtensions.Panels).getDefaultPanelId()); // fallback to default panel as needed } diff --git a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts index b50dca22023..0e437ffaffe 100644 --- a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts @@ -169,6 +169,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { 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(['require(main.bundle.js)', metrics.timers.ellapsedLoadMainBundle, '[main]', `initial startup: ${metrics.initialStartup}`]); + table.push(['serve main IPC handle', metrics.timers.ellapsedMainServer, '[main]', `initial startup: ${metrics.initialStartup}`]); table.push(['app.isReady => window.loadUrl()', metrics.timers.ellapsedWindowLoad, '[main]', `initial startup: ${metrics.initialStartup}`]); table.push(['window.loadUrl() => begin to require(workbench.desktop.main.js)', metrics.timers.ellapsedWindowLoadToRequire, '[main->renderer]', StartupKindToString(metrics.windowKind)]); table.push(['require(workbench.desktop.main.js)', metrics.timers.ellapsedRequire, '[renderer]', `cached data: ${(metrics.didUseCachedData ? 'YES' : 'NO')}${stats ? `, node_modules took ${stats.nodeRequireTotal}ms` : ''}`]); diff --git a/src/vs/workbench/services/timer/browser/timerService.ts b/src/vs/workbench/services/timer/browser/timerService.ts index 0e94af6bcb6..c62d344a545 100644 --- a/src/vs/workbench/services/timer/browser/timerService.ts +++ b/src/vs/workbench/services/timer/browser/timerService.ts @@ -41,23 +41,25 @@ export interface IMemoryInfo { "panelId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "editorIds": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "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.ellapsedMainServer" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedWindowLoad" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedWindowLoadToRequire" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "timers.ellapsedExtensions" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "timers.ellapsedExtensionsReady" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "timers.ellapsedRequire" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "timers.ellapsedWaitForWindowConfig" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "timers.ellapsedWaitForShellEnv" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedStorageInit" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "timers.ellapsedSharedProcesConnected" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedWorkspaceServiceInit" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "timers.ellapsedSharedProcesConnected" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedRequiredUserDataInit" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedOtherUserDataInit" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "timers.ellapsedRequire" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "timers.ellapsedExtensions" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "timers.ellapsedExtensionsReady" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedViewletRestore" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedPanelRestore" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedEditorRestore" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedWorkbench" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "timers.ellapsedNlsGeneration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "timers.ellapsedWaitForWindowConfig" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "timers.ellapsedWaitForShellEnv" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "platform" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "release" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "arch" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, @@ -177,6 +179,14 @@ export interface IStartupMetrics { */ readonly ellapsedLoadMainBundle?: number; + /** + * The time it took to create the main instance server. + * + * * Happens in the main-process + * * Measured with the `willStartMainServer` and `didStartMainServer` performance marks. + */ + readonly ellapsedMainServer?: number; + /** * The time it took to tell electron to open/restore a renderer (browser window). * @@ -528,6 +538,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, + ellapsedMainServer: initialStartup ? this._marks.getDuration('code/willStartMainServer', 'code/didStartMainServer') : undefined, ellapsedWindowLoad: initialStartup ? this._marks.getDuration('code/mainAppReady', 'code/willOpenNewWindow') : undefined, ellapsedWindowLoadToRequire: this._marks.getDuration('code/willOpenNewWindow', 'code/willLoadWorkbenchMain'), ellapsedRequire: this._marks.getDuration('code/willLoadWorkbenchMain', 'code/didLoadWorkbenchMain'),