Skip to content

Commit 95bb42d

Browse files
authored
Merge pull request microsoft#185243 from microsoft/tyriar/ptyhost_trace
Improve pty host diagnostics and introduce hidden simulated latency settings
2 parents 4144fb9 + 1fa84df commit 95bb42d

File tree

8 files changed

+178
-63
lines changed

8 files changed

+178
-63
lines changed

src/vs/code/electron-main/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ export class CodeApplication extends Disposable {
935935
graceTime: LocalReconnectConstants.GraceTime,
936936
shortGraceTime: LocalReconnectConstants.ShortGraceTime,
937937
scrollback: this.configurationService.getValue<number>(TerminalSettingId.PersistentSessionScrollback) ?? 100
938-
}, this.environmentMainService, this.lifecycleMainService, this.logService);
938+
}, this.configurationService, this.environmentMainService, this.lifecycleMainService, this.logService);
939939
const ptyHostService = new PtyHostService(
940940
ptyHostStarter,
941941
this.configurationService,

src/vs/platform/terminal/common/terminal.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,14 @@ export const enum TerminalSettingId {
107107
ShellIntegrationCommandHistory = 'terminal.integrated.shellIntegration.history',
108108
ShellIntegrationSuggestEnabled = 'terminal.integrated.shellIntegration.suggestEnabled',
109109
EnableImages = 'terminal.integrated.enableImages',
110-
SmoothScrolling = 'terminal.integrated.smoothScrolling'
110+
SmoothScrolling = 'terminal.integrated.smoothScrolling',
111+
112+
// Debug settings that are hidden from user
113+
114+
/** Simulated latency applied to all calls made to the pty host */
115+
DeveloperPtyHostLatency = 'terminal.integrated.developer.ptyHost.latency',
116+
/** Simulated startup delay of the pty host process */
117+
DeveloperPtyHostStartupDelay = 'terminal.integrated.developer.ptyHost.startupDelay',
111118
}
112119

113120
export const enum PosixShellType {

src/vs/platform/terminal/electron-main/electronPtyHostStarter.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { parsePtyHostDebugPort } from 'vs/platform/environment/node/environmentS
88
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
99
import { ILogService } from 'vs/platform/log/common/log';
1010
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
11-
import { IReconnectConstants } from 'vs/platform/terminal/common/terminal';
11+
import { IReconnectConstants, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
1212
import { IPtyHostConnection, IPtyHostStarter } from 'vs/platform/terminal/node/ptyHost';
1313
import { UtilityProcess } from 'vs/platform/utilityProcess/electron-main/utilityProcess';
1414
import { Client as MessagePortClient } from 'vs/base/parts/ipc/electron-main/ipc.mp';
@@ -17,6 +17,7 @@ import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain';
1717
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
1818
import { Emitter } from 'vs/base/common/event';
1919
import { deepClone } from 'vs/base/common/objects';
20+
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
2021

2122
export class ElectronPtyHostStarter implements IPtyHostStarter {
2223

@@ -29,6 +30,7 @@ export class ElectronPtyHostStarter implements IPtyHostStarter {
2930

3031
constructor(
3132
private readonly _reconnectConstants: IReconnectConstants,
33+
@IConfigurationService private readonly _configurationService: IConfigurationService,
3234
@IEnvironmentService private readonly _environmentService: INativeEnvironmentService,
3335
@ILifecycleMainService private readonly _lifecycleMainService: ILifecycleMainService,
3436
@ILogService private readonly _logService: ILogService
@@ -73,16 +75,25 @@ export class ElectronPtyHostStarter implements IPtyHostStarter {
7375
}
7476

7577
private _createPtyHostConfiguration(lastPtyId: number) {
76-
return {
78+
const config: { [key: string]: string } = {
7779
...deepClone(process.env),
7880
VSCODE_LAST_PTY_ID: String(lastPtyId),
7981
VSCODE_AMD_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain',
8082
VSCODE_PIPE_LOGGING: 'true',
8183
VSCODE_VERBOSE_LOGGING: 'true', // transmit console logs from server to client,
8284
VSCODE_RECONNECT_GRACE_TIME: String(this._reconnectConstants.graceTime),
8385
VSCODE_RECONNECT_SHORT_GRACE_TIME: String(this._reconnectConstants.shortGraceTime),
84-
VSCODE_RECONNECT_SCROLLBACK: String(this._reconnectConstants.scrollback)
86+
VSCODE_RECONNECT_SCROLLBACK: String(this._reconnectConstants.scrollback),
8587
};
88+
const simulatedLatency = this._configurationService.getValue(TerminalSettingId.DeveloperPtyHostLatency);
89+
if (simulatedLatency && typeof simulatedLatency === 'number') {
90+
config.VSCODE_LATENCY = String(simulatedLatency);
91+
}
92+
const startupDelay = this._configurationService.getValue(TerminalSettingId.DeveloperPtyHostStartupDelay);
93+
if (startupDelay && typeof startupDelay === 'number') {
94+
config.VSCODE_STARTUP_DELAY = String(startupDelay);
95+
}
96+
return config;
8697
}
8798

8899
private _onWindowConnection(e: IpcMainEvent, nonce: string) {

src/vs/platform/terminal/node/ptyHostMain.ts

Lines changed: 61 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -20,49 +20,73 @@ import { IReconnectConstants, TerminalIpcChannels } from 'vs/platform/terminal/c
2020
import { HeartbeatService } from 'vs/platform/terminal/node/heartbeatService';
2121
import { PtyService } from 'vs/platform/terminal/node/ptyService';
2222
import { isUtilityProcess } from 'vs/base/parts/sandbox/node/electronTypes';
23+
import { timeout } from 'vs/base/common/async';
2324

24-
const _isUtilityProcess = isUtilityProcess(process);
25+
startPtyHost();
2526

26-
let server: ChildProcessServer<string> | UtilityProcessServer;
27-
if (_isUtilityProcess) {
28-
server = new UtilityProcessServer();
29-
} else {
30-
server = new ChildProcessServer(TerminalIpcChannels.PtyHost);
31-
}
27+
async function startPtyHost() {
28+
// Parse environment variables
29+
const startupDelay = parseInt(process.env.VSCODE_STARTUP_DELAY ?? '0');
30+
const simulatedLatency = parseInt(process.env.VSCODE_LATENCY ?? '0');
31+
const reconnectConstants: IReconnectConstants = {
32+
graceTime: parseInt(process.env.VSCODE_RECONNECT_GRACE_TIME || '0'),
33+
shortGraceTime: parseInt(process.env.VSCODE_RECONNECT_SHORT_GRACE_TIME || '0'),
34+
scrollback: parseInt(process.env.VSCODE_RECONNECT_SCROLLBACK || '100')
35+
};
36+
const lastPtyId = parseInt(process.env.VSCODE_LAST_PTY_ID || '0');
3237

33-
const lastPtyId = parseInt(process.env.VSCODE_LAST_PTY_ID || '0');
34-
delete process.env.VSCODE_LAST_PTY_ID;
38+
// Sanitize environment
39+
delete process.env.VSCODE_RECONNECT_GRACE_TIME;
40+
delete process.env.VSCODE_RECONNECT_SHORT_GRACE_TIME;
41+
delete process.env.VSCODE_RECONNECT_SCROLLBACK;
42+
delete process.env.VSCODE_LATENCY;
43+
delete process.env.VSCODE_STARTUP_DELAY;
44+
delete process.env.VSCODE_LAST_PTY_ID;
3545

36-
const productService: IProductService = { _serviceBrand: undefined, ...product };
37-
const environmentService = new NativeEnvironmentService(parseArgs(process.argv, OPTIONS), productService);
46+
// Setup RPC
47+
const _isUtilityProcess = isUtilityProcess(process);
48+
let server: ChildProcessServer<string> | UtilityProcessServer;
49+
if (_isUtilityProcess) {
50+
server = new UtilityProcessServer();
51+
} else {
52+
server = new ChildProcessServer(TerminalIpcChannels.PtyHost);
53+
}
3854

39-
// Logging
40-
const loggerService = new LoggerService(getLogLevel(environmentService), environmentService.logsHome);
41-
server.registerChannel(TerminalIpcChannels.Logger, new LoggerChannel(loggerService, () => DefaultURITransformer));
42-
const logger = loggerService.createLogger('ptyhost', { name: localize('ptyHost', "Pty Host") });
43-
const logService = new LogService(logger, [new ConsoleLogger()]);
55+
// Services
56+
const productService: IProductService = { _serviceBrand: undefined, ...product };
57+
const environmentService = new NativeEnvironmentService(parseArgs(process.argv, OPTIONS), productService);
58+
const loggerService = new LoggerService(getLogLevel(environmentService), environmentService.logsHome);
59+
server.registerChannel(TerminalIpcChannels.Logger, new LoggerChannel(loggerService, () => DefaultURITransformer));
60+
const logger = loggerService.createLogger('ptyhost', { name: localize('ptyHost', "Pty Host") });
61+
const logService = new LogService(logger, [new ConsoleLogger()]);
4462

45-
const heartbeatService = new HeartbeatService();
46-
server.registerChannel(TerminalIpcChannels.Heartbeat, ProxyChannel.fromService(heartbeatService));
63+
// Log and apply developer config
64+
if (startupDelay) {
65+
logService.warn(`Pty Host startup is delayed ${startupDelay}ms`);
66+
await timeout(startupDelay);
67+
}
68+
if (simulatedLatency) {
69+
logService.warn(`Pty host is simulating ${simulatedLatency}ms latency`);
70+
}
4771

48-
const reconnectConstants: IReconnectConstants = {
49-
graceTime: parseInt(process.env.VSCODE_RECONNECT_GRACE_TIME || '0'),
50-
shortGraceTime: parseInt(process.env.VSCODE_RECONNECT_SHORT_GRACE_TIME || '0'),
51-
scrollback: parseInt(process.env.VSCODE_RECONNECT_SCROLLBACK || '100')
52-
};
53-
delete process.env.VSCODE_RECONNECT_GRACE_TIME;
54-
delete process.env.VSCODE_RECONNECT_SHORT_GRACE_TIME;
55-
delete process.env.VSCODE_RECONNECT_SCROLLBACK;
72+
// Heartbeat responsiveness tracking
73+
const heartbeatService = new HeartbeatService();
74+
server.registerChannel(TerminalIpcChannels.Heartbeat, ProxyChannel.fromService(heartbeatService));
5675

57-
const ptyService = new PtyService(lastPtyId, logService, productService, reconnectConstants);
58-
const ptyServiceChannel = ProxyChannel.fromService(ptyService);
59-
server.registerChannel(TerminalIpcChannels.PtyHost, ptyServiceChannel);
60-
if (_isUtilityProcess) {
61-
server.registerChannel(TerminalIpcChannels.PtyHostWindow, ptyServiceChannel);
62-
}
76+
// Init pty service
77+
const ptyService = new PtyService(lastPtyId, logService, productService, reconnectConstants, simulatedLatency);
78+
const ptyServiceChannel = ProxyChannel.fromService(ptyService);
79+
server.registerChannel(TerminalIpcChannels.PtyHost, ptyServiceChannel);
6380

64-
process.once('exit', () => {
65-
logService.dispose();
66-
heartbeatService.dispose();
67-
ptyService.dispose();
68-
});
81+
// Register a channel for direct communication via Message Port
82+
if (_isUtilityProcess) {
83+
server.registerChannel(TerminalIpcChannels.PtyHostWindow, ptyServiceChannel);
84+
}
85+
86+
// Clean up
87+
process.once('exit', () => {
88+
logService.dispose();
89+
heartbeatService.dispose();
90+
ptyService.dispose();
91+
});
92+
}

src/vs/platform/terminal/node/ptyHostService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ export class PtyHostService extends Disposable implements IPtyService {
149149
// Setup heartbeat service and trigger a heartbeat immediately to reset the timeouts
150150
const heartbeatService = ProxyChannel.toService<IHeartbeatService>(client.getChannel(TerminalIpcChannels.Heartbeat));
151151
heartbeatService.onBeat(() => this._handleHeartbeat());
152+
// TODO: Starting the heartbeat tracking now causes problems
152153
this._handleHeartbeat();
153154

154155
// Handle exit

0 commit comments

Comments
 (0)