Include terminal replay in startup stats

Fixes #186068
This commit is contained in:
Daniel Imms
2023-06-24 06:26:59 -07:00
parent 6a9dbdffa3
commit aa91e246d8
7 changed files with 30 additions and 11 deletions
@@ -680,6 +680,7 @@ export interface ITerminalChildProcess {
onProcessData: Event<IProcessDataEvent | string>;
onProcessReady: Event<IProcessReadyEvent>;
onProcessReplayComplete?: Event<void>;
onDidChangeProperty: Event<IProcessProperty<any>>;
onProcessExit: Event<number | undefined>;
onRestoreCommands?: Event<ISerializedCommandDetectionCapability>;
@@ -536,6 +536,7 @@ export interface ITerminalInstance {
onDisposed: Event<ITerminalInstance>;
onProcessIdReady: Event<ITerminalInstance>;
onProcessReplayComplete: Event<void>;
onRequestExtHostProcess: Event<ITerminalInstance>;
onDimensionsChanged: Event<void>;
onMaximumDimensionsChanged: Event<void>;
@@ -288,6 +288,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
readonly onDisposed = this._onDisposed.event;
private readonly _onProcessIdReady = this._register(new Emitter<ITerminalInstance>());
readonly onProcessIdReady = this._onProcessIdReady.event;
private readonly _onProcessReplayComplete = this._register(new Emitter<void>());
readonly onProcessReplayComplete = this._onProcessReplayComplete.event;
private readonly _onTitleChanged = this._register(new Emitter<ITerminalInstance>());
readonly onTitleChanged = this._onTitleChanged.event;
private readonly _onIconChanged = this._register(new Emitter<{ instance: ITerminalInstance; userInitiated: boolean }>());
@@ -1395,6 +1397,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._initialDataEvents?.push(ev.data);
this._onData.fire(ev.data);
});
processManager.onProcessReplayComplete(() => this._onProcessReplayComplete.fire());
processManager.onEnvironmentVariableInfoChanged(e => this._onEnvironmentVariableInfoChanged(e));
processManager.onPtyDisconnect(() => {
if (this.xterm) {
@@ -108,6 +108,8 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
readonly onBeforeProcessData = this._onBeforeProcessData.event;
private readonly _onProcessData = this._register(new Emitter<IProcessDataEvent>());
readonly onProcessData = this._onProcessData.event;
private readonly _onProcessReplayComplete = this._register(new Emitter<void>());
readonly onProcessReplayComplete = this._onProcessReplayComplete.event;
private readonly _onDidChangeProperty = this._register(new Emitter<IProcessProperty<any>>());
readonly onDidChangeProperty = this._onDidChangeProperty.event;
private readonly _onEnvironmentVariableInfoChange = this._register(new Emitter<IEnvironmentVariableInfo>());
@@ -375,10 +377,11 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
this._onDidChangeProperty.fire({ type, value });
})
];
if (newProcess.onProcessReplayComplete) {
this._processListeners.push(newProcess.onProcessReplayComplete(() => this._onProcessReplayComplete.fire()));
}
if (newProcess.onRestoreCommands) {
this._processListeners.push(newProcess.onRestoreCommands(e => {
this._onRestoreCommands.fire(e);
}));
this._processListeners.push(newProcess.onRestoreCommands(e => this._onRestoreCommands.fire(e)));
}
setTimeout(() => {
if (this.processState === ProcessState.Launching) {
@@ -95,6 +95,8 @@ export class TerminalService implements ITerminalService {
return this._detachedXterms;
}
private _reconnectedTerminalGroups: Promise<ITerminalGroup[]> | undefined;
private _reconnectedTerminals: Map<string, ITerminalInstance[]> = new Map();
getReconnectedTerminals(reconnectionOwner: string): ITerminalInstance[] | undefined {
return this._reconnectedTerminals.get(reconnectionOwner);
@@ -292,6 +294,13 @@ export class TerminalService implements ITerminalService {
reconnectedPromise.then(async () => {
this._setConnected();
mark('code/terminal/didReconnect');
mark('code/terminal/willReplay');
const instances = await this._reconnectedTerminalGroups?.then(groups => groups.map(e => e.terminalInstances).flat()) ?? [];
await Promise.all(instances.map(e => new Promise<void>(r => Event.once(e.onProcessReplayComplete)(() => {
mark(`code/terminal/replay/${e.shellLaunchConfig.attachPersistentProcess?.id}`);
r();
}))));
mark('code/terminal/didReplay');
for (const backend of this._terminalInstanceService.getRegisteredBackends()) {
mark('code/terminal/willGetPerformanceMarks');
this._timerService.setPerformanceMarks(backend.remoteAuthority === undefined ? 'localPtyHost' : 'remotePtyHost', await backend.getPerformanceMarks());
@@ -450,7 +459,7 @@ export class TerminalService implements ITerminalService {
mark('code/terminal/didGetTerminalLayoutInfo');
if (layoutInfo && layoutInfo.tabs.length > 0) {
mark('code/terminal/willRecreateTerminalGroups');
this._restoredGroupCount = await this._recreateTerminalGroups(layoutInfo);
this._reconnectedTerminalGroups = this._recreateTerminalGroups(layoutInfo);
mark('code/terminal/didRecreateTerminalGroups');
}
// now that terminals have been restored,
@@ -458,17 +467,17 @@ export class TerminalService implements ITerminalService {
this._attachProcessLayoutListeners();
}
private async _recreateTerminalGroups(layoutInfo?: ITerminalsLayoutInfo): Promise<number> {
private _recreateTerminalGroups(layoutInfo?: ITerminalsLayoutInfo): Promise<ITerminalGroup[]> {
const groupPromises: Promise<ITerminalGroup | undefined>[] = [];
let reconnectCounter = 0;
let activeGroup: Promise<ITerminalGroup | undefined> | undefined;
if (layoutInfo) {
const tabPromises: Promise<ITerminalGroup | undefined>[] = [];
for (const tabLayout of layoutInfo.tabs) {
const terminalLayouts = tabLayout.terminals.filter(t => t.terminal && t.terminal.isOrphan);
if (terminalLayouts.length) {
reconnectCounter += terminalLayouts.length;
const promise = this._recreateTerminalGroup(tabLayout, terminalLayouts);
tabPromises.push(promise);
groupPromises.push(promise);
if (tabLayout.isActive) {
activeGroup = promise;
}
@@ -482,7 +491,7 @@ export class TerminalService implements ITerminalService {
activeGroup?.then(group => this._terminalGroupService.activeGroup = group);
}
}
return reconnectCounter;
return Promise.all(groupPromises).then(result => result.filter(e => !!e) as ITerminalGroup[]);
}
private async _recreateTerminalGroup(tabLayout: IRawTerminalTabLayoutInfo<IPtyHostAttachTarget | null>, terminalLayouts: IRawTerminalInstanceLayoutInfo<IPtyHostAttachTarget | null>[]): Promise<ITerminalGroup | undefined> {
@@ -502,7 +511,6 @@ export class TerminalService implements ITerminalService {
});
group = lastInstance.then(instance => this._terminalGroupService.getGroupForInstance(instance));
} else {
// TODO: Make parentInstance a promise?
// add split terminals to this group
lastInstance = this.createTerminal({
config: { attachPersistentProcess },
@@ -280,6 +280,7 @@ export interface ITerminalProcessManager extends IDisposable {
readonly onProcessReady: Event<IProcessReadyEvent>;
readonly onBeforeProcessData: Event<IBeforeProcessDataEvent>;
readonly onProcessData: Event<IProcessDataEvent>;
readonly onProcessReplayComplete: Event<void>;
readonly onEnvironmentVariableInfoChanged: Event<IEnvironmentVariableInfo>;
readonly onDidChangeProperty: Event<IProcessProperty<any>>;
readonly onProcessExit: Event<number | undefined>;
@@ -32,8 +32,8 @@ export class LocalPty extends Disposable implements ITerminalChildProcess {
private readonly _onProcessData = this._register(new Emitter<IProcessDataEvent | string>());
readonly onProcessData = this._onProcessData.event;
private readonly _onProcessReplay = this._register(new Emitter<IPtyHostProcessReplayEvent>());
readonly onProcessReplay = this._onProcessReplay.event;
private readonly _onProcessReplayComplete = this._register(new Emitter<void>());
readonly onProcessReplayComplete = this._onProcessReplayComplete.event;
private readonly _onProcessReady = this._register(new Emitter<IProcessReadyEvent>());
readonly onProcessReady = this._onProcessReady.event;
private readonly _onDidChangeProperty = this._register(new Emitter<IProcessProperty<any>>());
@@ -162,6 +162,8 @@ export class LocalPty extends Disposable implements ITerminalChildProcess {
// remove size override
this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: undefined });
this._onProcessReplayComplete.fire();
}
handleOrphanQuestion() {