[JS Profiler deprecation] Remove the JS Profiler code

Bug: 335130722, 40903173
Change-Id: I6cad460fcb632b4b0dfc80d842430d6d27947e11
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5465631
Commit-Queue: Nancy Li <nancyly@chromium.org>
Reviewed-by: Jack Franklin <jacktfranklin@chromium.org>
This commit is contained in:
Nancy Li
2024-04-22 16:01:23 +00:00
committed by Devtools-frontend LUCI CQ
parent 324c86a306
commit 6db489bfef
25 changed files with 27 additions and 751 deletions
+3 -4
View File
@@ -503,8 +503,8 @@ grd_files_release_sources = [
"front_end/panels/issues/components/components.js",
"front_end/panels/issues/issues-meta.js",
"front_end/panels/issues/issues.js",
"front_end/panels/js_profiler/js_profiler-meta.js",
"front_end/panels/js_profiler/js_profiler.js",
"front_end/panels/js_timeline/js_timeline-meta.js",
"front_end/panels/js_timeline/js_timeline.js",
"front_end/panels/layer_viewer/layer_viewer-meta.js",
"front_end/panels/layer_viewer/layer_viewer.js",
"front_end/panels/layers/layers-meta.js",
@@ -1418,8 +1418,6 @@ grd_files_debug_sources = [
"front_end/panels/performance_monitor/PerformanceMonitor.js",
"front_end/panels/performance_monitor/performanceMonitor.css.js",
"front_end/panels/profiler/BottomUpProfileDataGrid.js",
"front_end/panels/profiler/CPUProfileFlameChart.js",
"front_end/panels/profiler/CPUProfileView.js",
"front_end/panels/profiler/ChildrenProvider.js",
"front_end/panels/profiler/HeapProfileView.js",
"front_end/panels/profiler/HeapProfilerPanel.js",
@@ -1432,6 +1430,7 @@ grd_files_debug_sources = [
"front_end/panels/profiler/LiveHeapProfileView.js",
"front_end/panels/profiler/ModuleUIStrings.js",
"front_end/panels/profiler/ProfileDataGrid.js",
"front_end/panels/profiler/ProfileFlameChartDataProvider.js",
"front_end/panels/profiler/ProfileHeader.js",
"front_end/panels/profiler/ProfileLauncherView.js",
"front_end/panels/profiler/ProfileSidebarTreeElement.js",
-1
View File
@@ -164,7 +164,6 @@ group("unittests") {
"panels/network:unittests",
"panels/network/components:unittests",
"panels/performance_monitor:unittests",
"panels/profiler:unittests",
"panels/protocol_monitor:unittests",
"panels/protocol_monitor/components:unittests",
"panels/recorder:unittests",
-2
View File
@@ -699,8 +699,6 @@ export enum PanelWithLocation {
'sources.search-drawer' = 28,
'security-main' = 29,
'security-drawer' = 30,
'js_profiler-main' = 31,
'js_profiler-drawer' = 32,
'lighthouse-main' = 33,
'lighthouse-drawer' = 34,
'coverage-main' = 35,
+1 -1
View File
@@ -13,7 +13,7 @@ devtools_entrypoint("entrypoint") {
"../../core/i18n:bundle",
"../../core/sdk:bundle",
"../../generated:protocol",
"../../panels/js_profiler:meta",
"../../panels/js_timeline:meta",
"../../panels/mobile_throttling:meta",
"../../ui/legacy/components/utils:bundle",
"../main:bundle",
+1 -1
View File
@@ -3,7 +3,7 @@
// found in the LICENSE file.
import '../shell/shell.js';
import '../../panels/js_profiler/js_profiler-meta.js';
import '../../panels/js_timeline/js_timeline-meta.js';
import '../../panels/mobile_throttling/mobile_throttling-meta.js';
import * as Common from '../../core/common/common.js';
+1 -1
View File
@@ -36,7 +36,7 @@ devtools_entrypoint("entrypoint") {
":node_app",
"../../core/i18n:bundle",
"../../core/root:bundle",
"../../panels/js_profiler:meta",
"../../panels/js_timeline:meta",
"../../panels/mobile_throttling:meta",
"../../panels/sources:bundle",
"../../ui/legacy:bundle",
+6 -5
View File
@@ -3,16 +3,17 @@
// found in the LICENSE file.
import '../shell/shell.js';
import '../../panels/mobile_throttling/mobile_throttling-meta.js';
import '../../panels/js_profiler/js_profiler-meta.js';
import type * as Sources from '../../panels/sources/sources.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as UI from '../../ui/legacy/legacy.js';
import '../../panels/js_timeline/js_timeline-meta.js';
import * as Common from '../../core/common/common.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as Root from '../../core/root/root.js';
import type * as Sources from '../../panels/sources/sources.js';
import * as UI from '../../ui/legacy/legacy.js';
import * as Main from '../main/main.js';
import {NodeMainImpl} from './NodeMain.js'; // eslint-disable-line rulesdir/es_modules_import
import {NodeConnectionsPanel} from './NodeConnectionsPanel.js'; // eslint-disable-line rulesdir/es_modules_import
import {NodeMainImpl} from './NodeMain.js'; // eslint-disable-line rulesdir/es_modules_import
const UIStrings = {
/**
-1
View File
@@ -36,7 +36,6 @@ group("legacy_test_runner-resources") {
"bindings_test_runner:bundle",
"console_test_runner:bundle",
"coverage_test_runner:bundle",
"cpu_profiler_test_runner:bundle",
"data_grid_test_runner:bundle",
"device_mode_test_runner:bundle",
"elements_test_runner:bundle",
@@ -1,15 +0,0 @@
# Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("../../../scripts/build/ninja/copy.gni")
group("bundle") {
public_deps = [ ":gen" ]
data_deps = [ ":gen" ]
}
copy_to_gen("gen") {
sources = [ "cpu_profiler_test_runner.js" ]
}
@@ -1,78 +0,0 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Profiler from '../../panels/profiler/profiler.js';
import {TestRunner} from '../test_runner/test_runner.js';
/**
* @fileoverview using private properties isn't a Closure violation in tests.
*/
export const CPUProfilerTestRunner = {};
CPUProfilerTestRunner.startProfilerTest = function(callback) {
TestRunner.addResult('Profiler was enabled.');
TestRunner.addSniffer(
Profiler.ProfilesPanel.JSProfilerPanel.instance(), 'addProfileHeader', CPUProfilerTestRunner.profileHeaderAdded,
true);
TestRunner.addSniffer(
Profiler.ProfileView.ProfileView.prototype, 'refresh', CPUProfilerTestRunner.profileViewRefresh, true);
TestRunner.safeWrap(callback)();
};
CPUProfilerTestRunner.completeProfilerTest = function() {
TestRunner.addResult('');
TestRunner.addResult('Profiler was disabled.');
TestRunner.completeTest();
};
CPUProfilerTestRunner.runProfilerTestSuite = function(testSuite) {
const testSuiteTests = testSuite.slice();
function runner() {
if (!testSuiteTests.length) {
CPUProfilerTestRunner.completeProfilerTest();
return;
}
const nextTest = testSuiteTests.shift();
TestRunner.addResult('');
TestRunner.addResult(
'Running: ' +
/function\s([^(]*)/.exec(nextTest)[1]);
TestRunner.safeWrap(nextTest)(runner, runner);
}
CPUProfilerTestRunner.startProfilerTest(runner);
};
CPUProfilerTestRunner.showProfileWhenAdded = function(title) {
CPUProfilerTestRunner.showProfileWhenAdded = title;
};
CPUProfilerTestRunner.profileHeaderAdded = function(profile) {
if (CPUProfilerTestRunner.showProfileWhenAdded === profile.title) {
Profiler.ProfilesPanel.JSProfilerPanel.instance().showProfile(profile);
}
};
CPUProfilerTestRunner.waitUntilProfileViewIsShown = function(title, callback) {
callback = TestRunner.safeWrap(callback);
const profilesPanel = Profiler.ProfilesPanel.JSProfilerPanel.instance();
if (profilesPanel.visibleView && profilesPanel.visibleView.profile &&
profilesPanel.visibleView.profileHeader.title === title) {
callback(profilesPanel.visibleView);
} else {
CPUProfilerTestRunner.waitUntilProfileViewIsShownCallback = {title: title, callback: callback};
}
};
CPUProfilerTestRunner.profileViewRefresh = function() {
if (CPUProfilerTestRunner.waitUntilProfileViewIsShownCallback &&
CPUProfilerTestRunner.waitUntilProfileViewIsShownCallback.title === this.profileHeader.title) {
const callback = CPUProfilerTestRunner.waitUntilProfileViewIsShownCallback;
delete CPUProfilerTestRunner.waitUntilProfileViewIsShownCallback;
callback.callback(this);
}
};
@@ -7,7 +7,7 @@ import("../../../scripts/build/ninja/devtools_module.gni")
import("../visibility.gni")
devtools_entrypoint("bundle") {
entrypoint = "js_profiler.ts"
entrypoint = "js_timeline.ts"
deps = []
@@ -20,15 +20,11 @@ devtools_entrypoint("bundle") {
}
devtools_entrypoint("meta") {
entrypoint = "js_profiler-meta.ts"
entrypoint = "js_timeline-meta.ts"
deps = [
":bundle",
"../../core/i18n:bundle",
"../../core/root:bundle",
"../../panels/profiler:bundle",
"../../panels/timeline:bundle",
"../../ui/legacy:bundle",
]
visibility = [ "../../entrypoints/*" ]
@@ -3,7 +3,7 @@
// found in the LICENSE file.
import * as i18n from '../../core/i18n/i18n.js';
import type * as Timeline from '../../panels/timeline/timeline.js';
import type * as Timeline from '../timeline/timeline.js';
import * as UI from '../../ui/legacy/legacy.js';
const UIStrings = {
@@ -32,7 +32,7 @@ const UIStrings = {
*/
startProfilingAndReloadPage: 'Start profiling and reload page',
};
const str_ = i18n.i18n.registerUIStrings('panels/js_profiler/js_profiler-meta.ts', UIStrings);
const str_ = i18n.i18n.registerUIStrings('panels/js_timeline/js_timeline-meta.ts', UIStrings);
const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
let loadedTimelineModule: (typeof Timeline|undefined);
+1 -18
View File
@@ -21,8 +21,6 @@ generate_css("css_files") {
devtools_module("profiler") {
sources = [
"BottomUpProfileDataGrid.ts",
"CPUProfileFlameChart.ts",
"CPUProfileView.ts",
"ChildrenProvider.ts",
"HeapProfileView.ts",
"HeapProfilerPanel.ts",
@@ -35,6 +33,7 @@ devtools_module("profiler") {
"LiveHeapProfileView.ts",
"ModuleUIStrings.ts",
"ProfileDataGrid.ts",
"ProfileFlameChartDataProvider.ts",
"ProfileHeader.ts",
"ProfileLauncherView.ts",
"ProfileSidebarTreeElement.ts",
@@ -75,7 +74,6 @@ devtools_entrypoint("bundle") {
visibility = [
":*",
"../../entrypoints/*",
"../js_profiler/*",
"../timeline/*",
]
@@ -95,18 +93,3 @@ devtools_entrypoint("meta") {
visibility = [ "../../entrypoints/*" ]
}
ts_library("unittests") {
testonly = true
sources = [ "CPUProfileView.test.ts" ]
deps = [
":bundle",
"../../core/common:bundle",
"../../core/protocol_client:bundle",
"../../core/sdk:bundle",
"../../generated:protocol",
"../../testing",
]
}
@@ -1,37 +0,0 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as SDK from '../../core/sdk/sdk.js';
import type * as Protocol from '../../generated/protocol.js';
import {createTarget} from '../../testing/EnvironmentHelpers.js';
import {describeWithRealConnection} from '../../testing/RealConnection.js';
import type * as Profiler from './profiler.js';
describeWithRealConnection('CPUProfileView test', () => {
it('reads registered console profile messages from the model', async () => {
const Profiler = await import('./profiler.js');
const target = createTarget();
const model = target.model(SDK.CPUProfilerModel.CPUProfilerModel) as SDK.CPUProfilerModel.CPUProfilerModel;
const scriptId = 'bar' as Protocol.Runtime.ScriptId;
const lineNumber = 42;
const cpuProfile = {
nodes: [{
id: 1,
callFrame: {functionName: 'fun', scriptId, lineNumber, url: 'http://foo', columnNumber: 1},
hitCount: 42,
}],
startTime: 1,
endTime: 2,
};
model.consoleProfileFinished({
id: 'foo',
location: {scriptId, lineNumber},
profile: cpuProfile,
});
const profileType = new Profiler.CPUProfileView.CPUProfileType();
const cpuProfileHeader = profileType.getProfiles()[0] as Profiler.CPUProfileView.CPUProfileHeader;
assert.deepEqual(cpuProfileHeader?.cpuProfilerModel?.registeredConsoleProfileMessages[0]?.cpuProfile, cpuProfile);
});
});
-463
View File
@@ -1,463 +0,0 @@
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/*
* Copyright (C) 2008 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import * as Common from '../../core/common/common.js';
import * as Host from '../../core/host/host.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as SDK from '../../core/sdk/sdk.js';
import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
import * as Components from '../../ui/legacy/components/utils/utils.js';
import * as UI from '../../ui/legacy/legacy.js';
import type * as Protocol from '../../generated/protocol.js';
import * as CPUProfile from '../../models/cpu_profile/cpu_profile.js';
import {ProfileFlameChartDataProvider} from './CPUProfileFlameChart.js';
import {type Formatter, type ProfileDataGridNode} from './ProfileDataGrid.js';
import {ProfileEvents, ProfileType, type ProfileHeader} from './ProfileHeader.js';
import {ProfileView, WritableProfileHeader} from './ProfileView.js';
const UIStrings = {
/**
*@description Time of a single activity, as opposed to the total time
*/
selfTime: 'Self Time',
/**
*@description Text for the total time of something
*/
totalTime: 'Total Time',
/**
*@description Text in CPUProfile View of a profiler tool
*/
recordJavascriptCpuProfile: 'Record JavaScript CPU Profile',
/**
*@description Text in CPUProfile View of a profiler tool
*/
stopCpuProfiling: 'Stop CPU profiling',
/**
*@description Text in CPUProfile View of a profiler tool
*/
startCpuProfiling: 'Start CPU profiling',
/**
*@description Text in CPUProfile View of a profiler tool
*/
cpuProfiles: 'CPU PROFILES',
/**
*@description Text in CPUProfile View of a profiler tool, that show how much time a script spend executing a function.
*/
cpuProfilesShow: 'CPU profiles show where the execution time is spent in your page\'s JavaScript functions.',
/**
*@description Text in CPUProfile View of a profiler tool
*/
recording: 'Recording…',
/**
*@description Time in miliseconds
*@example {30.1} PH1
*/
fms: '{PH1} ms',
/**
*@description Text in CPUProfile View of a profiler tool
*@example {21.33} PH1
*/
formatPercent: '{PH1} %',
/**
*@description Text for the name of something
*/
name: 'Name',
/**
*@description Text for web URLs
*/
url: 'URL',
/**
*@description Text in CPUProfile View of a profiler tool
*/
aggregatedSelfTime: 'Aggregated self time',
/**
*@description Text in CPUProfile View of a profiler tool
*/
aggregatedTotalTime: 'Aggregated total time',
/**
*@description Text that indicates a JavaScript function in a CPU profile is not optimized.
*/
notOptimized: 'Not optimized',
};
const str_ = i18n.i18n.registerUIStrings('panels/profiler/CPUProfileView.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
export class CPUProfileView extends ProfileView implements UI.SearchableView.Searchable {
override profileHeader: CPUProfileHeader;
override adjustedTotal: number;
constructor(profileHeader: CPUProfileHeader) {
super();
this.profileHeader = profileHeader;
this.initialize(new NodeFormatter(this));
const profile = profileHeader.profileModel();
this.adjustedTotal = profile.profileHead.total;
this.adjustedTotal -= profile.idleNode ? profile.idleNode.total : 0;
this.setProfile(profile);
}
override wasShown(): void {
super.wasShown();
PerfUI.LineLevelProfile.Performance.instance().reset();
PerfUI.LineLevelProfile.Performance.instance().appendCPUProfile(
this.profileHeader.profileModel(), this.profileHeader.target);
}
override columnHeader(columnId: string): Common.UIString.LocalizedString {
switch (columnId) {
case 'self':
return i18nString(UIStrings.selfTime);
case 'total':
return i18nString(UIStrings.totalTime);
}
return Common.UIString.LocalizedEmptyString;
}
override createFlameChartDataProvider(): ProfileFlameChartDataProvider {
return new CPUFlameChartDataProvider(this.profileHeader.profileModel(), this.profileHeader.cpuProfilerModel);
}
}
export class CPUProfileType extends ProfileType {
recording: boolean;
constructor() {
super(CPUProfileType.TypeId, i18nString(UIStrings.recordJavascriptCpuProfile));
this.recording = false;
const targetManager = SDK.TargetManager.TargetManager.instance();
const profilerModels = targetManager.models(SDK.CPUProfilerModel.CPUProfilerModel);
for (const model of profilerModels) {
for (const message of model.registeredConsoleProfileMessages) {
this.consoleProfileFinished(message);
}
}
SDK.TargetManager.TargetManager.instance().addModelListener(
SDK.CPUProfilerModel.CPUProfilerModel, SDK.CPUProfilerModel.Events.ConsoleProfileFinished,
event => this.consoleProfileFinished(event.data), this);
}
override profileBeingRecorded(): ProfileHeader|null {
return super.profileBeingRecorded() as ProfileHeader | null;
}
override typeName(): string {
return 'CPU';
}
override fileExtension(): string {
return '.cpuprofile';
}
override get buttonTooltip(): Common.UIString.LocalizedString {
return this.recording ? i18nString(UIStrings.stopCpuProfiling) : i18nString(UIStrings.startCpuProfiling);
}
override buttonClicked(): boolean {
if (this.recording) {
void this.stopRecordingProfile();
return false;
}
this.startRecordingProfile();
return true;
}
override get treeItemTitle(): Common.UIString.LocalizedString {
return i18nString(UIStrings.cpuProfiles);
}
override get description(): Common.UIString.LocalizedString {
return i18nString(UIStrings.cpuProfilesShow);
}
consoleProfileFinished(data: SDK.CPUProfilerModel.ProfileFinishedData): void {
const profile = new CPUProfileHeader(data.cpuProfilerModel, this, data.title);
profile.setProtocolProfile(data.cpuProfile);
this.addProfile(profile);
}
startRecordingProfile(): void {
const cpuProfilerModel = UI.Context.Context.instance().flavor(SDK.CPUProfilerModel.CPUProfilerModel);
if (this.profileBeingRecorded() || !cpuProfilerModel) {
return;
}
const profile = new CPUProfileHeader(cpuProfilerModel, this);
this.setProfileBeingRecorded(profile as ProfileHeader);
void SDK.TargetManager.TargetManager.instance().suspendAllTargets();
this.addProfile(profile as ProfileHeader);
profile.updateStatus(i18nString(UIStrings.recording));
this.recording = true;
void cpuProfilerModel.startRecording();
Host.userMetrics.actionTaken(Host.UserMetrics.Action.ProfilesCPUProfileTaken);
}
async stopRecordingProfile(): Promise<void> {
this.recording = false;
const profileBeingRecorded = this.profileBeingRecorded() as CPUProfileHeader;
if (!profileBeingRecorded || !profileBeingRecorded.cpuProfilerModel) {
return;
}
const profile = await profileBeingRecorded.cpuProfilerModel.stopRecording();
const recordedProfile = this.profileBeingRecorded() as CPUProfileHeader;
if (recordedProfile) {
if (!profile) {
throw new Error('Expected profile to be non-null');
}
recordedProfile.setProtocolProfile(profile);
recordedProfile.updateStatus('');
this.setProfileBeingRecorded(null);
}
await SDK.TargetManager.TargetManager.instance().resumeAllTargets();
this.dispatchEventToListeners(ProfileEvents.ProfileComplete, recordedProfile);
}
override createProfileLoadedFromFile(title: string): ProfileHeader {
return new CPUProfileHeader(null, this, title);
}
override profileBeingRecordedRemoved(): void {
void this.stopRecordingProfile();
}
// eslint-disable-next-line @typescript-eslint/naming-convention
static readonly TypeId = 'CPU';
}
export class CPUProfileHeader extends WritableProfileHeader {
cpuProfilerModel: SDK.CPUProfilerModel.CPUProfilerModel|null;
profileModelInternal?: CPUProfile.CPUProfileDataModel.CPUProfileDataModel;
target: SDK.Target.Target|null;
constructor(cpuProfilerModel: SDK.CPUProfilerModel.CPUProfilerModel|null, type: CPUProfileType, title?: string) {
super(cpuProfilerModel && cpuProfilerModel.debuggerModel(), type, title);
this.cpuProfilerModel = cpuProfilerModel;
this.target = this.cpuProfilerModel && this.cpuProfilerModel.target() || null;
}
override createView(): ProfileView {
return new CPUProfileView(this);
}
protocolProfile(): Protocol.Profiler.Profile {
if (!this.protocolProfile()) {
throw new Error('Expected _protocolProfile to be available');
}
return this.protocolProfile();
}
profileModel(): CPUProfile.CPUProfileDataModel.CPUProfileDataModel {
if (!this.profileModelInternal) {
throw new Error('Expected _profileModel to be available');
}
return this.profileModelInternal;
}
override setProfile(profile: Protocol.Profiler.Profile): void {
this.profileModelInternal = new CPUProfile.CPUProfileDataModel.CPUProfileDataModel(profile);
}
}
export class NodeFormatter implements Formatter {
readonly profileView: CPUProfileView;
constructor(profileView: CPUProfileView) {
this.profileView = profileView;
}
formatValue(value: number): string {
return i18nString(UIStrings.fms, {PH1: value.toFixed(1)});
}
formatValueAccessibleText(value: number): string {
return this.formatValue(value);
}
formatPercent(value: number, node: ProfileDataGridNode): string {
if (this.profileView) {
const profile = this.profileView.profile();
if (profile && node.profileNode !== (profile as CPUProfile.CPUProfileDataModel.CPUProfileDataModel).idleNode) {
return i18nString(UIStrings.formatPercent, {PH1: value.toFixed(2)});
}
}
return '';
}
linkifyNode(node: ProfileDataGridNode): Element|null {
const cpuProfilerModel = this.profileView.profileHeader.cpuProfilerModel;
const target = cpuProfilerModel ? cpuProfilerModel.target() : null;
const options = {className: 'profile-node-file', inlineFrameIndex: 0};
return this.profileView.linkifier().maybeLinkifyConsoleCallFrame(target, node.profileNode.callFrame, options);
}
}
export class CPUFlameChartDataProvider extends ProfileFlameChartDataProvider {
readonly cpuProfile: CPUProfile.CPUProfileDataModel.CPUProfileDataModel;
readonly cpuProfilerModel: SDK.CPUProfilerModel.CPUProfilerModel|null;
entrySelfTimes?: Float32Array;
constructor(
cpuProfile: CPUProfile.CPUProfileDataModel.CPUProfileDataModel,
cpuProfilerModel: SDK.CPUProfilerModel.CPUProfilerModel|null) {
super();
this.cpuProfile = cpuProfile;
this.cpuProfilerModel = cpuProfilerModel;
}
override minimumBoundary(): number {
return this.cpuProfile.profileStartTime;
}
override totalTime(): number {
return this.cpuProfile.profileHead.total;
}
override entryHasDeoptReason(entryIndex: number): boolean {
const node = (this.entryNodes[entryIndex] as CPUProfile.CPUProfileDataModel.CPUProfileNode);
return Boolean(node.deoptReason);
}
override calculateTimelineData(): PerfUI.FlameChart.FlameChartTimelineData {
const entries: (CPUFlameChartDataProvider.ChartEntry|null)[] = [];
const stack: number[] = [];
let maxDepth = 5;
function onOpenFrame(): void {
stack.push(entries.length);
// Reserve space for the entry, as they have to be ordered by startTime.
// The entry itself will be put there in onCloseFrame.
entries.push(null);
}
function onCloseFrame(
depth: number, node: CPUProfile.ProfileTreeModel.ProfileNode, startTime: number, totalTime: number,
selfTime: number): void {
const index = (stack.pop() as number);
entries[index] = new CPUFlameChartDataProvider.ChartEntry(depth, totalTime, startTime, selfTime, node);
maxDepth = Math.max(maxDepth, depth);
}
this.cpuProfile.forEachFrame(onOpenFrame, onCloseFrame);
const entryNodes: CPUProfile.ProfileTreeModel.ProfileNode[] = new Array(entries.length);
const entryLevels = new Uint16Array(entries.length);
const entryTotalTimes = new Float32Array(entries.length);
const entrySelfTimes = new Float32Array(entries.length);
const entryStartTimes = new Float64Array(entries.length);
for (let i = 0; i < entries.length; ++i) {
const entry = entries[i];
if (!entry) {
continue;
}
entryNodes[i] = entry.node;
entryLevels[i] = entry.depth;
entryTotalTimes[i] = entry.duration;
entryStartTimes[i] = entry.startTime;
entrySelfTimes[i] = entry.selfTime;
}
this.maxStackDepthInternal = maxDepth + 1;
this.entryNodes = entryNodes;
this.timelineDataInternal =
PerfUI.FlameChart.FlameChartTimelineData.create({entryLevels, entryTotalTimes, entryStartTimes, groups: null});
this.entrySelfTimes = entrySelfTimes;
return this.timelineDataInternal;
}
override prepareHighlightedEntryInfo(entryIndex: number): Element|null {
const timelineData = this.timelineDataInternal;
const node = this.entryNodes[entryIndex];
if (!node) {
return null;
}
const entryInfo: {
title: string,
value: string,
}[] = [];
function pushEntryInfoRow(title: string, value: string): void {
entryInfo.push({title: title, value: value});
}
function millisecondsToString(ms: number): string {
if (ms === 0) {
return '0';
}
if (ms < 1000) {
return i18nString(UIStrings.fms, {PH1: ms.toFixed(1)});
}
return i18n.TimeUtilities.secondsToString(ms / 1000, true);
}
const name = UI.UIUtils.beautifyFunctionName(node.functionName);
pushEntryInfoRow(i18nString(UIStrings.name), name);
const selfTime = millisecondsToString((this.entrySelfTimes as Float32Array)[entryIndex]);
const totalTime =
millisecondsToString((timelineData as PerfUI.FlameChart.FlameChartTimelineData).entryTotalTimes[entryIndex]);
pushEntryInfoRow(i18nString(UIStrings.selfTime), selfTime);
pushEntryInfoRow(i18nString(UIStrings.totalTime), totalTime);
const linkifier = new Components.Linkifier.Linkifier();
const link =
linkifier.maybeLinkifyConsoleCallFrame(this.cpuProfilerModel && this.cpuProfilerModel.target(), node.callFrame);
if (link) {
pushEntryInfoRow(i18nString(UIStrings.url), link.textContent || '');
}
linkifier.dispose();
pushEntryInfoRow(
i18nString(UIStrings.aggregatedSelfTime), i18n.TimeUtilities.secondsToString(node.self / 1000, true));
pushEntryInfoRow(
i18nString(UIStrings.aggregatedTotalTime), i18n.TimeUtilities.secondsToString(node.total / 1000, true));
const deoptReason = (node as CPUProfile.CPUProfileDataModel.CPUProfileNode).deoptReason;
if (deoptReason) {
pushEntryInfoRow(i18nString(UIStrings.notOptimized), deoptReason);
}
return ProfileView.buildPopoverTable(entryInfo);
}
}
export namespace CPUFlameChartDataProvider {
export class ChartEntry {
depth: number;
duration: number;
startTime: number;
selfTime: number;
node: CPUProfile.ProfileTreeModel.ProfileNode;
constructor(
depth: number, duration: number, startTime: number, selfTime: number,
node: CPUProfile.ProfileTreeModel.ProfileNode) {
this.depth = depth;
this.duration = duration;
this.startTime = startTime;
this.selfTime = selfTime;
this.node = node;
}
}
}
+1 -1
View File
@@ -13,9 +13,9 @@ import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
import * as Components from '../../ui/legacy/components/utils/utils.js';
import * as UI from '../../ui/legacy/legacy.js';
import {ProfileFlameChartDataProvider} from './CPUProfileFlameChart.js';
import {Events, HeapTimelineOverview, type IdsRangeChangedEvent, type Samples} from './HeapTimelineOverview.js';
import {type Formatter, type ProfileDataGridNode} from './ProfileDataGrid.js';
import {ProfileFlameChartDataProvider} from './ProfileFlameChartDataProvider.js';
import {ProfileEvents, type ProfileHeader, ProfileType} from './ProfileHeader.js';
import {ProfileView, WritableProfileHeader} from './ProfileView.js';
@@ -139,7 +139,7 @@ export class ProfileFlameChartDataProvider implements PerfUI.FlameChart.FlameCha
}
}
export class CPUProfileFlameChart extends
export class ProfileFlameChart extends
Common.ObjectWrapper.eventMixin<PerfUI.FlameChart.EventTypes, typeof UI.Widget.VBox>(UI.Widget.VBox)
implements UI.SearchableView.Searchable {
readonly searchableView: UI.SearchableView.SearchableView;
@@ -2,17 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {CPUProfileType} from './CPUProfileView.js';
import {SamplingHeapProfileType} from './HeapProfileView.js';
import {HeapSnapshotProfileType, TrackingHeapSnapshotProfileType} from './HeapSnapshotView.js';
export class ProfileTypeRegistry {
cpuProfileType: CPUProfileType;
heapSnapshotProfileType: HeapSnapshotProfileType;
samplingHeapProfileType: SamplingHeapProfileType;
trackingHeapSnapshotProfileType: TrackingHeapSnapshotProfileType;
constructor() {
this.cpuProfileType = new CPUProfileType();
this.heapSnapshotProfileType = new HeapSnapshotProfileType();
this.samplingHeapProfileType = new SamplingHeapProfileType();
this.trackingHeapSnapshotProfileType = new TrackingHeapSnapshotProfileType();
+5 -5
View File
@@ -16,8 +16,8 @@ import * as Components from '../../ui/legacy/components/utils/utils.js';
import * as UI from '../../ui/legacy/legacy.js';
import {BottomUpProfileDataGridTree} from './BottomUpProfileDataGrid.js';
import {CPUProfileFlameChart, type ProfileFlameChartDataProvider} from './CPUProfileFlameChart.js';
import {type Formatter, type ProfileDataGridNode, ProfileDataGridTree} from './ProfileDataGrid.js';
import {ProfileFlameChart, type ProfileFlameChartDataProvider} from './ProfileFlameChartDataProvider.js';
import {type DataDisplayDelegate, ProfileHeader, type ProfileType} from './ProfileHeader.js';
import {ProfileSidebarTreeElement} from './ProfileSidebarTreeElement.js';
import {TopDownProfileDataGridTree} from './TopDownProfileDataGrid.js';
@@ -121,9 +121,9 @@ export class ProfileView extends UI.View.SimpleView implements UI.SearchableView
topDownProfileDataGridTree?: TopDownProfileDataGridTree|null;
currentSearchResultIndex?: number;
dataProvider?: ProfileFlameChartDataProvider;
flameChart?: CPUProfileFlameChart;
visibleView?: CPUProfileFlameChart|DataGrid.DataGrid.DataGridWidget<unknown>;
searchableElement?: ProfileDataGridTree|CPUProfileFlameChart;
flameChart?: ProfileFlameChart;
visibleView?: ProfileFlameChart|DataGrid.DataGrid.DataGridWidget<unknown>;
searchableElement?: ProfileDataGridTree|ProfileFlameChart;
profileDataGridTree?: ProfileDataGridTree;
constructor() {
super(i18nString(UIStrings.profile));
@@ -405,7 +405,7 @@ export class ProfileView extends UI.View.SimpleView implements UI.SearchableView
return;
}
this.dataProvider = this.createFlameChartDataProvider();
this.flameChart = new CPUProfileFlameChart(this.searchableViewInternal, this.dataProvider);
this.flameChart = new ProfileFlameChart(this.searchableViewInternal, this.dataProvider);
this.flameChart.addEventListener(PerfUI.FlameChart.Events.EntryInvoked, event => {
void this.onEntryInvoked(event);
});
@@ -28,7 +28,6 @@
*/
import * as Common from '../../core/common/common.js';
import * as Host from '../../core/host/host.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as Platform from '../../core/platform/platform.js';
import * as SDK from '../../core/sdk/sdk.js';
@@ -48,7 +47,6 @@ import {Events as ProfileLauncherEvents, ProfileLauncherView} from './ProfileLau
import {ProfileSidebarTreeElement} from './ProfileSidebarTreeElement.js';
import profilesPanelStyles from './profilesPanel.css.js';
import profilesSidebarTreeStyles from './profilesSidebarTree.css.js';
import {instance} from './ProfileTypeRegistry.js';
const UIStrings = {
/**
@@ -74,19 +72,6 @@ const UIStrings = {
*@description Text in Profiles Panel of a profiler tool
*/
profiles: 'Profiles',
/**
*@description Text in the JS Profiler panel to show warning to user that JS profiler will be deprecated.
*/
deprecationWarnMsg:
'This panel will be deprecated in the upcoming version. Use the Performance panel to record JavaScript CPU profiles.',
/**
*@description Text of a button in the JS Profiler panel to let user give feedback.
*/
feedback: 'Feedback',
/**
*@description Text of a button in the JS Profiler panel to let user go to Performance panel.
*/
goToPerformancePanel: 'Go to Performance Panel',
};
const str_ = i18n.i18n.registerUIStrings('panels/profiler/ProfilesPanel.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -682,84 +667,6 @@ export class ProfilesSidebarTreeElement extends UI.TreeOutline.TreeElement {
}
}
let jsProfilerPanelInstance: JSProfilerPanel;
export class JSProfilerPanel extends ProfilesPanel implements UI.ActionRegistration.ActionDelegate {
constructor() {
const registry = instance;
super('js-profiler', [registry.cpuProfileType], 'profiler.js-toggle-recording');
this.splitWidget().mainWidget()?.setMinimumSize(350, 0);
this.#showDeprecationInfobar();
}
static instance(opts: {
forceNew: boolean|null,
} = {forceNew: null}): JSProfilerPanel {
const {forceNew} = opts;
if (!jsProfilerPanelInstance || forceNew) {
jsProfilerPanelInstance = new JSProfilerPanel();
}
return jsProfilerPanelInstance;
}
#showDeprecationInfobar(): void {
function openFeedbackLink(): void {
Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(
'https://crbug.com/1354548' as Platform.DevToolsPath.UrlString);
}
async function openPerformancePanel(): Promise<void> {
await UI.InspectorView.InspectorView.instance().showPanel('timeline');
}
const infobar = new UI.Infobar.Infobar(
UI.Infobar.Type.Warning,
/* text */ i18nString(UIStrings.deprecationWarnMsg), /* actions? */
[
{
text: i18nString(UIStrings.feedback),
highlight: false,
delegate: openFeedbackLink,
dismiss: false,
jslogContext: 'feedback',
},
{
text: i18nString(UIStrings.goToPerformancePanel),
highlight: true,
delegate: openPerformancePanel,
dismiss: false,
jslogContext: 'go-to-performance-panel',
},
],
/* disableSetting? */ undefined,
/* isCloseable TODO(crbug.com/1354548) Remove the prop from infobar with JS Profiler deprecation */ false,
'panel-deprecated',
);
infobar.setParentView(this);
this.splitWidget().mainWidget()?.element.prepend(infobar.element);
}
override wasShown(): void {
super.wasShown();
UI.Context.Context.instance().setFlavor(JSProfilerPanel, this);
}
override willHide(): void {
UI.Context.Context.instance().setFlavor(JSProfilerPanel, null);
super.willHide();
}
handleAction(_context: UI.Context.Context, _actionId: string): boolean {
const panel = UI.Context.Context.instance().flavor(JSProfilerPanel);
if (panel instanceof JSProfilerPanel) {
panel.toggleRecord();
} else {
throw new Error('non-null JSProfilerPanel expected!');
}
return true;
}
}
export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
handleAction(context: UI.Context.Context, actionId: string): boolean {
switch (actionId) {
+2 -4
View File
@@ -4,8 +4,6 @@
import * as BottomUpProfileDataGrid from './BottomUpProfileDataGrid.js';
import * as ChildrenProvider from './ChildrenProvider.js';
import * as CPUProfileFlameChart from './CPUProfileFlameChart.js';
import * as CPUProfileView from './CPUProfileView.js';
import * as HeapProfilerPanel from './HeapProfilerPanel.js';
import * as HeapProfileView from './HeapProfileView.js';
import * as HeapSnapshotDataGrids from './HeapSnapshotDataGrids.js';
@@ -16,6 +14,7 @@ import * as HeapTimelineOverview from './HeapTimelineOverview.js';
import * as IsolateSelector from './IsolateSelector.js';
import * as LiveHeapProfileView from './LiveHeapProfileView.js';
import * as ProfileDataGrid from './ProfileDataGrid.js';
import * as ProfileFlameChart from './ProfileFlameChartDataProvider.js';
import * as ProfileHeader from './ProfileHeader.js';
import * as ProfileLauncherView from './ProfileLauncherView.js';
import * as ProfileSidebarTreeElement from './ProfileSidebarTreeElement.js';
@@ -27,8 +26,6 @@ import * as TopDownProfileDataGrid from './TopDownProfileDataGrid.js';
export {
BottomUpProfileDataGrid,
ChildrenProvider,
CPUProfileFlameChart,
CPUProfileView,
HeapProfilerPanel,
HeapProfileView,
HeapSnapshotDataGrids,
@@ -39,6 +36,7 @@ export {
IsolateSelector,
LiveHeapProfileView,
ProfileDataGrid,
ProfileFlameChart,
ProfileHeader,
ProfileLauncherView,
ProfileSidebarTreeElement,
+1 -1
View File
@@ -147,7 +147,7 @@ devtools_entrypoint("bundle") {
"../../testing/*",
"../../ui/components/docs/performance_panel/*",
"../input/*",
"../js_profiler/*",
"../js_timeline/*",
"../lighthouse/*",
"../recorder/*",
"./track_appenders:unittests",
@@ -73,14 +73,6 @@ async function loadTimelineModule(): Promise<typeof Timeline> {
return loadedTimelineModule;
}
// The profiler module is imported here because the js profiler tab is implemented
// in the profiler module. Since the tab doesn't belong to all apps that extend
// the shell app, it cannot be registered in profiler's meta file, as profiler is
// part of the shell app, and thus all of the extensions registered in profiler
// belong to all apps that extend from shell.
// Instead, we register the extensions for the js profiler tab in panels/timeline/ and
// js_profiler/ so that the tab is available only in the apps it belongs to.
function maybeRetrieveContextTypes<T = unknown>(getClassCallBack: (timelineModule: typeof Timeline) => T[]): T[] {
if (loadedTimelineModule === undefined) {
return [];