Skip to content

Commit 593e178

Browse files
author
Benjamin Pasero
committed
sandbox - make timer service available in electron-sandbox
cc @jrieken
1 parent add7bbf commit 593e178

13 files changed

Lines changed: 113 additions & 45 deletions

File tree

src/vs/base/parts/sandbox/common/electronTypes.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,22 @@ export interface CrashReporterStartOptions {
309309
*/
310310
globalExtra?: Record<string, string>;
311311
}
312+
313+
export interface ProcessMemoryInfo {
314+
/**
315+
* The amount of memory not shared by other processes, such as JS heap or HTML
316+
* content in Kilobytes.
317+
*/
318+
private: number;
319+
/**
320+
* The amount of memory currently pinned to actual physical RAM in Kilobytes.
321+
*
322+
* @platform linux,win32
323+
*/
324+
residentSet: number;
325+
/**
326+
* The amount of memory shared between processes, typically memory consumed by the
327+
* Electron code itself in Kilobytes.
328+
*/
329+
shared: number;
330+
}

src/vs/base/parts/sandbox/electron-browser/preload.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
platform: process.platform,
9595
env: process.env,
9696
versions: process.versions,
97+
9798
_whenEnvResolved: undefined,
9899
get whenEnvResolved() {
99100
if (!this._whenEnvResolved) {
@@ -102,6 +103,15 @@
102103

103104
return this._whenEnvResolved;
104105
},
106+
107+
getProcessMemoryInfo:
108+
/**
109+
* @returns {Promise<import('electron').ProcessMemoryInfo>}
110+
*/
111+
function () {
112+
return process.getProcessMemoryInfo();
113+
},
114+
105115
on:
106116
/**
107117
* @param {string} type

src/vs/base/parts/sandbox/electron-sandbox/globals.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { ProcessMemoryInfo } from 'vs/base/parts/sandbox/common/electronTypes';
7+
68
export const ipcRenderer = (window as any).vscode.ipcRenderer as {
79

810
/**
@@ -95,6 +97,21 @@ export const process = (window as any).vscode.process as {
9597
*/
9698
on: (type: string, callback: Function) => void;
9799

100+
/**
101+
* Resolves with a ProcessMemoryInfo
102+
*
103+
* Returns an object giving memory usage statistics about the current process. Note
104+
* that all statistics are reported in Kilobytes. This api should be called after
105+
* app ready.
106+
*
107+
* Chromium does not provide `residentSet` value for macOS. This is because macOS
108+
* performs in-memory compression of pages that haven't been recently used. As a
109+
* result the resident set size value is not what one would expect. `private`
110+
* memory is more representative of the actual pre-compression memory usage of the
111+
* process on macOS.
112+
*/
113+
getProcessMemoryInfo: () => ProcessMemoryInfo;
114+
98115
/**
99116
* A list of versions for the current node.js/electron configuration.
100117
*/

src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,13 +293,13 @@ class ProcessExplorer {
293293
container.append(tableHead);
294294

295295
const hasMultipleMachines = Object.keys(processLists).length > 1;
296-
const totalMem = await this.electronService.getTotalMem();
296+
const { totalmem } = await this.electronService.getOSStatistics();
297297
processLists.forEach((remote, i) => {
298298
const isLocal = i === 0;
299299
if (isRemoteDiagnosticError(remote.rootProcess)) {
300300
this.renderProcessFetchError(remote.name, remote.rootProcess.errorMessage);
301301
} else {
302-
this.renderTableSection(remote.name, this.getProcessList(remote.rootProcess, isLocal, totalMem), hasMultipleMachines, isLocal);
302+
this.renderTableSection(remote.name, this.getProcessList(remote.rootProcess, isLocal, totalmem), hasMultipleMachines, isLocal);
303303
}
304304
});
305305
}

src/vs/platform/electron/common/electron.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,23 @@ import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs';
1010
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
1111
import { ColorScheme } from 'vs/platform/theme/common/theme';
1212

13+
export interface ICPUProperties {
14+
model: string;
15+
speed: number;
16+
}
17+
1318
export interface IOSProperties {
1419
type: string;
1520
release: string;
1621
arch: string;
1722
platform: string;
23+
cpus: ICPUProperties[];
24+
}
25+
26+
export interface IOSStatistics {
27+
totalmem: number;
28+
freemem: number;
29+
loadavg: number[];
1830
}
1931

2032
export interface ICommonElectronService {
@@ -82,8 +94,10 @@ export interface ICommonElectronService {
8294
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void>;
8395
moveItemToTrash(fullPath: string, deleteOnFail?: boolean): Promise<boolean>;
8496
isAdmin(): Promise<boolean>;
85-
getTotalMem(): Promise<number>;
86-
getOS(): Promise<IOSProperties>;
97+
98+
getOSProperties(): Promise<IOSProperties>;
99+
getOSStatistics(): Promise<IOSStatistics>;
100+
getOSVirtualMachineHint(): Promise<number>;
87101

88102
// Process
89103
killProcess(pid: number, code: string): Promise<void>;

src/vs/platform/electron/electron-main/electronMainService.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifec
1111
import { IOpenedWindow, IOpenWindowOptions, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
1212
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs';
1313
import { isMacintosh, isWindows, isRootUser } from 'vs/base/common/platform';
14-
import { ICommonElectronService, IOSProperties } from 'vs/platform/electron/common/electron';
14+
import { ICommonElectronService, IOSProperties, IOSStatistics } from 'vs/platform/electron/common/electron';
1515
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
1616
import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
1717
import { AddFirstParameterToFunctions } from 'vs/base/common/types';
@@ -21,8 +21,9 @@ import { URI } from 'vs/base/common/uri';
2121
import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
2222
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
2323
import { MouseInputEvent } from 'vs/base/parts/sandbox/common/electronTypes';
24-
import { arch, totalmem, release, platform, type } from 'os';
24+
import { arch, totalmem, release, platform, type, loadavg, freemem, cpus } from 'os';
2525
import { ColorScheme } from 'vs/platform/theme/common/theme';
26+
import { virtualMachineHint } from 'vs/base/node/id';
2627

2728
export interface IElectronMainService extends AddFirstParameterToFunctions<ICommonElectronService, Promise<unknown> /* only methods, not events */, number | undefined /* window ID */> { }
2829

@@ -334,19 +335,28 @@ export class ElectronMainService implements IElectronMainService {
334335
return isAdmin;
335336
}
336337

337-
async getTotalMem(): Promise<number> {
338-
return totalmem();
338+
async getOSStatistics(): Promise<IOSStatistics> {
339+
return {
340+
totalmem: totalmem(),
341+
freemem: freemem(),
342+
loadavg: loadavg()
343+
};
339344
}
340345

341-
async getOS(): Promise<IOSProperties> {
346+
async getOSProperties(): Promise<IOSProperties> {
342347
return {
343348
arch: arch(),
344349
platform: platform(),
345350
release: release(),
346-
type: type()
351+
type: type(),
352+
cpus: cpus()
347353
};
348354
}
349355

356+
async getOSVirtualMachineHint(): Promise<number> {
357+
return virtualMachineHint.value();
358+
}
359+
350360
//#endregion
351361

352362

src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
1919
import * as files from 'vs/workbench/contrib/files/common/files';
2020
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
2121
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
22-
import { didUseCachedData } from 'vs/workbench/services/timer/electron-browser/timerService';
22+
import { didUseCachedData } from 'vs/workbench/services/timer/electron-sandbox/timerService';
2323
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
2424
import { ITimerService } from 'vs/workbench/services/timer/browser/timerService';
2525

src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ import { ITunnelProvider, ITunnelService, RemoteTunnel } from 'vs/platform/remot
4545
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
4646
import { IManualSyncTask, IResourcePreview, ISyncResourceHandle, ISyncTask, IUserDataAutoSyncService, IUserDataSyncService, IUserDataSyncStore, IUserDataSyncStoreManagementService, SyncResource, SyncStatus, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync';
4747
import { IUserDataSyncAccount, IUserDataSyncAccountService } from 'vs/platform/userDataSync/common/userDataSyncAccount';
48-
import { AbstractTimerService, IStartupMetrics, ITimerService, Writeable } from 'vs/workbench/services/timer/browser/timerService';
4948
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
5049
import { ITaskProvider, ITaskService, ITaskSummary, ProblemMatcherRunOptions, Task, TaskFilter, TaskTerminateResponse, WorkspaceFolderTaskResult } from 'vs/workbench/contrib/tasks/common/taskService';
5150
import { Action } from 'vs/base/common/actions';
@@ -765,20 +764,6 @@ registerSingleton(IUserDataSyncStoreManagementService, SimpleIUserDataSyncStoreM
765764
//#endregion
766765

767766

768-
//#region Timer
769-
770-
class SimpleTimerService extends AbstractTimerService {
771-
protected _isInitialStartup(): boolean { return true; }
772-
protected _didUseCachedData(): boolean { return false; }
773-
protected async _getWindowCount(): Promise<number> { return 1; }
774-
protected async _extendStartupInfo(info: Writeable<IStartupMetrics>): Promise<void> { }
775-
}
776-
777-
registerSingleton(ITimerService, SimpleTimerService);
778-
779-
//#endregion
780-
781-
782767
//#region Task
783768

784769
class SimpleTaskService implements ITaskService {

src/vs/workbench/services/dialogs/electron-sandbox/dialogService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ class NativeDialogService implements IDialogService {
212212
}
213213

214214
const isSnap = process.platform === 'linux' && process.env.SNAP && process.env.SNAP_REVISION;
215-
const os = await this.electronService.getOS();
215+
const osProps = await this.electronService.getOSProperties();
216216

217217
const detailString = (useAgo: boolean): string => {
218218
return nls.localize('aboutDetail',
@@ -224,7 +224,7 @@ class NativeDialogService implements IDialogService {
224224
process.versions['chrome'],
225225
process.versions['node'],
226226
process.versions['v8'],
227-
`${os.type} ${os.arch} ${os.release}${isSnap ? ' snap' : ''}`
227+
`${osProps.type} ${osProps.arch} ${osProps.release}${isSnap ? ' snap' : ''}`
228228
);
229229
};
230230

src/vs/workbench/services/timer/electron-browser/timerService.ts renamed to src/vs/workbench/services/timer/electron-sandbox/timerService.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { virtualMachineHint } from 'vs/base/node/id';
7-
import * as os from 'os';
86
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
97
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
108
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
@@ -18,6 +16,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
1816
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
1917
import { IStartupMetrics, AbstractTimerService, Writeable } from 'vs/workbench/services/timer/browser/timerService';
2018
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
19+
import { context, process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
2120

2221
export class TimerService extends AbstractTimerService {
2322

@@ -49,12 +48,18 @@ export class TimerService extends AbstractTimerService {
4948

5049
protected async _extendStartupInfo(info: Writeable<IStartupMetrics>): Promise<void> {
5150
try {
52-
info.totalmem = os.totalmem();
53-
info.freemem = os.freemem();
54-
info.platform = os.platform();
55-
info.release = os.release();
56-
info.arch = os.arch();
57-
info.loadavg = os.loadavg();
51+
const [osProperties, osStatistics, virtualMachineHint] = await Promise.all([
52+
this._electronService.getOSProperties(),
53+
this._electronService.getOSStatistics(),
54+
this._electronService.getOSVirtualMachineHint()
55+
]);
56+
57+
info.totalmem = osStatistics.totalmem;
58+
info.freemem = osStatistics.freemem;
59+
info.platform = osProperties.platform;
60+
info.release = osProperties.release;
61+
info.arch = osProperties.arch;
62+
info.loadavg = osStatistics.loadavg;
5863

5964
const processMemoryInfo = await process.getProcessMemoryInfo();
6065
info.meminfo = {
@@ -63,9 +68,9 @@ export class TimerService extends AbstractTimerService {
6368
sharedBytes: processMemoryInfo.shared
6469
};
6570

66-
info.isVMLikelyhood = Math.round((virtualMachineHint.value() * 100));
71+
info.isVMLikelyhood = Math.round((virtualMachineHint * 100));
6772

68-
const rawCpus = os.cpus();
73+
const rawCpus = osProperties.cpus;
6974
if (rawCpus && rawCpus.length > 0) {
7075
info.cpus = { count: rawCpus.length, speed: rawCpus[0].speed, model: rawCpus[0].model };
7176
}
@@ -78,8 +83,12 @@ export class TimerService extends AbstractTimerService {
7883
//#region cached data logic
7984

8085
export function didUseCachedData(): boolean {
86+
// TODO@Ben TODO@Jo need a different way to figure out if cached data was used
87+
if (context.sandbox) {
88+
return true;
89+
}
8190
// We surely don't use cached data when we don't tell the loader to do so
82-
if (!Boolean((<any>global).require.getConfig().nodeCachedData)) {
91+
if (!Boolean((<any>window).require.getConfig().nodeCachedData)) {
8392
return false;
8493
}
8594
// There are loader events that signal if cached data was missing, rejected,

0 commit comments

Comments
 (0)