mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
simplify extension host profiling
This commit is contained in:
parent
efd5704d8d
commit
4baa90bfde
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IExtensionService, IResponsiveStateChangeEvent, ICpuProfilerTarget, IExtensionHostProfile, ProfileSession } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionService, IResponsiveStateChangeEvent, IExtensionHostProfile, ProfileSession } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
@ -24,8 +24,8 @@ import { createSlowExtensionAction } from 'vs/workbench/contrib/extensions/elect
|
|||
|
||||
export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private readonly _session = new Map<ICpuProfilerTarget, CancellationTokenSource>();
|
||||
private readonly _blame = new Set<string>();
|
||||
private _session: CancellationTokenSource | undefined;
|
||||
|
||||
constructor(
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
|
@ -41,26 +41,27 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont
|
|||
}
|
||||
|
||||
private async _onDidChangeResponsiveChange(event: IResponsiveStateChangeEvent): Promise<void> {
|
||||
const { target } = event;
|
||||
const target = this._extensionService;
|
||||
|
||||
if (!target.canProfileExtensionHost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.isResponsive && this._session.has(target)) {
|
||||
if (event.isResponsive && this._session) {
|
||||
// stop profiling when responsive again
|
||||
this._session.get(target)!.cancel();
|
||||
this._session.cancel();
|
||||
|
||||
} else if (!event.isResponsive && !this._session.has(target)) {
|
||||
} else if (!event.isResponsive && !this._session) {
|
||||
// start profiling if not yet profiling
|
||||
const token = new CancellationTokenSource();
|
||||
this._session.set(target, token);
|
||||
const cts = new CancellationTokenSource();
|
||||
this._session = cts;
|
||||
|
||||
|
||||
let session: ProfileSession;
|
||||
try {
|
||||
session = await target.startExtensionHostProfile();
|
||||
} catch (err) {
|
||||
this._session.delete(target);
|
||||
this._session = undefined;
|
||||
// fail silent as this is often
|
||||
// caused by another party being
|
||||
// connected already
|
||||
|
@ -69,7 +70,7 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont
|
|||
|
||||
// wait 5 seconds or until responsive again
|
||||
await new Promise(resolve => {
|
||||
token.token.onCancellationRequested(resolve);
|
||||
cts.token.onCancellationRequested(resolve);
|
||||
setTimeout(resolve, 5e3);
|
||||
});
|
||||
|
||||
|
@ -79,7 +80,7 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont
|
|||
} catch (err) {
|
||||
onUnexpectedError(err);
|
||||
} finally {
|
||||
this._session.delete(target);
|
||||
this._session = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,11 +116,10 @@ export interface IWillActivateEvent {
|
|||
}
|
||||
|
||||
export interface IResponsiveStateChangeEvent {
|
||||
target: ICpuProfilerTarget;
|
||||
isResponsive: boolean;
|
||||
}
|
||||
|
||||
export interface IExtensionService extends ICpuProfilerTarget {
|
||||
export interface IExtensionService {
|
||||
_serviceBrand: any;
|
||||
|
||||
/**
|
||||
|
@ -204,6 +203,16 @@ export interface IExtensionService extends ICpuProfilerTarget {
|
|||
*/
|
||||
getInspectPort(): number;
|
||||
|
||||
/**
|
||||
* Can the extension host be profiled.
|
||||
*/
|
||||
canProfileExtensionHost(): boolean;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
startExtensionHostProfile(): Promise<ProfileSession>;
|
||||
|
||||
/**
|
||||
* Restarts the extension host.
|
||||
*/
|
||||
|
@ -227,19 +236,6 @@ export interface IExtensionService extends ICpuProfilerTarget {
|
|||
_onExtensionHostExit(code: number): void;
|
||||
}
|
||||
|
||||
export interface ICpuProfilerTarget {
|
||||
|
||||
/**
|
||||
* Check if the extension host can be profiled.
|
||||
*/
|
||||
canProfileExtensionHost(): boolean;
|
||||
|
||||
/**
|
||||
* Begin an extension host process profile session.
|
||||
*/
|
||||
startExtensionHostProfile(): Promise<ProfileSession>;
|
||||
}
|
||||
|
||||
export interface ProfileSession {
|
||||
stop(): Promise<IExtensionHostProfile>;
|
||||
}
|
||||
|
|
|
@ -12,9 +12,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
|
|||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ExtHostCustomersRegistry } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostExtensionServiceShape, IExtHostContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ProfileSession } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/electron-browser/extensionHost';
|
||||
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
|
||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
|
||||
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
|
@ -169,10 +167,6 @@ export class ExtensionHostProcessManager extends Disposable {
|
|||
return ExtensionHostProcessManager._convert(SIZE, sw.elapsed());
|
||||
}
|
||||
|
||||
public canProfileExtensionHost(): boolean {
|
||||
return this._extensionHostProcessWorker && Boolean(this._extensionHostProcessWorker.getInspectPort());
|
||||
}
|
||||
|
||||
private _createExtensionHostCustomers(protocol: IMessagePassingProtocol): ExtHostExtensionServiceShape {
|
||||
|
||||
let logger: IRPCProtocolLogger | null = null;
|
||||
|
@ -236,16 +230,6 @@ export class ExtensionHostProcessManager extends Disposable {
|
|||
});
|
||||
}
|
||||
|
||||
public startExtensionHostProfile(): Promise<ProfileSession> {
|
||||
if (this._extensionHostProcessWorker) {
|
||||
let port = this._extensionHostProcessWorker.getInspectPort();
|
||||
if (port) {
|
||||
return this._instantiationService.createInstance(ExtensionHostProfiler, port).start();
|
||||
}
|
||||
}
|
||||
throw new Error('Extension host not running or no inspect port available');
|
||||
}
|
||||
|
||||
public getInspectPort(): number {
|
||||
if (this._extensionHostProcessWorker) {
|
||||
let port = this._extensionHostProcessWorker.getInspectPort();
|
||||
|
@ -256,6 +240,10 @@ export class ExtensionHostProcessManager extends Disposable {
|
|||
return 0;
|
||||
}
|
||||
|
||||
public canProfileExtensionHost(): boolean {
|
||||
return this._extensionHostProcessWorker && Boolean(this._extensionHostProcessWorker.getInspectPort());
|
||||
}
|
||||
|
||||
public async resolveAuthority(remoteAuthority: string): Promise<ResolvedAuthority> {
|
||||
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
||||
if (authorityPlusIndex === -1) {
|
||||
|
|
|
@ -35,6 +35,7 @@ import { Schemas } from 'vs/base/common/network';
|
|||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
|
||||
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
|
||||
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
|
||||
|
@ -442,7 +443,7 @@ export class ExtensionService extends Disposable implements IExtensionService {
|
|||
const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, autoStart, extensions, this._extensionHostLogsLocation);
|
||||
const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, extHostProcessWorker, null, initialActivationEvents);
|
||||
extHostProcessManager.onDidCrash(([code, signal]) => this._onExtensionHostCrashed(code, signal));
|
||||
extHostProcessManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ target: extHostProcessManager, isResponsive: responsiveState === ResponsiveState.Responsive }); });
|
||||
extHostProcessManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); });
|
||||
this._extensionHostProcessManagers.push(extHostProcessManager);
|
||||
}
|
||||
|
||||
|
@ -583,7 +584,10 @@ export class ExtensionService extends Disposable implements IExtensionService {
|
|||
for (let i = 0, len = this._extensionHostProcessManagers.length; i < len; i++) {
|
||||
const extHostProcessManager = this._extensionHostProcessManagers[i];
|
||||
if (extHostProcessManager.canProfileExtensionHost()) {
|
||||
return extHostProcessManager.startExtensionHostProfile();
|
||||
const port = extHostProcessManager.getInspectPort();
|
||||
if (port) {
|
||||
return this._instantiationService.createInstance(ExtensionHostProfiler, port).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error('Extension host not running or no inspect port available');
|
||||
|
|
Loading…
Reference in a new issue