Skip to content

Commit

Permalink
show blocking extension in editor, #60332
Browse files Browse the repository at this point in the history
  • Loading branch information
jrieken committed Nov 26, 2018
1 parent 55565d4 commit 91fb4ec
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 15 deletions.
4 changes: 2 additions & 2 deletions src/tsconfig.strictNullChecks.json
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@
"./vs/workbench/parts/extensions/common/extensions.ts",
"./vs/workbench/parts/extensions/common/extensionsFileTemplate.ts",
"./vs/workbench/parts/extensions/electron-browser/extensionsActivationProgress.ts",
"./vs/workbench/parts/extensions/electron-browser/extensionsAutoProfiler.ts",
// "./vs/workbench/parts/extensions/electron-browser/extensionsAutoProfiler.ts",
"./vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts",
"./vs/workbench/parts/logs/common/logConstants.ts",
"./vs/workbench/parts/logs/electron-browser/logs.contribution.ts",
Expand Down Expand Up @@ -741,4 +741,4 @@
"exclude": [
"./typings/require-monaco.d.ts"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
private readonly _onDidChangeLastProfile: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidChangeLastProfile: Event<void> = this._onDidChangeLastProfile.event;

private readonly _unresponsiveProfiles = new Map<string, IExtensionHostProfile>();
private _profile: IExtensionHostProfile;
private _profileSession: ProfileSession;
private _state: ProfileSessionState;
Expand Down Expand Up @@ -120,13 +121,19 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
this._onDidChangeLastProfile.fire(void 0);
}

