Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: Source/devtools/front_end/timeline/TimelineTreeView.js

Issue 1298543002: DevTools: Support Top-Down tree view on Timeline (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: addressing comments. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/devtools/front_end/timeline/TimelinePanel.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @constructor 6 * @constructor
7 * @extends {WebInspector.VBox} 7 * @extends {WebInspector.VBox}
8 * @param {!WebInspector.TimelineModel} model 8 * @param {!WebInspector.TimelineModel} model
9 */ 9 */
10 WebInspector.TimelineTreeView = function(model) 10 WebInspector.TimelineTreeView = function(model)
11 { 11 {
12 WebInspector.VBox.call(this); 12 WebInspector.VBox.call(this);
13 this.element.classList.add("timeline-tree-view"); 13 this.element.classList.add("timeline-tree-view");
14 14
15 this._model = model; 15 this._model = model;
16 var columns = []; 16 var columns = [];
17 columns.push({id: "self", title: WebInspector.UIString("Self Time"), width: "120px", sort: WebInspector.DataGrid.Order.Descending, sortable: true}); 17 columns.push({id: "self", title: WebInspector.UIString("Self Time"), width: "120px", sort: WebInspector.DataGrid.Order.Descending, sortable: true});
18 columns.push({id: "total", title: WebInspector.UIString("Total Time"), width : "120px", sort: WebInspector.DataGrid.Order.Descending, sortable: true}); 18 columns.push({id: "total", title: WebInspector.UIString("Total Time"), width : "120px", sortable: true});
19 columns.push({id: "activity", title: WebInspector.UIString("Activity"), disc losure: true, sortable: true}); 19 columns.push({id: "activity", title: WebInspector.UIString("Activity"), disc losure: true, sortable: true});
20 20
21 var nonessentialEvents = [
22 WebInspector.TimelineModel.RecordType.EventDispatch,
23 WebInspector.TimelineModel.RecordType.FunctionCall,
24 WebInspector.TimelineModel.RecordType.TimerFire
25 ];
21 this._filters = [ 26 this._filters = [
22 WebInspector.TimelineUIUtils.hiddenEventsFilter(), 27 WebInspector.TimelineUIUtils.hiddenEventsFilter(),
28 new WebInspector.ExclusiveTraceEventNameFilter(nonessentialEvents),
23 new WebInspector.ExcludeTopLevelFilter() 29 new WebInspector.ExcludeTopLevelFilter()
24 ]; 30 ];
25 31
26 this._groupBySetting = WebInspector.settings.createSetting("timelineTreeGrou pBy", WebInspector.TimelineTreeView.GroupBy.None); 32 this._groupBySetting = WebInspector.settings.createSetting("timelineTreeGrou pBy", WebInspector.TimelineTreeView.GroupBy.None);
27 33
28 this.dataGrid = new WebInspector.SortableDataGrid(columns); 34 this.dataGrid = new WebInspector.SortableDataGrid(columns);
29 this.dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sortingChanged, this); 35 this.dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sortingChanged, this);
30 36
31 this._createToolbar(); 37 this._createToolbar();
32 38
33 this.dataGrid.show(this.element); 39 this.dataGrid.show(this.element);
34 } 40 }
35 41
36 /** 42 /**
37 * @enum {string} 43 * @enum {string}
38 */ 44 */
45 WebInspector.TimelineTreeView.Mode = {
46 TopDown: "TopDown",
47 BottomUp: "BottomUp"
48 }
49
50 /**
51 * @enum {string}
52 */
39 WebInspector.TimelineTreeView.GroupBy = { 53 WebInspector.TimelineTreeView.GroupBy = {
40 None: "None", 54 None: "None",
41 Domain: "Domain", 55 Domain: "Domain",
42 DomainSecondLevel: "DomainSecondLevel", 56 DomainSecondLevel: "DomainSecondLevel",
43 URL: "URL" 57 URL: "URL"
44 } 58 }
45 59
46 WebInspector.TimelineTreeView.prototype = { 60 WebInspector.TimelineTreeView.prototype = {
47 /** 61 /**
48 * @param {!WebInspector.TimelineSelection} selection 62 * @param {!WebInspector.TimelineSelection} selection
49 */ 63 */
50 updateContents: function(selection) 64 updateContents: function(selection)
51 { 65 {
52 this._startTime = selection.startTime(); 66 this._startTime = selection.startTime();
53 this._endTime = selection.endTime(); 67 this._endTime = selection.endTime();
54 this._refreshRecords(); 68 this._refreshTree();
55 }, 69 },
56 70
57 _createToolbar: function() 71 _createToolbar: function()
58 { 72 {
59 this._panelToolbar = new WebInspector.Toolbar(this.element); 73 var panelToolbar = new WebInspector.Toolbar(this.element);
74 panelToolbar.appendToolbarItem(new WebInspector.ToolbarText(WebInspector .UIString("View")));
75
76 this._modeCombobox = new WebInspector.ToolbarComboBox(this._onTreeModeCh anged.bind(this));
77 this._modeCombobox.addOption(this._modeCombobox.createOption(WebInspecto r.UIString("Costly Functions"), "", WebInspector.TimelineTreeView.Mode.BottomUp) );
78 this._modeCombobox.addOption(this._modeCombobox.createOption(WebInspecto r.UIString("Costly Entrypoints"), "", WebInspector.TimelineTreeView.Mode.TopDown ));
79 panelToolbar.appendToolbarItem(this._modeCombobox);
80
60 this._groupByCombobox = new WebInspector.ToolbarComboBox(this._onGroupBy Changed.bind(this)); 81 this._groupByCombobox = new WebInspector.ToolbarComboBox(this._onGroupBy Changed.bind(this));
61 /** 82 /**
62 * @param {string} name 83 * @param {string} name
63 * @param {string} id 84 * @param {string} id
64 * @this {WebInspector.TimelineTreeView} 85 * @this {WebInspector.TimelineTreeView}
65 */ 86 */
66 function addOption(name, id) 87 function addGroupingOption(name, id)
67 { 88 {
68 var option = this._groupByCombobox.createOption(name, "", id); 89 var option = this._groupByCombobox.createOption(name, "", id);
69 this._groupByCombobox.addOption(option); 90 this._groupByCombobox.addOption(option);
70 if (id === this._groupBySetting.get()) 91 if (id === this._groupBySetting.get())
71 this._groupByCombobox.select(option); 92 this._groupByCombobox.select(option);
72 } 93 }
73 addOption.call(this, WebInspector.UIString("No Grouping"), WebInspector. TimelineTreeView.GroupBy.None); 94 panelToolbar.appendToolbarItem(new WebInspector.ToolbarText(WebInspector .UIString("Group by")));
74 addOption.call(this, WebInspector.UIString("Group by Domain"), WebInspec tor.TimelineTreeView.GroupBy.Domain); 95 addGroupingOption.call(this, WebInspector.UIString("Function"), WebInspe ctor.TimelineTreeView.GroupBy.None);
75 addOption.call(this, WebInspector.UIString("Group by Domain (2nd Level)" ), WebInspector.TimelineTreeView.GroupBy.DomainSecondLevel); 96 addGroupingOption.call(this, WebInspector.UIString("Domain"), WebInspect or.TimelineTreeView.GroupBy.Domain);
76 addOption.call(this, WebInspector.UIString("Group by URL"), WebInspector .TimelineTreeView.GroupBy.URL); 97 addGroupingOption.call(this, WebInspector.UIString("Domain (2nd Level)") , WebInspector.TimelineTreeView.GroupBy.DomainSecondLevel);
77 this._panelToolbar.appendToolbarItem(this._groupByCombobox); 98 addGroupingOption.call(this, WebInspector.UIString("URL"), WebInspector. TimelineTreeView.GroupBy.URL);
99 panelToolbar.appendToolbarItem(this._groupByCombobox);
100 },
101
102 _onTreeModeChanged: function()
103 {
104 this._refreshTree();
78 }, 105 },
79 106
80 _onGroupByChanged: function() 107 _onGroupByChanged: function()
81 { 108 {
82 this._groupBySetting.set(this._groupByCombobox.selectedOption().value); 109 this._groupBySetting.set(this._groupByCombobox.selectedOption().value);
83 this._refreshRecords(); 110 this._refreshTree();
84 }, 111 },
85 112
86 _refreshRecords: function() 113 _refreshTree: function()
87 { 114 {
88 var groupBy = this._groupBySetting.get();
89 var groupNodes = new Map();
90
91 /**
92 * @param {string} id
93 * @return {!WebInspector.TimelineModel.ProfileTreeNode}
94 */
95 function groupNodeById(id)
96 {
97 var node = groupNodes.get(id);
98 if (!node) {
99 node = new WebInspector.TimelineModel.ProfileTreeNode();
100 node.name = id || WebInspector.UIString("(unknown)");
101 node.selfTime = 0;
102 node.totalTime = 0;
103 groupNodes.set(id, node);
104 }
105 return node;
106 }
107
108 /**
109 * @return {?WebInspector.TimelineModel.ProfileTreeNode}
110 */
111 function groupByNone()
112 {
113 return null;
114 }
115
116 /**
117 * @param {!WebInspector.TimelineModel.ProfileTreeNode} node
118 * @return {?WebInspector.TimelineModel.ProfileTreeNode}
119 */
120 function groupByURL(node)
121 {
122 return groupNodeById(WebInspector.TimelineTreeView.eventURL(node.eve nt) || "");
123 }
124
125 /**
126 * @param {!WebInspector.TimelineModel.ProfileTreeNode} node
127 * @return {?WebInspector.TimelineModel.ProfileTreeNode}
128 */
129 function groupByDomain(node)
130 {
131 var parsedURL = (WebInspector.TimelineTreeView.eventURL(node.event) || "").asParsedURL();
132 var domain = parsedURL && parsedURL.host || "";
133 return groupNodeById(domain);
134 }
135
136 /**
137 * @param {!WebInspector.TimelineModel.ProfileTreeNode} node
138 * @return {?WebInspector.TimelineModel.ProfileTreeNode}
139 */
140 function groupByDomainSecondLevel(node)
141 {
142 var parsedURL = (WebInspector.TimelineTreeView.eventURL(node.event) || "").asParsedURL();
143 if (!parsedURL)
144 return groupNodeById("");
145 if (/^[.0-9]+$/.test(parsedURL.host))
146 return groupNodeById(parsedURL.host)
147 var domainMatch = /([^.]*\.)?[^.]*$/.exec(parsedURL.host);
148 return groupNodeById(domainMatch && domainMatch[0] || "");
149 }
150
151 /**
152 * @param {!WebInspector.TracingModel.Event} e
153 * @return {string}
154 */
155 function eventId(e)
156 {
157 // Function call frames are always groupped by the URL
158 if (e.name === "JSFrame") {
159 var data = e.args["data"];
160 return "f:" + (data["callUID"] || WebInspector.TimelineTreeView. eventURL(e));
161 }
162 // While the rest of events are groupped by the event type
163 // unless the group by URL/Domain mode is on.
164 if (groupBy === WebInspector.TimelineTreeView.GroupBy.URL)
165 return e.name + ":@" + WebInspector.TimelineTreeView.eventURL(e) ;
166 return e.name;
167 }
168
169 var groupByMapper = new Map([
170 [WebInspector.TimelineTreeView.GroupBy.None, groupByNone],
171 [WebInspector.TimelineTreeView.GroupBy.Domain, groupByDomain],
172 [WebInspector.TimelineTreeView.GroupBy.DomainSecondLevel, groupByDom ainSecondLevel],
173 [WebInspector.TimelineTreeView.GroupBy.URL, groupByURL]
174 ]);
175 var topDown = WebInspector.TimelineModel.buildTopDownTree(this._model.ma inThreadEvents(), this._startTime, this._endTime, this._filters, eventId);
176 var bottomUpRoot = WebInspector.TimelineModel.buildBottomUpTree(topDown, groupByMapper.get(groupBy));
177 for (var group of groupNodes)
178 bottomUpRoot.children.set(group[0], group[1]);
179 this.dataGrid.rootNode().removeChildren(); 115 this.dataGrid.rootNode().removeChildren();
180 for (var child of bottomUpRoot.children.values()) { 116 var topDown = WebInspector.TimelineModel.buildTopDownTree(
117 this._model.mainThreadEvents(), this._startTime, this._endTime, this ._filters, WebInspector.TimelineTreeView.eventId);
118 var tree = this._modeCombobox.selectedOption().value === WebInspector.Ti melineTreeView.Mode.TopDown
119 ? this._preformTopDownTreeGrouping(topDown)
120 : this._buildBottomUpTree(topDown);
121 for (var child of tree.children.values()) {
181 // Exclude the idle time off the total calculation. 122 // Exclude the idle time off the total calculation.
182 var gridNode = new WebInspector.TimelineTreeView.GridNode(child, top Down.totalTime); 123 var gridNode = new WebInspector.TimelineTreeView.GridNode(child, top Down.totalTime);
183 this.dataGrid.insertChild(gridNode); 124 this.dataGrid.insertChild(gridNode);
184 } 125 }
185 this._sortingChanged(); 126 this._sortingChanged();
186 }, 127 },
187 128
129 /**
130 * @param {!WebInspector.TimelineModel.ProfileTreeNode} topDownTree
131 * @return {!WebInspector.TimelineModel.ProfileTreeNode}
132 */
133 _preformTopDownTreeGrouping: function(topDownTree)
134 {
135 var nodeToGroupId = this._nodeToGroupIdFunction();
136 if (nodeToGroupId) {
137 this._groupNodes = new Map();
138 for (var node of topDownTree.children.values()) {
139 var groupNode = this._nodeToGroupNode(nodeToGroupId, node);
140 groupNode.selfTime += node.selfTime;
141 groupNode.totalTime += node.totalTime;
142 groupNode.children.set(node.id, node);
143 }
144 topDownTree.children = this._groupNodes;
145 this._groupNodes = null;
146 }
147 return topDownTree;
148 },
149
150 /**
151 * @param {!WebInspector.TimelineModel.ProfileTreeNode} topDownTree
152 * @return {!WebInspector.TimelineModel.ProfileTreeNode}
153 */
154 _buildBottomUpTree: function(topDownTree)
155 {
156 this._groupNodes = new Map();
157 var nodeToGroupId = this._nodeToGroupIdFunction();
158 var nodeToGroupNode = nodeToGroupId ? this._nodeToGroupNode.bind(this, n odeToGroupId) : null;
159 var bottomUpRoot = WebInspector.TimelineModel.buildBottomUpTree(topDownT ree, nodeToGroupNode);
160 for (var group of this._groupNodes)
161 bottomUpRoot.children.set(group[0], group[1]);
162 return bottomUpRoot;
163 },
164
165 /**
166 * @return {?function(!WebInspector.TimelineModel.ProfileTreeNode):string}
167 */
168 _nodeToGroupIdFunction: function()
169 {
170 /**
171 * @param {!WebInspector.TimelineModel.ProfileTreeNode} node
172 * @return {string}
173 */
174 function groupByURL(node)
175 {
176 return WebInspector.TimelineTreeView.eventURL(node.event) || "";
177 }
178
179 /**
180 * @param {!WebInspector.TimelineModel.ProfileTreeNode} node
181 * @return {string}
182 */
183 function groupByDomain(node)
184 {
185 var parsedURL = (WebInspector.TimelineTreeView.eventURL(node.event) || "").asParsedURL();
186 return parsedURL && parsedURL.host || "";
187 }
188
189 /**
190 * @param {!WebInspector.TimelineModel.ProfileTreeNode} node
191 * @return {string}
192 */
193 function groupByDomainSecondLevel(node)
194 {
195 var parsedURL = (WebInspector.TimelineTreeView.eventURL(node.event) || "").asParsedURL();
196 if (!parsedURL)
197 return "";
198 if (/^[.0-9]+$/.test(parsedURL.host))
199 return parsedURL.host;
200 var domainMatch = /([^.]*\.)?[^.]*$/.exec(parsedURL.host);
201 return domainMatch && domainMatch[0] || "";
202 }
203
204 var groupByMap = /** @type {!Map<!WebInspector.TimelineTreeView.GroupBy, ?function(!WebInspector.TimelineModel.ProfileTreeNode):string>} */ (new Map([
205 [WebInspector.TimelineTreeView.GroupBy.None, null],
206 [WebInspector.TimelineTreeView.GroupBy.Domain, groupByDomain],
207 [WebInspector.TimelineTreeView.GroupBy.DomainSecondLevel, groupByDom ainSecondLevel],
208 [WebInspector.TimelineTreeView.GroupBy.URL, groupByURL]
209 ]));
210 return groupByMap.get(this._groupBySetting.get()) || null;
211 },
212
213 /**
214 * @param {function(!WebInspector.TimelineModel.ProfileTreeNode):string} nod eToGroupId
215 * @param {!WebInspector.TimelineModel.ProfileTreeNode} node
216 * @return {!WebInspector.TimelineModel.ProfileTreeNode}
217 */
218 _nodeToGroupNode: function(nodeToGroupId, node)
219 {
220 var id = nodeToGroupId(node);
221 var groupNode = this._groupNodes.get(id);
222 if (!groupNode) {
223 groupNode = new WebInspector.TimelineModel.ProfileTreeNode();
224 groupNode.name = id || WebInspector.UIString("(unattributed)");
225 groupNode.selfTime = 0;
226 groupNode.totalTime = 0;
227 groupNode.children = new Map();
228 this._groupNodes.set(id, groupNode);
229 }
230 return groupNode;
231 },
232
188 _sortingChanged: function() 233 _sortingChanged: function()
189 { 234 {
190 var columnIdentifier = this.dataGrid.sortColumnIdentifier(); 235 var columnIdentifier = this.dataGrid.sortColumnIdentifier();
191 /** 236 /**
192 * @param {string} field 237 * @param {string} field
193 * @param {!WebInspector.DataGridNode} a 238 * @param {!WebInspector.DataGridNode} a
194 * @param {!WebInspector.DataGridNode} b 239 * @param {!WebInspector.DataGridNode} b
195 * @return {number} 240 * @return {number}
196 */ 241 */
197 function compareField(field, a, b) 242 function compareField(field, a, b)
(...skipping 10 matching lines...) Expand all
208 "activity": "name" 253 "activity": "name"
209 }[columnIdentifier]; 254 }[columnIdentifier];
210 this.dataGrid.sortNodes(compareField.bind(null, field), !this.dataGrid.i sSortOrderAscending()); 255 this.dataGrid.sortNodes(compareField.bind(null, field), !this.dataGrid.i sSortOrderAscending());
211 }, 256 },
212 257
213 __proto__: WebInspector.VBox.prototype 258 __proto__: WebInspector.VBox.prototype
214 } 259 }
215 260
216 /** 261 /**
217 * @param {!WebInspector.TracingModel.Event} event 262 * @param {!WebInspector.TracingModel.Event} event
263 * @return {string}
264 */
265 WebInspector.TimelineTreeView.eventId = function(event)
266 {
267 if (event.name === WebInspector.TimelineModel.RecordType.JSFrame) {
268 var data = event.args["data"];
269 return "f:" + (data["callUID"] || WebInspector.TimelineTreeView.eventURL (event));
270 }
271 return event.name + ":@" + WebInspector.TimelineTreeView.eventURL(event);
272 }
273
274 /**
275 * @param {!WebInspector.TracingModel.Event} event
218 * @return {?string} 276 * @return {?string}
219 */ 277 */
220 WebInspector.TimelineTreeView.eventURL = function(event) 278 WebInspector.TimelineTreeView.eventURL = function(event)
221 { 279 {
222 var data = event.args["data"] || event.args["beginData"]; 280 var data = event.args["data"] || event.args["beginData"];
223 var url = data && data["url"]; 281 var url = data && data["url"];
224 if (url) 282 if (url)
225 return url; 283 return url;
226 var topFrame = event.stackTrace && event.stackTrace[0]; 284 var topFrame = event.stackTrace && event.stackTrace[0];
227 return topFrame && topFrame["url"] || null; 285 return topFrame && topFrame["url"] || null;
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 if (!this._profileNode.children) 406 if (!this._profileNode.children)
349 return; 407 return;
350 for (var node of this._profileNode.children.values()) { 408 for (var node of this._profileNode.children.values()) {
351 var gridNode = new WebInspector.TimelineTreeView.GridNode(node, this ._totalTime); 409 var gridNode = new WebInspector.TimelineTreeView.GridNode(node, this ._totalTime);
352 this.insertChildOrdered(gridNode); 410 this.insertChildOrdered(gridNode);
353 } 411 }
354 }, 412 },
355 413
356 __proto__: WebInspector.SortableDataGridNode.prototype 414 __proto__: WebInspector.SortableDataGridNode.prototype
357 } 415 }
OLDNEW
« no previous file with comments | « Source/devtools/front_end/timeline/TimelinePanel.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698