startup perf - load NLS module conditionally; add perf mark for main IPC server

This commit is contained in:
Benjamin Pasero 2021-04-08 12:08:31 +02:00
parent 11d3a8027d
commit 2214484ee4
No known key found for this signature in database
GPG key ID: E6380CC4C8219E65
6 changed files with 30 additions and 13 deletions

View file

@ -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: {} };

View file

@ -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;

View file

@ -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<NodeIPCServer> {
private async claimInstance(logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, productService: IProductService, retry: boolean): Promise<NodeIPCServer> {
// 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

View file

@ -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<PanelRegistry>(PanelExtensions.Panels).getDefaultPanelId()); // fallback to default panel as needed
}

View file

@ -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` : ''}`]);

View file

@ -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'),