public getLastProfile(): IExtensionHostProfile {
return this._profile;
getUnresponsiveProfile(extensionId: string): IExtensionHostProfile | undefined {
return this._unresponsiveProfiles.get(extensionId);
}

public clearLastProfile(): void {
this._setLastProfile(null);
setUnresponsiveProfile(extensionId: string, profile: IExtensionHostProfile): boolean {
if (!this._unresponsiveProfiles.has(extensionId)) {
this._unresponsiveProfiles.set(extensionId, profile);
this._setLastProfile(profile);
return true;
}
return false;
}

}

export class ProfileExtHostStatusbarItem implements IStatusbarItem {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { tmpdir } from 'os';
import { join } from 'path';
import { writeFile } from 'vs/base/node/pfs';
import { IExtensionHostProfileService } from 'vs/workbench/parts/extensions/electron-browser/runtimeExtensionsEditor';

export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchContribution {

private readonly _session = new Map<ICpuProfilerTarget, CancellationTokenSource>();

constructor(
@IExtensionService private _extensionService: IExtensionService,
@IExtensionHostProfileService private readonly _extensionProfileService: IExtensionHostProfileService,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@ILogService private readonly _logService: ILogService,
) {
Expand Down Expand Up @@ -118,6 +120,7 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont
return;
}

const didPrompt = duration > 5e6 && top!.percentage > 90 && this._extensionProfileService.setUnresponsiveProfile(extension.id, profile);
const path = join(tmpdir(), `exthost-${Math.random().toString(16).slice(2, 8)}.cpuprofile`);
await writeFile(path, JSON.stringify(profile.data));

Expand All @@ -127,11 +130,13 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont
"exthostunresponsive" : {
"duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true },
"data": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
"prompt" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true },
}
*/
this._telemetryService.publicLog('exthostunresponsive', {
duration,
data
data,
prompt: didPrompt ? 1 : 0
});
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { randomPort } from 'vs/base/node/ports';
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel';

export const IExtensionHostProfileService = createDecorator<IExtensionHostProfileService>('extensionHostProfileService');
export const CONTEXT_PROFILE_SESSION_STATE = new RawContextKey<string>('profileSessionState', 'none');
Expand All @@ -64,7 +65,8 @@ export interface IExtensionHostProfileService {
startProfiling(): void;
stopProfiling(): void;

clearLastProfile(): void;
getUnresponsiveProfile(extensionId: string): IExtensionHostProfile;
setUnresponsiveProfile(extensionId: string, profile: IExtensionHostProfile): boolean;
}

interface IExtensionProfileInformation {
Expand All @@ -87,6 +89,7 @@ interface IRuntimeExtension {
marketplaceInfo: IExtension;
status: IExtensionsStatus;
profileInfo: IExtensionProfileInformation;
unresponsiveProfile?: IExtensionHostProfile;
}

export class RuntimeExtensionsEditor extends BaseEditor {
Expand All @@ -100,7 +103,7 @@ export class RuntimeExtensionsEditor extends BaseEditor {
private _extensionsDescriptions: IExtensionDescription[];
private _updateSoon: RunOnceScheduler;
private _profileSessionState: IContextKey<string>;
private _extensionsHostRecoded: IContextKey<boolean>;
private _extensionsHostRecorded: IContextKey<boolean>;

constructor(
@ITelemetryService telemetryService: ITelemetryService,
Expand All @@ -121,22 +124,21 @@ export class RuntimeExtensionsEditor extends BaseEditor {
this._profileInfo = this._extensionHostProfileService.lastProfile;
this._register(this._extensionHostProfileService.onDidChangeLastProfile(() => {
this._profileInfo = this._extensionHostProfileService.lastProfile;
this._extensionsHostRecoded.set(!!this._profileInfo);
this._extensionsHostRecorded.set(!!this._profileInfo);
this._updateExtensions();
}));
this._extensionHostProfileService.onDidChangeState(() => {
this._register(this._extensionHostProfileService.onDidChangeState(() => {
const state = this._extensionHostProfileService.state;

this._profileSessionState.set(ProfileSessionState[state].toLowerCase());
});
}));

this._elements = null;

this._extensionsDescriptions = [];
this._updateExtensions();

this._profileSessionState = CONTEXT_PROFILE_SESSION_STATE.bindTo(contextKeyService);
this._extensionsHostRecoded = CONTEXT_EXTENSION_HOST_PROFILE_RECORDED.bindTo(contextKeyService);
this._extensionsHostRecorded = CONTEXT_EXTENSION_HOST_PROFILE_RECORDED.bindTo(contextKeyService);

this._updateSoon = this._register(new RunOnceScheduler(() => this._updateExtensions(), 200));

Expand Down Expand Up @@ -210,7 +212,8 @@ export class RuntimeExtensionsEditor extends BaseEditor {
description: extensionDescription,
marketplaceInfo: marketplaceMap[extensionDescription.id],
status: statusMap[extensionDescription.id],
profileInfo: profileInfo
profileInfo: profileInfo,
unresponsiveProfile: this._extensionHostProfileService.getUnresponsiveProfile(extensionDescription.id)
};
}

Expand All @@ -224,6 +227,16 @@ export class RuntimeExtensionsEditor extends BaseEditor {
}
return b.profileInfo.totalTime - a.profileInfo.totalTime;
});
} else {
// bubble up unresponsive extension
result = result.sort((a, b) => {
if (a.unresponsiveProfile && !b.unresponsiveProfile) {
return -1;
} else if (!a.unresponsiveProfile && b.unresponsiveProfile) {
return 1;
}
return 0;
});
}

return result;
Expand All @@ -250,6 +263,7 @@ export class RuntimeExtensionsEditor extends BaseEditor {

activationTime: HTMLElement;
profileTime: HTMLElement;
unresponsiveWarn: HTMLElement;

profileTimeline: HTMLElement;

Expand Down Expand Up @@ -282,6 +296,7 @@ export class RuntimeExtensionsEditor extends BaseEditor {
const timeContainer = append(element, $('.time'));
const activationTime = append(timeContainer, $('div.activation-time'));
const profileTime = append(timeContainer, $('div.profile-time'));
const unresponsiveWarn = append(timeContainer, $('div.unresponsive-warn'));

const profileTimeline = append(element, $('div.profile-timeline'));

Expand All @@ -300,6 +315,7 @@ export class RuntimeExtensionsEditor extends BaseEditor {
actionbar,
activationTime,
profileTime,
unresponsiveWarn,
profileTimeline,
msgIcon,
msgLabel,
Expand Down Expand Up @@ -414,6 +430,15 @@ export class RuntimeExtensionsEditor extends BaseEditor {
data.profileTime.textContent = '';
data.profileTimeline.innerHTML = '';
}

const unresponsiveProfile = this._extensionHostProfileService.getUnresponsiveProfile(element.description.id);
if (unresponsiveProfile && (!this._profileInfo || this._profileInfo === unresponsiveProfile)) {
data.unresponsiveWarn.innerHTML = renderOcticons(`Unresponsive $(alert)`);
data.unresponsiveWarn.title = nls.localize('unresponsive.title', "Extension has caused the extension host to freeze.");
} else {
data.unresponsiveWarn.innerHTML = '';
data.unresponsiveWarn.title = '';
}
},

disposeElement: () => null,
Expand Down

0 comments on commit 91fb4ec

Please sign in to comment.