Closed Bug 1087877 Opened 10 years ago Closed 10 years ago

[timeline] user should be able to filter out any type of marker

Categories

(DevTools :: Performance Tools (Profiler/Timeline), defect)

x86_64
All
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED
Firefox 37

People

(Reporter: paul, Assigned: paul)

References

Details

Attachments

(1 file, 5 obsolete files)

No description provided.
Attached patch v0.1 (obsolete) (deleted) — Splinter Review
Victor, I need advice. Once the list of visible markers has changed, I want to update the overview. Not drawing the markers is easy (I just update the local blueprint), but I'm not sure about how to resize the overview. I can destroy and rebuild the overview, that sounds easy. But maybe you'd think of a cleaner way to do that (that would mean digging into Graphs.jsm). Attached the WIP patch.
Assignee: nobody → paul
Status: NEW → ASSIGNED
Flags: needinfo?(vporof)
Comment on attachment 8523810 [details] [diff] [review] v0.1 Review of attachment 8523810 [details] [diff] [review]: ----------------------------------------------------------------- ::: browser/devtools/timeline/timeline.js @@ +438,5 @@ > this.waterfall.recalculateBounds(); > this.updateWaterfall(); > + }, > + > + _onVisibleMarkersChanged: function(e) { Nit: document even the private functions. @@ +445,5 @@ > + for (let item of items) { > + if (item.hasAttribute("checked")) { > + visibleMarkers.push(item.getAttribute("marker-type")); > + } > + } Instead of all these crazy for loops, why not just let visibleMarkers = Array.map($$("#timelineFilterPopup > [marker-type][checked]"), e => e.getAttribute("marker-type")); @@ +447,5 @@ > + visibleMarkers.push(item.getAttribute("marker-type")); > + } > + } > + let str = JSON.stringify(visibleMarkers); > + Services.prefs.setCharPref("devtools.timeline.visibleMarkers", str); We're trying to use the Prefs helper everywhere. E.g. http://dxr.mozilla.org/mozilla-central/source/browser/devtools/profiler/profiler.js#217 To set a pref, Prefs.visibleMarkers = str; @@ +457,5 @@ > + let popup = $("#timelineFilterPopup"); > + let button = $("#filter-button"); > + > + popup.addEventListener("popupshowing", () => button.setAttribute("open", "true")); > + popup.addEventListener("popuphiding", () => button.removeAttribute("open", "true")); Don't use a second argument for removeAttribute. @@ +459,5 @@ > + > + popup.addEventListener("popupshowing", () => button.setAttribute("open", "true")); > + popup.addEventListener("popuphiding", () => button.removeAttribute("open", "true")); > + > + let visibleMarkers = Services.prefs.getCharPref("devtools.timeline.visibleMarkers"); Prefs @@ +460,5 @@ > + popup.addEventListener("popupshowing", () => button.setAttribute("open", "true")); > + popup.addEventListener("popuphiding", () => button.removeAttribute("open", "true")); > + > + let visibleMarkers = Services.prefs.getCharPref("devtools.timeline.visibleMarkers"); > + visibleMarkers = JSON.parse(visibleMarkers); You should handle the case when the parsing fails, because users can manually edit these prefs. @@ +470,5 @@ > + menuitem.setAttribute("closemenu", "none"); > + menuitem.setAttribute("type", "checkbox"); > + menuitem.setAttribute("marker-type", type); > + > + this._onVisibleMarkersChanged = this._onVisibleMarkersChanged.bind(this); Don't bind this function on every iteration of the loop. @@ +473,5 @@ > + > + this._onVisibleMarkersChanged = this._onVisibleMarkersChanged.bind(this); > + menuitem.addEventListener("command", this._onVisibleMarkersChanged); > + > + if (visibleMarkers.indexOf(type) > -1) { Uber nit: use != instead of >, it makes it more obvious. ::: browser/devtools/timeline/timeline.xul @@ +31,5 @@ > tooltiptext="&timelineUI.recordButton.tooltip;"/> > + <toolbarbutton id="filter-button" > + popup="timelineFilterPopup" > + class="devtools-toolbarbutton" > + tooltiptext="xxx"/> Don't forget to localize this. ::: browser/devtools/timeline/widgets/markers-overview.js @@ +62,5 @@ > }); > } > > MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, { > + fixedHeight: OVERVIEW_HEADER_HEIGHT + OVERVIEW_ROW_HEIGHT * 5, This 5 should be a const somewhere. @@ +82,5 @@ > this._lastGroup = Math.max(this._lastGroup, blueprint[type].group); > } > }, > > + setVisibleMarkers: function(visibleMarkers) { Nit: document this. @@ +90,5 @@ > + filteredBluePrint[type] = TIMELINE_BLUEPRINT[type]; > + } > + } > + this.setBlueprint(filteredBluePrint); > + this.buildGraphImage(); Yeah, you'll always have to do this. The canvas itself needs to be resized, and that will nuke the context, so there's no way to avoid this. @@ +121,5 @@ > // draw all markers sharing the same style at once. > > for (let marker of markers) { > + if (this._paintBatches.has(marker.name)) { > + this._paintBatches.get(marker.name).batch.push(marker); This does a double lookup in the paintBatches map, which can be slow. Please rewrite this as for (let marker of markers) { let storeForMarkerType = this._paintBatches.get(marker.name); if (storeForMarkerType) { storeForMarkerType.batch.push(marker); } } ::: browser/devtools/timeline/widgets/waterfall.js @@ +134,5 @@ > if (e.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) { > e.preventDefault(); > this.selectNearestRow(this._selectedRow + WATERFALL_ROWCOUNT_ONPAGEUPDOWN); > } > + }, false); Eh? You probably want to change this in another patch? @@ +355,5 @@ > selectNearestRow: function(idx) { > if (idx < 0) { > idx = 0; > } > + if (!this._listContents.querySelector(".waterfall-marker-container:not([is-spacer])")) { This is pretty ugly. I'll need to review your other patch as well.
Attachment #8523810 - Flags: feedback+
(In reply to Paul Rouget [:paul] (slow to respond. Ping me on IRC) from comment #1) > Created attachment 8523810 [details] [diff] [review] > v0.1 > > Victor, I need advice. Once the list of visible markers has changed, I want > to update the overview. Not drawing the markers is easy (I just update the > local blueprint), but I'm not sure about how to resize the overview. I can > destroy and rebuild the overview, that sounds easy. But maybe you'd think of > a cleaner way to do that (that would mean digging into Graphs.jsm). > > Attached the WIP patch. tl; dr: Yeah, you'll always have to do this. The canvas itself needs to be resized, and that will nuke the context, so there's no way to avoid this.
Flags: needinfo?(vporof)
Attached patch v0.2 (obsolete) (deleted) — Splinter Review
I do 2 things in this patch I'm not happy with: - destroying the overview; - the .sort().reduce().reduce() magic in _getFilteredBluePrint. What do you recommend?
Attachment #8523810 - Attachment is obsolete: true
Attachment #8527451 - Flags: feedback?(vporof)
Comment on attachment 8527451 [details] [diff] [review] v0.2 Review of attachment 8527451 [details] [diff] [review]: ----------------------------------------------------------------- ::: browser/devtools/timeline/timeline.js @@ +495,5 @@ > + let filteredBluePrint = bluePrintAsArray.reduce((p,c) => { > + p[c.type] = c.value; > + return p; > + }, {}); > + return filteredBluePrint; This is fantastically convoluted, and unfortunately for good reason. However, I'd write it like so: let filteredBlueprint = Cu.cloneInto(TIMELINE_BLUEPRINT, {}); let maybeRemovedGroups = new Set(); let removedGroups = new Set(); // 1. Remove hidden markers from the blueprint. for (let hiddenMarkerName of hiddenMarkers) { maybeRemovedGroups.add(filteredBlueprint[hiddenMarkerName].group); delete filteredBluePrint[hiddenMarkerName]; } // 2. Get a list of all the groups that will be removed. for (let removedGroup of maybeRemovedGroups) { let markerNames = Object.keys(filteredBluePrint); let allGroupsRemoved = markerNames.every(e => filteredBlueprint[e].group != removedGroup); if (allGroupsRemoved) { removedGroups.add(removedGroup); } } // 3. Offset groups. for (let removedGroup of removedGroups) { for (let [, markerDetails] of Iterator(filteredBlueprint)) { if (markerDetails.group > removedGroup) { markerDetails.group--; } } } It's a bit shorter and easier to digest IMHO. @@ +504,5 @@ > + * and overview. > + */ > + _onHiddenMarkersChanged: Task.async(function(e) { > + let hiddenMarkers = Array.map($$("#timelineFilterPopup > [marker-type]:not([checked])"), > + e => e.getAttribute("marker-type")); Nit: let menuItems = $$("#timelineFilterPopup > [marker-type]:not([checked])"); let hiddenMarkers = Array.map(menuItems, e => e.getAttribute("marker-type")); @@ +532,5 @@ > + let markers = TimelineController.getMarkers(); > + this.markersOverview.setData({ interval, markers }); > + this.markersOverview.selectionEnabled = true; > + this.markersOverview.setSelection(selection); > + } This is indeed quite gross. All you need to do is this.markersOverview.setBlueprint(blueprint); this.markersOverview.refresh({ force: true }); and add a options param in AbstractCanvasGraph.prototype.refresh to force refresh even if the dimensions haven't changed. @@ +547,5 @@ > + popup.addEventListener("popuphiding", () => button.removeAttribute("open")); > + > + this._onHiddenMarkersChanged = this._onHiddenMarkersChanged.bind(this); > + > + for (let type in TIMELINE_BLUEPRINT) { Nit: for (let [markerName, markerDetails] of Iterator(TIMELINE_BLUEPRINT)) { ... } for a nicer loop and better variable names. ::: browser/devtools/timeline/widgets/markers-overview.js @@ +66,5 @@ > selectionLineColor: OVERVIEW_SELECTION_LINE_COLOR, > selectionBackgroundColor: OVERVIEW_SELECTION_BACKGROUND_COLOR, > selectionStripesColor: OVERVIEW_SELECTION_STRIPES_COLOR, > > + get fixedHeight() { Nit: add a comment describing how this is dependent on a blueprint being set beforehand and the relationship to groups. ::: browser/devtools/timeline/widgets/waterfall.js @@ +103,5 @@ > this._buildMarkers(this._listContents, markers, startTime, endTime, dataScale); > this.selectRow(this._selectedRowIdx); > }, > > + setBlueprint: function(blueprint) { Nit: document all methods, like for markers-overview.js
Attachment #8527451 - Flags: feedback?(vporof) → feedback+
Attached patch v1 (obsolete) (deleted) — Splinter Review
Attachment #8527451 - Attachment is obsolete: true
Attachment #8534816 - Flags: review?(vporof)
Comment on attachment 8534816 [details] [diff] [review] v1 Review of attachment 8534816 [details] [diff] [review]: ----------------------------------------------------------------- Great success ::: browser/devtools/timeline/test/browser_timeline_filters.js @@ +40,5 @@ > + ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker"); > + > + let heightBefore = overview.fixedHeight; > + EventUtils.synthesizeMouseAtCenter(menuItem1, {type: "mouseup"}, panel.panelWin); > + yield nextTick(); Are you using this to wait for an animation frame on the canvas? This might be flimsy, but we'll see.
Attachment #8534816 - Flags: review?(vporof) → review+
(In reply to Victor Porof [:vporof][:vp] from comment #9) > Comment on attachment 8534816 [details] [diff] [review] > v1 > > Review of attachment 8534816 [details] [diff] [review]: > ----------------------------------------------------------------- > > Great success > > ::: browser/devtools/timeline/test/browser_timeline_filters.js > @@ +40,5 @@ > > + ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker"); > > + > > + let heightBefore = overview.fixedHeight; > > + EventUtils.synthesizeMouseAtCenter(menuItem1, {type: "mouseup"}, panel.panelWin); > > + yield nextTick(); > > Are you using this to wait for an animation frame on the canvas? This might > be flimsy, but we'll see. No reason. But there's a failure. And I think it's because of how I "hacked" the menuitems to add the bullet.
Attached patch v1.1 (obsolete) (deleted) — Splinter Review
I had to change a bit how menuitems are built. Wrapping them in hboxes only worked on Windows, and I think it was the reason of tbpl failures on Mac. https://tbpl.mozilla.org/?tree=Try&rev=748c235ff6c9
Attachment #8534816 - Attachment is obsolete: true
Attachment #8536402 - Flags: review+
Attached patch v1.2 (obsolete) (deleted) — Splinter Review
Attachment #8536402 - Attachment is obsolete: true
Attachment #8536554 - Flags: review+
Keywords: checkin-needed
Flags: in-testsuite+
Keywords: checkin-needed
Whiteboard: [fixed-in-fx-team]
Attached patch 1.3 (deleted) — Splinter Review
Attachment #8536554 - Attachment is obsolete: true
Attachment #8543719 - Flags: review+
Status: ASSIGNED → RESOLVED
Closed: 10 years ago
Resolution: --- → FIXED
Target Milestone: --- → Firefox 37
Depends on: 1118299
Sorry for the spam. Moving bugs to Firefox :: Developer Tools: Performance Tools (Profiler/Timeline). dkl
Component: Developer Tools: Timeline → Developer Tools: Performance Tools (Profiler/Timeline)
Product: Firefox → DevTools
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: