+2013-02-28 Alexei Filippov <alph@chromium.org>
+
+ Web Inspector: Move profiler tools into separate panels
+ https://bugs.webkit.org/show_bug.cgi?id=109832
+
+ Reviewed by Yury Semikhatsky.
+
+ This is a first part of the fix that puts each profiler tool into a separate panel.
+ The fix introduces separate panels for each profiler type.
+ There are now six panel (including experimental):
+ 1. JS CPU profiler
+ 2. CSS Selector profiler
+ 3. JS Heap profiler
+ 4. Canvas profier
+ 5. Native memory snapshots
+ 6. Native memory distribution
+ The new functionality is put behind experimental flag.
+
+ * inspector/front-end/ProfileLauncherView.js:
+ (WebInspector.ProfileLauncherView):
+ (WebInspector.ProfileLauncherView.prototype.addProfileType):
+ * inspector/front-end/ProfilesPanel.js:
+ (WebInspector.ProfileHeader.prototype.view):
+ (WebInspector.ProfileHeader.prototype.createView):
+ (WebInspector.ProfilesPanel):
+ (WebInspector.ProfilesPanel.prototype._handleContextMenuEvent):
+ (WebInspector.ProfilesPanel.prototype._addProfileHeader):
+ (WebInspector.ProfilesPanel.prototype._removeProfileHeader):
+ (WebInspector.ProfilesPanel.prototype._showProfile):
+ (WebInspector.ProfilesPanel.prototype._searchableViews):
+ (WebInspector.ProfileSidebarTreeElement.prototype.handleContextMenuEvent):
+ (WebInspector.ProfileGroupSidebarTreeElement):
+ (WebInspector.ProfileGroupSidebarTreeElement.prototype.onselect):
+ (WebInspector.CPUProfilerPanel):
+ (WebInspector.CSSSelectorProfilerPanel):
+ (WebInspector.HeapProfilerPanel):
+ (WebInspector.CanvasProfilerPanel):
+ (WebInspector.MemoryChartProfilerPanel):
+ (WebInspector.NativeMemoryProfilerPanel):
+ * inspector/front-end/Settings.js:
+ (WebInspector.ExperimentsSettings):
+ * inspector/front-end/inspector.css:
+ (.toolbar-item.cpu-profiler .toolbar-icon):
+ (.toolbar-item.css-profiler .toolbar-icon):
+ (.toolbar-item.heap-profiler .toolbar-icon):
+ (.toolbar-item.canvas-profiler .toolbar-icon):
+ (.toolbar-item.memory-chart-profiler .toolbar-icon):
+ (.toolbar-item.memory-snapshot-profiler .toolbar-icon):
+ * inspector/front-end/inspector.js:
+ (WebInspector._panelDescriptors):
+
2013-02-28 Keishi Hattori <keishi@webkit.org>
Add calendar header for new calendar picker
/**
* @constructor
* @extends {WebInspector.View}
+ * @param {!WebInspector.ProfilesPanel} profilesPanel
+ * @param {boolean} singleProfileMode
*/
-WebInspector.ProfileLauncherView = function(profilesPanel)
+WebInspector.ProfileLauncherView = function(profilesPanel, singleProfileMode)
{
WebInspector.View.call(this);
this._panel = profilesPanel;
+ this._singleProfileMode = singleProfileMode;
this._profileRunning = false;
this.element.addStyleClass("profile-launcher-view");
this._contentElement = this.element.createChild("div", "profile-launcher-view-content");
- var header = this._contentElement.createChild("h1");
- header.textContent = WebInspector.UIString("Select profiling type");
+ if (!singleProfileMode) {
+ var header = this._contentElement.createChild("h1");
+ header.textContent = WebInspector.UIString("Select profiling type");
+ }
this._profileTypeSelectorForm = this._contentElement.createChild("form");
addProfileType: function(profileType)
{
var checked = !this._profileTypeSelectorForm.children.length;
- var labelElement = this._profileTypeSelectorForm.createChild("label");
- labelElement.textContent = profileType.name;
- var optionElement = document.createElement("input");
- labelElement.insertBefore(optionElement, labelElement.firstChild);
- optionElement.type = "radio";
- optionElement.name = "profile-type";
- if (checked) {
- optionElement.checked = checked;
- this.dispatchEventToListeners(WebInspector.ProfileLauncherView.EventTypes.ProfileTypeSelected, profileType);
+ var labelElement;
+ if (this._singleProfileMode)
+ labelElement = this._profileTypeSelectorForm.createChild("h1");
+ else {
+ labelElement = this._profileTypeSelectorForm.createChild("label");
+ labelElement.textContent = profileType.name;
+ var optionElement = document.createElement("input");
+ labelElement.insertBefore(optionElement, labelElement.firstChild);
+ optionElement.type = "radio";
+ optionElement.name = "profile-type";
+ optionElement.style.hidden = true;
+ if (checked) {
+ optionElement.checked = checked;
+ this.dispatchEventToListeners(WebInspector.ProfileLauncherView.EventTypes.ProfileTypeSelected, profileType);
+ }
+ optionElement.addEventListener("change", this._profileTypeChanged.bind(this, profileType), false);
}
- optionElement.addEventListener("change", this._profileTypeChanged.bind(this, profileType), false);
var descriptionElement = labelElement.createChild("p");
descriptionElement.textContent = profileType.description;
var decorationElement = profileType.decorationElement();
if (decorationElement)
labelElement.appendChild(decorationElement);
+ if (this._singleProfileMode)
+ this._profileTypeChanged(profileType);
},
_controlButtonClicked: function()
},
/**
+ * @param {!WebInspector.ProfilesPanel} panel
* @return {!WebInspector.View}
*/
- view: function()
+ view: function(panel)
{
if (!this._view)
- this._view = this.createView(WebInspector.ProfilesPanel._instance);
+ this._view = this.createView(panel);
return this._view;
},
/**
- * @param {WebInspector.ProfilesPanel} profilesPanel
+ * @param {!WebInspector.ProfilesPanel} panel
* @return {!WebInspector.View}
*/
- createView: function(profilesPanel)
+ createView: function(panel)
{
throw new Error("Not implemented.");
},
* @constructor
* @extends {WebInspector.Panel}
* @implements {WebInspector.ContextMenu.Provider}
+ * @param {string=} name
*/
-WebInspector.ProfilesPanel = function()
+WebInspector.ProfilesPanel = function(name)
{
- WebInspector.Panel.call(this, "profiles");
- WebInspector.ProfilesPanel._instance = this;
+ // If the name is not specified the ProfilesPanel works in multi-profile mode.
+ var singleProfileMode = typeof name !== "undefined";
+ name = name || "profiles";
+ WebInspector.Panel.call(this, name);
this.registerRequiredCSS("panelEnablerView.css");
this.registerRequiredCSS("heapProfiler.css");
this.registerRequiredCSS("profilesPanel.css");
this.profilesItemTreeElement = new WebInspector.ProfilesSidebarTreeElement(this);
this.sidebarTree.appendChild(this.profilesItemTreeElement);
+ this._singleProfileMode = singleProfileMode;
this._profileTypesByIdMap = {};
var panelEnablerHeading = WebInspector.UIString("You need to enable profiling before you can use the Profiles panel.");
var panelEnablerDisclaimer = WebInspector.UIString("Enabling profiling will make scripts run slower.");
var panelEnablerButton = WebInspector.UIString("Enable Profiling");
- this.panelEnablerView = new WebInspector.PanelEnablerView("profiles", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
+ this.panelEnablerView = new WebInspector.PanelEnablerView(name, panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
this.panelEnablerView.addEventListener("enable clicked", this.enableProfiler, this);
this.profileViews = document.createElement("div");
this._profilerEnabled = !Capabilities.profilerCausesRecompilation;
- this._launcherView = new WebInspector.ProfileLauncherView(this);
+ this._launcherView = new WebInspector.ProfileLauncherView(this, singleProfileMode);
this._launcherView.addEventListener(WebInspector.ProfileLauncherView.EventTypes.ProfileTypeSelected, this._onProfileTypeSelected, this);
this._reset();
- this._registerProfileType(new WebInspector.CPUProfileType());
- if (!WebInspector.WorkerManager.isWorkerFrontend())
- this._registerProfileType(new WebInspector.CSSSelectorProfileType());
- if (Capabilities.heapProfilerPresent)
- this._registerProfileType(new WebInspector.HeapSnapshotProfileType());
- if (WebInspector.experimentsSettings.nativeMemorySnapshots.isEnabled()) {
- this._registerProfileType(new WebInspector.NativeMemoryProfileType());
- this._registerProfileType(new WebInspector.NativeSnapshotProfileType());
+ if (!singleProfileMode) {
+ this._registerProfileType(new WebInspector.CPUProfileType());
+ if (!WebInspector.WorkerManager.isWorkerFrontend())
+ this._registerProfileType(new WebInspector.CSSSelectorProfileType());
+ if (Capabilities.heapProfilerPresent)
+ this._registerProfileType(new WebInspector.HeapSnapshotProfileType());
+ if (WebInspector.experimentsSettings.nativeMemorySnapshots.isEnabled()) {
+ this._registerProfileType(new WebInspector.NativeSnapshotProfileType());
+ this._registerProfileType(new WebInspector.NativeMemoryProfileType());
+ }
+ if (WebInspector.experimentsSettings.canvasInspection.isEnabled())
+ this._registerProfileType(new WebInspector.CanvasProfileType());
}
- if (WebInspector.experimentsSettings.canvasInspection.isEnabled())
- this._registerProfileType(new WebInspector.CanvasProfileType());
this._createFileSelectorElement();
this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
this._profileTypesByIdMap[profileType.id] = profileType;
this._launcherView.addProfileType(profileType);
profileType.treeElement = new WebInspector.SidebarSectionTreeElement(profileType.treeItemTitle, null, true);
- profileType.treeElement.hidden = true;
+ profileType.treeElement.hidden = !this._singleProfileMode;
this.sidebarTree.appendChild(profileType.treeElement);
profileType.treeElement.childrenListElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
function onAddProfileHeader(event)
if (!element)
return;
if (element.treeElement && element.treeElement.handleContextMenuEvent) {
- element.treeElement.handleContextMenuEvent(event);
+ element.treeElement.handleContextMenuEvent(event, this);
return;
}
if (element !== this.element || event.srcElement === this.sidebarElement) {
group.push(profile);
if (group.length === 2) {
// Make a group TreeElement now that there are 2 profiles.
- group._profilesTreeElement = new WebInspector.ProfileGroupSidebarTreeElement(profile.title);
+ group._profilesTreeElement = new WebInspector.ProfileGroupSidebarTreeElement(this, profile.title);
// Insert at the same index for the first profile of the group.
var index = sidebarParent.children.indexOf(group[0]._profilesTreeElement);
if (!sidebarParent.children.length) {
this.profilesItemTreeElement.select();
this._showLauncherView();
- sidebarParent.hidden = true;
+ sidebarParent.hidden = !this._singleProfileMode;
}
},
if (!profile || profile.isTemporary)
return;
- var view = profile.view();
+ var view = profile.view(this);
if (view === this.visibleView)
return;
// FIXME: allow to choose snapshot if there are several options.
if (profile.maxJSObjectId >= snapshotObjectId) {
this._showProfile(profile);
- profile.view().changeView(viewName, function() {
- profile.view().dataGrid.highlightObjectByHeapSnapshotId(snapshotObjectId);
+ var view = profile.view(this);
+ view.changeView(viewName, function() {
+ view.dataGrid.highlightObjectByHeapSnapshotId(snapshotObjectId);
});
break;
}
var profiles = this._getAllProfiles();
var searchableViews = [];
for (var i = 0; i < profiles.length; ++i) {
- var view = profiles[i].view();
+ var view = profiles[i].view(this);
if (view.performSearch)
searchableViews.push(view)
}
/**
* @param {!Event} event
+ * @param {!WebInspector.ProfilesPanel} panel
*/
- handleContextMenuEvent: function(event)
+ handleContextMenuEvent: function(event, panel)
{
var profile = this.profile;
var contextMenu = new WebInspector.ContextMenu(event);
- var profilesPanel = WebInspector.ProfilesPanel._instance;
// FIXME: use context menu provider
if (profile.canSaveToFile()) {
contextMenu.appendItem(WebInspector.UIString("Save Heap Snapshot\u2026"), profile.saveToFile.bind(profile));
- contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), profilesPanel._fileSelectorElement.click.bind(profilesPanel._fileSelectorElement));
+ contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), panel._fileSelectorElement.click.bind(panel._fileSelectorElement));
contextMenu.appendItem(WebInspector.UIString("Delete Heap Snapshot"), this.ondelete.bind(this));
} else {
- contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), profilesPanel._fileSelectorElement.click.bind(profilesPanel._fileSelectorElement));
+ contextMenu.appendItem(WebInspector.UIString("Load Heap Snapshot\u2026"), panel._fileSelectorElement.click.bind(panel._fileSelectorElement));
contextMenu.appendItem(WebInspector.UIString("Delete profile"), this.ondelete.bind(this));
}
contextMenu.show();
/**
* @constructor
* @extends {WebInspector.SidebarTreeElement}
+ * @param {WebInspector.ProfilesPanel} panel
* @param {string} title
* @param {string=} subtitle
*/
-WebInspector.ProfileGroupSidebarTreeElement = function(title, subtitle)
+WebInspector.ProfileGroupSidebarTreeElement = function(panel, title, subtitle)
{
WebInspector.SidebarTreeElement.call(this, "profile-group-sidebar-tree-item", title, subtitle, null, true);
+ this._panel = panel;
}
WebInspector.ProfileGroupSidebarTreeElement.prototype = {
onselect: function()
{
if (this.children.length > 0)
- WebInspector.ProfilesPanel._instance._showProfile(this.children[this.children.length - 1].profile);
+ this._panel._showProfile(this.children[this.children.length - 1].profile);
},
__proto__: WebInspector.SidebarTreeElement.prototype
__proto__: WebInspector.SidebarTreeElement.prototype
}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfilesPanel}
+ */
+WebInspector.CPUProfilerPanel = function()
+{
+ WebInspector.ProfilesPanel.call(this, "cpu-profiler");
+ this._registerProfileType(new WebInspector.CPUProfileType());
+}
+
+WebInspector.CPUProfilerPanel.prototype.__proto__ = WebInspector.ProfilesPanel.prototype;
+
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfilesPanel}
+ */
+WebInspector.CSSSelectorProfilerPanel = function()
+{
+ WebInspector.ProfilesPanel.call(this, "css-profiler");
+ this._registerProfileType(new WebInspector.CSSSelectorProfileType());
+}
+
+WebInspector.CSSSelectorProfilerPanel.prototype.__proto__ = WebInspector.ProfilesPanel.prototype;
+
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfilesPanel}
+ */
+WebInspector.HeapProfilerPanel = function()
+{
+ WebInspector.ProfilesPanel.call(this, "heap-profiler");
+ this._registerProfileType(new WebInspector.HeapSnapshotProfileType());
+}
+
+WebInspector.HeapProfilerPanel.prototype.__proto__ = WebInspector.ProfilesPanel.prototype;
+
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfilesPanel}
+ */
+WebInspector.CanvasProfilerPanel = function()
+{
+ WebInspector.ProfilesPanel.call(this, "canvas-profiler");
+ this._registerProfileType(new WebInspector.CanvasProfileType());
+}
+
+WebInspector.CanvasProfilerPanel.prototype.__proto__ = WebInspector.ProfilesPanel.prototype;
+
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfilesPanel}
+ */
+WebInspector.MemoryChartProfilerPanel = function()
+{
+ WebInspector.ProfilesPanel.call(this, "memory-chart-profiler");
+ this._registerProfileType(new WebInspector.NativeMemoryProfileType());
+}
+
+WebInspector.MemoryChartProfilerPanel.prototype.__proto__ = WebInspector.ProfilesPanel.prototype;
+
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfilesPanel}
+ */
+WebInspector.NativeMemoryProfilerPanel = function()
+{
+ WebInspector.ProfilesPanel.call(this, "memory-snapshot-profiler");
+ this._registerProfileType(new WebInspector.NativeSnapshotProfileType());
+}
+
+WebInspector.NativeMemoryProfilerPanel.prototype.__proto__ = WebInspector.ProfilesPanel.prototype;
+
+
importScript("ProfileDataGridTree.js");
importScript("BottomUpProfileDataGridTree.js");
importScript("CPUProfileView.js");
var audits = new WebInspector.PanelDescriptor("audits", WebInspector.UIString("Audits"), "AuditsPanel", "AuditsPanel.js");
var console = new WebInspector.PanelDescriptor("console", WebInspector.UIString("Console"), "ConsolePanel");
var allDescriptors = [elements, resources, network, scripts, timeline, profiles, audits, console];
+ var allProfilers = [profiles];
+ if (WebInspector.experimentsSettings.separateProfilers.isEnabled()) {
+ allProfilers = [];
+ allProfilers.push(new WebInspector.PanelDescriptor("cpu-profiler", WebInspector.UIString("CPU Profiler"), "CPUProfilerPanel", "ProfilesPanel.js"));
+ if (!WebInspector.WorkerManager.isWorkerFrontend())
+ allProfilers.push(new WebInspector.PanelDescriptor("css-profiler", WebInspector.UIString("CSS Profiler"), "CSSSelectorProfilerPanel", "ProfilesPanel.js"));
+ if (Capabilities.heapProfilerPresent)
+ allProfilers.push(new WebInspector.PanelDescriptor("heap-profiler", WebInspector.UIString("Heap Profiler"), "HeapProfilerPanel", "ProfilesPanel.js"));
+ if (!WebInspector.WorkerManager.isWorkerFrontend() && WebInspector.experimentsSettings.canvasInspection.isEnabled())
+ allProfilers.push(new WebInspector.PanelDescriptor("canvas-profiler", WebInspector.UIString("Canvas Profiler"), "CanvasProfilerPanel", "ProfilesPanel.js"));
+ if (!WebInspector.WorkerManager.isWorkerFrontend() && WebInspector.experimentsSettings.nativeMemorySnapshots.isEnabled()) {
+ allProfilers.push(new WebInspector.PanelDescriptor("memory-chart-profiler", WebInspector.UIString("Memory Distribution"), "MemoryChartProfilerPanel", "ProfilesPanel.js"));
+ allProfilers.push(new WebInspector.PanelDescriptor("memory-snapshot-profiler", WebInspector.UIString("Memory Snapshots"), "NativeMemoryProfilerPanel", "ProfilesPanel.js"));
+ }
+ Array.prototype.splice.bind(allDescriptors, allDescriptors.indexOf(profiles), 1).apply(null, allProfilers);
+ }
var panelDescriptors = [];
if (WebInspector.WorkerManager.isWorkerFrontend()) {
panelDescriptors.push(scripts);
panelDescriptors.push(timeline);
- panelDescriptors.push(profiles);
+ panelDescriptors = panelDescriptors.concat(allProfilers);
panelDescriptors.push(console);
return panelDescriptors;
}