Skip to content

Commit

Permalink
extensions: allow opening extension host CPU profile in the built-in …
Browse files Browse the repository at this point in the history
…profile viewer (#227834)

Fixes #227168

Also moves some old Action registrations to Action2 and uses proper
menu registration for context menu display.
  • Loading branch information
connor4312 committed Sep 6, 2024
1 parent 03f6dab commit 35676d1
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 230 deletions.
1 change: 1 addition & 0 deletions src/vs/platform/actions/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export class MenuId {
static readonly ExplorerContext = new MenuId('ExplorerContext');
static readonly ExplorerContextShare = new MenuId('ExplorerContextShare');
static readonly ExtensionContext = new MenuId('ExtensionContext');
static readonly ExtensionEditorContextMenu = new MenuId('ExtensionEditorContextMenu');
static readonly GlobalActivity = new MenuId('GlobalActivity');
static readonly CommandCenter = new MenuId('CommandCenter');
static readonly CommandCenterCenter = new MenuId('CommandCenterCenter');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ import { Action, IAction, Separator } from '../../../../base/common/actions.js';
import { isNonEmptyArray } from '../../../../base/common/arrays.js';
import { RunOnceScheduler } from '../../../../base/common/async.js';
import { fromNow } from '../../../../base/common/date.js';
import { memoize } from '../../../../base/common/decorators.js';
import { IDisposable, dispose } from '../../../../base/common/lifecycle.js';
import { Schemas } from '../../../../base/common/network.js';
import './media/runtimeExtensionsEditor.css';
import * as nls from '../../../../nls.js';
import { Categories } from '../../../../platform/action/common/actionCommonCategories.js';
import { Action2, MenuId } from '../../../../platform/actions/common/actions.js';
import { createAndFillInContextMenuActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';
import { Action2, IMenuService, MenuId } from '../../../../platform/actions/common/actions.js';
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
Expand All @@ -35,16 +34,17 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet
import { editorBackground } from '../../../../platform/theme/common/colorRegistry.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
import { EditorPane } from '../../../browser/parts/editor/editorPane.js';
import { errorIcon, warningIcon } from './extensionsIcons.js';
import { IExtension, IExtensionsWorkbenchService } from '../common/extensions.js';
import { RuntimeExtensionsInput } from '../common/runtimeExtensionsInput.js';
import { IEditorGroup } from '../../../services/editor/common/editorGroupsService.js';
import { IEditorService } from '../../../services/editor/common/editorService.js';
import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.js';
import { Extensions, IExtensionFeaturesManagementService, IExtensionFeaturesRegistry } from '../../../services/extensionManagement/common/extensionFeatures.js';
import { DefaultIconPath, EnablementState } from '../../../services/extensionManagement/common/extensionManagement.js';
import { LocalWebWorkerRunningLocation } from '../../../services/extensions/common/extensionRunningLocation.js';
import { IExtensionHostProfile, IExtensionService, IExtensionsStatus } from '../../../services/extensions/common/extensions.js';
import { IExtension, IExtensionsWorkbenchService } from '../common/extensions.js';
import { RuntimeExtensionsInput } from '../common/runtimeExtensionsInput.js';
import { errorIcon, warningIcon } from './extensionsIcons.js';
import './media/runtimeExtensionsEditor.css';

interface IExtensionProfileInformation {
/**
Expand Down Expand Up @@ -81,7 +81,7 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
group: IEditorGroup,
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
@IContextKeyService contextKeyService: IContextKeyService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IExtensionsWorkbenchService private readonly _extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionService private readonly _extensionService: IExtensionService,
@INotificationService private readonly _notificationService: INotificationService,
Expand All @@ -93,6 +93,7 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
@IClipboardService private readonly _clipboardService: IClipboardService,
@IExtensionFeaturesManagementService private readonly _extensionFeaturesManagementService: IExtensionFeaturesManagementService,
@IHoverService private readonly _hoverService: IHoverService,
@IMenuService private readonly _menuService: IMenuService,
) {
super(AbstractRuntimeExtensionsEditor.ID, group, telemetryService, themeService, storageService);

Expand Down Expand Up @@ -496,14 +497,9 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
}
actions.push(new Separator());

const profileAction = this._createProfileAction();
if (profileAction) {
actions.push(profileAction);
}
const saveExtensionHostProfileAction = this.saveExtensionHostProfileAction;
if (saveExtensionHostProfileAction) {
actions.push(saveExtensionHostProfileAction);
}

const menuActions = this._menuService.getMenuActions(MenuId.ExtensionEditorContextMenu, this.contextKeyService);
createAndFillInContextMenuActions(menuActions, { primary: [], secondary: actions });

this._contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
Expand All @@ -512,11 +508,6 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
});
}

@memoize
private get saveExtensionHostProfileAction(): IAction | null {
return this._createSaveExtensionHostProfileAction();
}

public layout(dimension: Dimension): void {
this._list?.layout(dimension.height);
}
Expand All @@ -525,8 +516,6 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
protected abstract _getUnresponsiveProfile(extensionId: ExtensionIdentifier): IExtensionHostProfile | undefined;
protected abstract _createSlowExtensionAction(element: IRuntimeExtension): Action | null;
protected abstract _createReportExtensionIssueAction(element: IRuntimeExtension): Action | null;
protected abstract _createSaveExtensionHostProfileAction(): Action | null;
protected abstract _createProfileAction(): Action | null;
}

export class ShowRuntimeExtensionsAction extends Action2 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,4 @@ export class RuntimeExtensionsEditor extends AbstractRuntimeExtensionsEditor {
}
return null;
}

protected _createSaveExtensionHostProfileAction(): Action | null {
return null;
}

protected _createProfileAction(): Action | null {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,73 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Action } from '../../../../base/common/actions.js';
import { Codicon } from '../../../../base/common/codicons.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import { randomPort } from '../../../../base/common/ports.js';
import * as nls from '../../../../nls.js';
import { Categories } from '../../../../platform/action/common/actionCommonCategories.js';
import { Action2, MenuId } from '../../../../platform/actions/common/actions.js';
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
import { INativeHostService } from '../../../../platform/native/common/native.js';
import { IProductService } from '../../../../platform/product/common/productService.js';
import { IProgressService, ProgressLocation } from '../../../../platform/progress/common/progress.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { ActiveEditorContext } from '../../../common/contextkeys.js';
import { IWorkbenchContribution } from '../../../common/contributions.js';
import { IConfig, IDebugService } from '../../debug/common/debug.js';
import { ExtensionHostKind } from '../../../services/extensions/common/extensionHostKind.js';
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
import { IHostService } from '../../../services/host/browser/host.js';
import { IConfig, IDebugService } from '../../debug/common/debug.js';
import { RuntimeExtensionsEditor } from './runtimeExtensionsEditor.js';

export class DebugExtensionHostAction extends Action {
static readonly ID = 'workbench.extensions.action.debugExtensionHost';
static readonly LABEL = nls.localize('debugExtensionHost', "Start Debugging Extension Host In New Window");
static readonly CSS_CLASS = 'debug-extension-host';

constructor(
@INativeHostService private readonly _nativeHostService: INativeHostService,
@IDialogService private readonly _dialogService: IDialogService,
@IExtensionService private readonly _extensionService: IExtensionService,
@IProductService private readonly productService: IProductService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IHostService private readonly _hostService: IHostService,
) {
super(DebugExtensionHostAction.ID, DebugExtensionHostAction.LABEL, DebugExtensionHostAction.CSS_CLASS);
export class DebugExtensionHostAction extends Action2 {
constructor() {
super({
id: 'workbench.extensions.action.debugExtensionHost',
title: { value: nls.localize('debugExtensionHost', "Start Debugging Extension Host In New Window"), original: 'Start Debugging Extension Host In New Window' },
category: Categories.Developer,
f1: true,
icon: Codicon.debugStart,
menu: {
id: MenuId.EditorTitle,
when: ActiveEditorContext.isEqualTo(RuntimeExtensionsEditor.ID),
group: 'navigation',
}
});
}

override async run(_args: unknown): Promise<any> {
const inspectPorts = await this._extensionService.getInspectPorts(ExtensionHostKind.LocalProcess, false);
if (inspectPorts.length === 0) {
const res = await this._dialogService.confirm({
message: nls.localize('restart1', "Debug Extensions"),
detail: nls.localize('restart2', "In order to debug extensions a restart is required. Do you want to restart '{0}' now?", this.productService.nameLong),
primaryButton: nls.localize({ key: 'restart3', comment: ['&& denotes a mnemonic'] }, "&&Restart")
});
if (res.confirmed) {
await this._nativeHostService.relaunch({ addArgs: [`--inspect-extensions=${randomPort()}`] });
}
run(accessor: ServicesAccessor): void {
const nativeHostService = accessor.get(INativeHostService);
const dialogService = accessor.get(IDialogService);
const extensionService = accessor.get(IExtensionService);
const productService = accessor.get(IProductService);
const instantiationService = accessor.get(IInstantiationService);
const hostService = accessor.get(IHostService);

return;
}
extensionService.getInspectPorts(ExtensionHostKind.LocalProcess, false).then(async inspectPorts => {
if (inspectPorts.length === 0) {
const res = await dialogService.confirm({
message: nls.localize('restart1', "Debug Extensions"),
detail: nls.localize('restart2', "In order to debug extensions a restart is required. Do you want to restart '{0}' now?", productService.nameLong),
primaryButton: nls.localize({ key: 'restart3', comment: ['&& denotes a mnemonic'] }, "&&Restart")
});
if (res.confirmed) {
await nativeHostService.relaunch({ addArgs: [`--inspect-extensions=${randomPort()}`] });
}
return;
}

if (inspectPorts.length > 1) {
// TODO
console.warn(`There are multiple extension hosts available for debugging. Picking the first one...`);
}
if (inspectPorts.length > 1) {
// TODO
console.warn(`There are multiple extension hosts available for debugging. Picking the first one...`);
}

const s = this._instantiationService.createInstance(Storage);
s.storeDebugOnNewWindow(inspectPorts[0].port);
const s = instantiationService.createInstance(Storage);
s.storeDebugOnNewWindow(inspectPorts[0].port);

this._hostService.openWindow();
hostService.openWindow();
});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { ExtensionHostKind } from '../../../services/extensions/common/extension
import { IExtensionHostProfile, IExtensionService, ProfileSession } from '../../../services/extensions/common/extensions.js';
import { ExtensionHostProfiler } from '../../../services/extensions/electron-sandbox/extensionHostProfiler.js';
import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from '../../../services/statusbar/browser/statusbar.js';
import { URI } from '../../../../base/common/uri.js';

export class ExtensionHostProfileService extends Disposable implements IExtensionHostProfileService {

Expand All @@ -42,6 +43,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
private profilingStatusBarIndicator: IStatusbarEntryAccessor | undefined;
private readonly profilingStatusBarIndicatorLabelUpdater = this._register(new MutableDisposable());

public lastProfileSavedTo: URI | undefined;
public get state() { return this._state; }
public get lastProfile() { return this._profile; }

Expand Down Expand Up @@ -166,6 +168,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio

private _setLastProfile(profile: IExtensionHostProfile) {
this._profile = profile;
this.lastProfileSavedTo = undefined;
this._onDidChangeLastProfile.fire(undefined);
}

Expand Down
Loading

0 comments on commit 35676d1

Please sign in to comment.