Skip to content

Commit 63e1f7e

Browse files
authored
diag - improve process titles (microsoft#175632)
* diag - improve process titles * do not use correlation id
1 parent 33b821b commit 63e1f7e

File tree

8 files changed

+82
-58
lines changed

8 files changed

+82
-58
lines changed

src/vs/base/node/ps.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,7 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
4848

4949
function findName(cmd: string): string {
5050

51-
const SHARED_PROCESS_HINT = /--vscode-window-kind=shared-process/i; // TODO@bpasero remove me
52-
const ISSUE_REPORTER_HINT = /--vscode-window-kind=issue-reporter/i;
53-
const PROCESS_EXPLORER_HINT = /--vscode-window-kind=process-explorer/i;
5451
const UTILITY_NETWORK_HINT = /--utility-sub-type=network/i;
55-
const UTILITY_EXTENSION_HOST_HINT = /--vscode-utility-kind=extensionHost/i;
56-
const UTILITY_FILE_WATCHER_HOST_HINT = /--vscode-utility-kind=fileWatcher/i;
57-
const UTILITY_SHARED_PROCESS_HINT = /--vscode-utility-kind=shared-process/i;
5852
const NODEJS_PROCESS_HINT = /--ms-enable-electron-run-as-node/i;
5953
const WINDOWS_CRASH_REPORTER = /--crashes-directory/i;
6054
const WINDOWS_PTY = /\\pipe\\winpty-control/i;
@@ -80,36 +74,12 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
8074
let matches = TYPE.exec(cmd);
8175
if (matches && matches.length === 2) {
8276
if (matches[1] === 'renderer') {
83-
if (SHARED_PROCESS_HINT.exec(cmd)) {
84-
return 'shared-process';
85-
}
86-
87-
if (ISSUE_REPORTER_HINT.exec(cmd)) {
88-
return 'issue-reporter';
89-
}
90-
91-
if (PROCESS_EXPLORER_HINT.exec(cmd)) {
92-
return 'process-explorer';
93-
}
94-
9577
return `window`;
9678
} else if (matches[1] === 'utility') {
9779
if (UTILITY_NETWORK_HINT.exec(cmd)) {
9880
return 'utility-network-service';
9981
}
10082

101-
if (UTILITY_EXTENSION_HOST_HINT.exec(cmd)) {
102-
return 'extension-host';
103-
}
104-
105-
if (UTILITY_FILE_WATCHER_HOST_HINT.exec(cmd)) {
106-
return 'file-watcher';
107-
}
108-
109-
if (UTILITY_SHARED_PROCESS_HINT.exec(cmd)) {
110-
return 'shared-process';
111-
}
112-
11383
return 'utility-process';
11484
} else if (matches[1] === 'extensionHost') {
11585
return 'extension-host'; // normalize remote extension host type

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

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ class ErrorRenderer implements ITreeRenderer<IRemoteDiagnosticError, void, IProc
163163

164164

165165
class ProcessRenderer implements ITreeRenderer<ProcessItem, void, IProcessItemTemplateData> {
166-
constructor(private platform: string, private totalMem: number, private mapPidToWindowTitle: Map<number, string>) { }
166+
constructor(private platform: string, private totalMem: number, private mapPidToName: Map<number, string>) { }
167167

168168
templateId: string = 'process';
169169
renderTemplate(container: HTMLElement): IProcessItemTemplateData {
@@ -179,12 +179,12 @@ class ProcessRenderer implements ITreeRenderer<ProcessItem, void, IProcessItemTe
179179
renderElement(node: ITreeNode<ProcessItem, void>, index: number, templateData: IProcessItemTemplateData, height: number | undefined): void {
180180
const { element } = node;
181181

182+
const pid = element.pid.toFixed(0);
183+
182184
let name = element.name;
183-
if (name === 'window') {
184-
const windowTitle = this.mapPidToWindowTitle.get(element.pid);
185-
name = windowTitle !== undefined ? `${name} (${this.mapPidToWindowTitle.get(element.pid)})` : name;
185+
if (this.mapPidToName.has(element.pid)) {
186+
name = this.mapPidToName.get(element.pid)!;
186187
}
187-
const pid = element.pid.toFixed(0);
188188

189189
templateData.name.textContent = name;
190190
templateData.name.title = element.cmd;
@@ -230,7 +230,7 @@ function isProcessItem(item: any): item is ProcessItem {
230230
class ProcessExplorer {
231231
private lastRequestTime: number;
232232

233-
private mapPidToWindowTitle = new Map<number, string>();
233+
private mapPidToName = new Map<number, string>();
234234

235235
private nativeHostService: INativeHostService;
236236

@@ -243,10 +243,12 @@ class ProcessExplorer {
243243
this.applyStyles(data.styles);
244244
this.setEventHandlers(data);
245245

246-
// Map window process pids to titles, annotate process names with this when rendering to distinguish between them
247-
ipcRenderer.on('vscode:windowsInfoResponse', (event: unknown, windows: any[]) => {
248-
this.mapPidToWindowTitle = new Map<number, string>();
249-
windows.forEach(window => this.mapPidToWindowTitle.set(window.pid, window.title));
246+
ipcRenderer.on('vscode:pidToNameResponse', (event: unknown, pidToNames: [number, string][]) => {
247+
this.mapPidToName = new Map<number, string>();
248+
249+
for (const [pid, name] of pidToNames) {
250+
this.mapPidToName.set(pid, name);
251+
}
250252
});
251253

252254
ipcRenderer.on('vscode:listProcessesResponse', async (event: unknown, processRoots: MachineProcessInformation[]) => {
@@ -267,7 +269,7 @@ class ProcessExplorer {
267269
});
268270

269271
this.lastRequestTime = Date.now();
270-
ipcRenderer.send('vscode:windowsInfoRequest');
272+
ipcRenderer.send('vscode:pidToNameRequest');
271273
ipcRenderer.send('vscode:listProcesses');
272274
}
273275

@@ -304,7 +306,7 @@ class ProcessExplorer {
304306
const { totalmem } = await this.nativeHostService.getOSStatistics();
305307

306308
const renderers = [
307-
new ProcessRenderer(this.data.platform, totalmem, this.mapPidToWindowTitle),
309+
new ProcessRenderer(this.data.platform, totalmem, this.mapPidToName),
308310
new ProcessHeaderTreeRenderer(),
309311
new MachineRenderer(),
310312
new ErrorRenderer()
@@ -555,7 +557,7 @@ class ProcessExplorer {
555557

556558
// Wait at least a second between requests.
557559
if (waited > 1000) {
558-
ipcRenderer.send('vscode:windowsInfoRequest');
560+
ipcRenderer.send('vscode:pidToNameRequest');
559561
ipcRenderer.send('vscode:listProcesses');
560562
} else {
561563
this.requestProcessList(waited);

src/vs/platform/diagnostics/common/diagnostics.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,16 +124,23 @@ export class NullDiagnosticsService implements IDiagnosticsService {
124124
}
125125

126126
export interface IWindowDiagnostics {
127+
readonly id: number;
127128
readonly pid: number;
128129
readonly title: string;
129130
readonly folderURIs: UriComponents[];
130131
readonly remoteAuthority?: string;
131132
}
132133

134+
export interface IProcessDiagnostics {
135+
readonly pid: number;
136+
readonly name: string;
137+
}
138+
133139
export interface IMainProcessDiagnostics {
134140
readonly mainPID: number;
135141
readonly mainArguments: string[]; // All arguments after argv[0], the exec path
136142
readonly windows: IWindowDiagnostics[];
143+
readonly pidToNames: IProcessDiagnostics[];
137144
readonly screenReader: boolean;
138145
readonly gpuFeatureStatus: any;
139146
}

src/vs/platform/diagnostics/electron-main/diagnosticsMainService.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import { app, BrowserWindow, Event as IpcEvent } from 'electron';
77
import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain';
88
import { CancellationToken } from 'vs/base/common/cancellation';
99
import { URI } from 'vs/base/common/uri';
10-
import { IDiagnosticInfo, IDiagnosticInfoOptions, IMainProcessDiagnostics, IRemoteDiagnosticError, IRemoteDiagnosticInfo, IWindowDiagnostics } from 'vs/platform/diagnostics/common/diagnostics';
10+
import { IDiagnosticInfo, IDiagnosticInfoOptions, IMainProcessDiagnostics, IProcessDiagnostics, IRemoteDiagnosticError, IRemoteDiagnosticInfo, IWindowDiagnostics } from 'vs/platform/diagnostics/common/diagnostics';
1111
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
1212
import { ICodeWindow } from 'vs/platform/window/electron-main/window';
1313
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
1414
import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
1515
import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService';
1616
import { assertIsDefined } from 'vs/base/common/types';
1717
import { ILogService } from 'vs/platform/log/common/log';
18+
import { UtilityProcess } from 'vs/platform/utilityProcess/electron-main/utilityProcess';
1819

1920
export const ID = 'diagnosticsMainService';
2021
export const IDiagnosticsMainService = createDecorator<IDiagnosticsMainService>(ID);
@@ -88,10 +89,16 @@ export class DiagnosticsMainService implements IDiagnosticsMainService {
8889
}
8990
}
9091

92+
const pidToNames: IProcessDiagnostics[] = [];
93+
for (const { pid, name } of UtilityProcess.getAll()) {
94+
pidToNames.push({ pid, name });
95+
}
96+
9197
return {
9298
mainPID: process.pid,
9399
mainArguments: process.argv.slice(1),
94100
windows,
101+
pidToNames,
95102
screenReader: !!app.accessibilitySupportEnabled,
96103
gpuFeatureStatus: app.getGPUFeatureStatus()
97104
};
@@ -106,6 +113,7 @@ export class DiagnosticsMainService implements IDiagnosticsMainService {
106113

107114
private browserWindowToInfo(window: BrowserWindow, folderURIs: URI[] = [], remoteAuthority?: string): IWindowDiagnostics {
108115
return {
116+
id: window.id,
109117
pid: window.webContents.getOSProcessId(),
110118
title: window.getTitle(),
111119
folderURIs,

src/vs/platform/diagnostics/node/diagnosticsService.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -456,32 +456,33 @@ export class DiagnosticsService implements IDiagnosticsService {
456456
}
457457

458458
private formatProcessList(info: IMainProcessDiagnostics, rootProcess: ProcessItem): string {
459-
const mapPidToWindowTitle = new Map<number, string>();
460-
info.windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
459+
const mapProcessToName = new Map<number, string>();
460+
info.windows.forEach(window => mapProcessToName.set(window.pid, `window [${window.id}] (${window.title})`));
461+
info.pidToNames.forEach(({ pid, name }) => mapProcessToName.set(pid, name));
461462

462463
const output: string[] = [];
463464

464465
output.push('CPU %\tMem MB\t PID\tProcess');
465466

466467
if (rootProcess) {
467-
this.formatProcessItem(info.mainPID, mapPidToWindowTitle, output, rootProcess, 0);
468+
this.formatProcessItem(info.mainPID, mapProcessToName, output, rootProcess, 0);
468469
}
469470

470471
return output.join('\n');
471472
}
472473

473-
private formatProcessItem(mainPid: number, mapPidToWindowTitle: Map<number, string>, output: string[], item: ProcessItem, indent: number): void {
474+
private formatProcessItem(mainPid: number, mapProcessToName: Map<number, string>, output: string[], item: ProcessItem, indent: number): void {
474475
const isRoot = (indent === 0);
475476

476477
// Format name with indent
477478
let name: string;
478479
if (isRoot) {
479480
name = item.pid === mainPid ? `${this.productService.applicationName} main` : 'remote agent';
480481
} else {
481-
name = `${' '.repeat(indent)} ${item.name}`;
482-
483-
if (item.name === 'window') {
484-
name = `${name} (${mapPidToWindowTitle.get(item.pid)})`;
482+
if (mapProcessToName.has(item.pid)) {
483+
name = mapProcessToName.get(item.pid)!;
484+
} else {
485+
name = `${' '.repeat(indent)} ${item.name}`;
485486
}
486487
}
487488

@@ -490,7 +491,7 @@ export class DiagnosticsService implements IDiagnosticsService {
490491

491492
// Recurse into children if any
492493
if (Array.isArray(item.children)) {
493-
item.children.forEach(child => this.formatProcessItem(mainPid, mapPidToWindowTitle, output, child, indent + 1));
494+
item.children.forEach(child => this.formatProcessItem(mainPid, mapProcessToName, output, child, indent + 1));
494495
}
495496
}
496497

src/vs/platform/issue/electron-main/issueMainService.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { IWindowState } from 'vs/platform/window/electron-main/window';
2727
import { randomPath } from 'vs/base/common/extpath';
2828
import { withNullAsUndefined } from 'vs/base/common/types';
2929
import { IStateService } from 'vs/platform/state/node/state';
30+
import { UtilityProcess } from 'vs/platform/utilityProcess/electron-main/utilityProcess';
3031

3132
export const IIssueMainService = createDecorator<IIssueMainService>('issueMainService');
3233
const processExplorerWindowState = 'issue.processExplorerWindowState';
@@ -178,9 +179,19 @@ export class IssueMainService implements IIssueMainService {
178179
this.processExplorerWindow?.close();
179180
});
180181

181-
validatedIpcMain.on('vscode:windowsInfoRequest', async event => {
182+
validatedIpcMain.on('vscode:pidToNameRequest', async event => {
182183
const mainProcessInfo = await this.diagnosticsMainService.getMainDiagnostics();
183-
this.safeSend(event, 'vscode:windowsInfoResponse', mainProcessInfo.windows);
184+
185+
const pidToNames: [number, string][] = [];
186+
for (const window of mainProcessInfo.windows) {
187+
pidToNames.push([window.pid, `window [${window.id}] (${window.title})`]);
188+
}
189+
190+
for (const { pid, name } of UtilityProcess.getAll()) {
191+
pidToNames.push([pid, name]);
192+
}
193+
194+
this.safeSend(event, 'vscode:pidToNameResponse', pidToNames);
184195
});
185196
}
186197

@@ -343,7 +354,7 @@ export class IssueMainService implements IIssueMainService {
343354
backgroundColor: options.backgroundColor || IssueMainService.DEFAULT_BACKGROUND_COLOR,
344355
webPreferences: {
345356
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js').fsPath,
346-
additionalArguments: [`--vscode-window-config=${ipcObjectUrl.resource.toString()}`, `--vscode-window-kind=${windowKind}`],
357+
additionalArguments: [`--vscode-window-config=${ipcObjectUrl.resource.toString()}`],
347358
v8CacheOptions: this.environmentMainService.useCodeCache ? 'bypassHeatCheck' : 'none',
348359
enableWebSQL: false,
349360
spellcheck: false,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,10 @@ export class SharedProcess extends Disposable implements ISharedProcess {
306306
this.window = new BrowserWindow({
307307
show: false,
308308
backgroundColor: this.themeMainService.getBackgroundColor(),
309+
title: 'shared-process',
309310
webPreferences: {
310311
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js').fsPath,
311-
additionalArguments: [`--vscode-window-config=${configObjectUrl.resource.toString()}`, '--vscode-window-kind=shared-process'],
312+
additionalArguments: [`--vscode-window-config=${configObjectUrl.resource.toString()}`],
312313
v8CacheOptions: this.environmentMainService.useCodeCache ? 'bypassHeatCheck' : 'none',
313314
nodeIntegration: true,
314315
nodeIntegrationInWorker: true,

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ export interface IWindowUtilityProcessConfiguration extends IUtilityProcessConfi
8888
readonly windowLifecycleBound?: boolean;
8989
}
9090

91+
function isWindowUtilityProcessConfiguration(config: IUtilityProcessConfiguration): config is IWindowUtilityProcessConfiguration {
92+
const candidate = config as IWindowUtilityProcessConfiguration;
93+
94+
return typeof candidate.responseWindowId === 'number';
95+
}
96+
9197
interface IUtilityProcessExitBaseEvent {
9298

9399
/**
@@ -118,10 +124,20 @@ export interface IUtilityProcessCrashEvent extends IUtilityProcessExitBaseEvent
118124
readonly reason: 'clean-exit' | 'abnormal-exit' | 'killed' | 'crashed' | 'oom' | 'launch-failed' | 'integrity-failure';
119125
}
120126

127+
export interface IUtilityProcessInfo {
128+
readonly pid: number;
129+
readonly name: string;
130+
}
131+
121132
export class UtilityProcess extends Disposable {
122133

123134
private static ID_COUNTER = 0;
124135

136+
private static readonly all = new Map<number, IUtilityProcessInfo>();
137+
static getAll(): IUtilityProcessInfo[] {
138+
return Array.from(UtilityProcess.all.values());
139+
}
140+
125141
private readonly id = String(++UtilityProcess.ID_COUNTER);
126142

127143
private readonly _onStdout = this._register(new Emitter<string>());
@@ -206,7 +222,7 @@ export class UtilityProcess extends Disposable {
206222
const serviceName = `${this.configuration.type}-${this.id}`;
207223
const modulePath = FileAccess.asFileUri('bootstrap-fork.js').fsPath;
208224
const args = this.configuration.args ?? [];
209-
const execArgv = this.configuration.execArgv ?? []; // TODO@deepak1556 this should be [...this.configuration.execArgv ?? [], `--vscode-utility-kind=${this.configuration.type}`] but is causing https://github.com/microsoft/vscode/issues/154549
225+
const execArgv = this.configuration.execArgv ?? [];
210226
const allowLoadingUnsignedLibraries = this.configuration.allowLoadingUnsignedLibraries;
211227
const stdio = 'pipe';
212228
const env = this.createEnv(configuration, isWindowSandboxed);
@@ -273,6 +289,10 @@ export class UtilityProcess extends Disposable {
273289
this._register(Event.fromNodeEventEmitter<void>(process, 'spawn')(() => {
274290
this.processPid = process.pid;
275291

292+
if (typeof process.pid === 'number') {
293+
UtilityProcess.all.set(process.pid, { pid: process.pid, name: isWindowUtilityProcessConfiguration(configuration) ? `${configuration.type} [${configuration.responseWindowId}]` : configuration.type });
294+
}
295+
276296
this.log('successfully created', Severity.Info);
277297
}));
278298

@@ -387,6 +407,10 @@ export class UtilityProcess extends Disposable {
387407
}
388408

389409
private onDidExitOrCrashOrKill(): void {
410+
if (typeof this.processPid === 'number') {
411+
UtilityProcess.all.delete(this.processPid);
412+
}
413+
390414
this.process = undefined;
391415
}
392416

0 commit comments

Comments
 (0)