OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 WebInspector.TimelineProfileTree = {}; |
5 WebInspector.TimelineProfileTree = { }; | |
6 | 5 |
7 /** | 6 /** |
8 * @constructor | 7 * @unrestricted |
9 */ | 8 */ |
10 WebInspector.TimelineProfileTree.Node = function() | 9 WebInspector.TimelineProfileTree.Node = class { |
11 { | 10 constructor() { |
12 /** @type {number} */ | 11 /** @type {number} */ |
13 this.totalTime; | 12 this.totalTime; |
14 /** @type {number} */ | 13 /** @type {number} */ |
15 this.selfTime; | 14 this.selfTime; |
16 /** @type {string} */ | 15 /** @type {string} */ |
17 this.id; | 16 this.id; |
18 /** @type {!WebInspector.TracingModel.Event} */ | 17 /** @type {!WebInspector.TracingModel.Event} */ |
19 this.event; | 18 this.event; |
20 /** @type {?Map<string|symbol,!WebInspector.TimelineProfileTree.Node>} */ | 19 /** @type {?Map<string|symbol,!WebInspector.TimelineProfileTree.Node>} */ |
21 this.children; | 20 this.children; |
22 /** @type {?WebInspector.TimelineProfileTree.Node} */ | 21 /** @type {?WebInspector.TimelineProfileTree.Node} */ |
23 this.parent; | 22 this.parent; |
24 this._isGroupNode = false; | 23 this._isGroupNode = false; |
25 }; | 24 } |
26 | 25 |
27 WebInspector.TimelineProfileTree.Node.prototype = { | 26 /** |
28 /** | 27 * @return {boolean} |
29 * @return {boolean} | 28 */ |
30 */ | 29 isGroupNode() { |
31 isGroupNode: function() | 30 return this._isGroupNode; |
32 { | 31 } |
33 return this._isGroupNode; | |
34 } | |
35 }; | 32 }; |
36 | 33 |
37 /** | 34 /** |
38 * @param {!Array<!WebInspector.TracingModel.Event>} events | 35 * @param {!Array<!WebInspector.TracingModel.Event>} events |
39 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters | 36 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters |
40 * @param {number} startTime | 37 * @param {number} startTime |
41 * @param {number} endTime | 38 * @param {number} endTime |
42 * @param {function(!WebInspector.TracingModel.Event):(string|symbol)=} eventIdC
allback | 39 * @param {function(!WebInspector.TracingModel.Event):(string|symbol)=} eventIdC
allback |
43 * @return {!WebInspector.TimelineProfileTree.Node} | 40 * @return {!WebInspector.TimelineProfileTree.Node} |
44 */ | 41 */ |
45 WebInspector.TimelineProfileTree.buildTopDown = function(events, filters, startT
ime, endTime, eventIdCallback) | 42 WebInspector.TimelineProfileTree.buildTopDown = function(events, filters, startT
ime, endTime, eventIdCallback) { |
46 { | 43 // Temporarily deposit a big enough value that exceeds the max recording time. |
47 // Temporarily deposit a big enough value that exceeds the max recording tim
e. | 44 var /** @const */ initialTime = 1e7; |
48 var /** @const */ initialTime = 1e7; | 45 var root = new WebInspector.TimelineProfileTree.Node(); |
49 var root = new WebInspector.TimelineProfileTree.Node(); | 46 root.totalTime = initialTime; |
50 root.totalTime = initialTime; | 47 root.selfTime = initialTime; |
51 root.selfTime = initialTime; | 48 root.children = /** @type {!Map<string, !WebInspector.TimelineProfileTree.Node
>} */ (new Map()); |
52 root.children = /** @type {!Map<string, !WebInspector.TimelineProfileTree.No
de>} */ (new Map()); | 49 var parent = root; |
53 var parent = root; | |
54 | 50 |
55 /** | 51 /** |
56 * @param {!WebInspector.TracingModel.Event} e | 52 * @param {!WebInspector.TracingModel.Event} e |
57 */ | 53 */ |
58 function onStartEvent(e) | 54 function onStartEvent(e) { |
59 { | 55 if (!WebInspector.TimelineModel.isVisible(filters, e)) |
60 if (!WebInspector.TimelineModel.isVisible(filters, e)) | 56 return; |
61 return; | 57 var time = e.endTime ? Math.min(endTime, e.endTime) - Math.max(startTime, e.
startTime) : 0; |
62 var time = e.endTime ? Math.min(endTime, e.endTime) - Math.max(startTime
, e.startTime) : 0; | 58 var id = eventIdCallback ? eventIdCallback(e) : Symbol('uniqueEventId'); |
63 var id = eventIdCallback ? eventIdCallback(e) : Symbol("uniqueEventId"); | 59 if (!parent.children) |
64 if (!parent.children) | 60 parent.children = /** @type {!Map<string,!WebInspector.TimelineProfileTree
.Node>} */ (new Map()); |
65 parent.children = /** @type {!Map<string,!WebInspector.TimelineProfi
leTree.Node>} */ (new Map()); | 61 var node = parent.children.get(id); |
66 var node = parent.children.get(id); | 62 if (node) { |
67 if (node) { | 63 node.selfTime += time; |
68 node.selfTime += time; | 64 node.totalTime += time; |
69 node.totalTime += time; | 65 } else { |
70 } else { | 66 node = new WebInspector.TimelineProfileTree.Node(); |
71 node = new WebInspector.TimelineProfileTree.Node(); | 67 node.totalTime = time; |
72 node.totalTime = time; | 68 node.selfTime = time; |
73 node.selfTime = time; | 69 node.parent = parent; |
74 node.parent = parent; | 70 node.id = id; |
75 node.id = id; | 71 node.event = e; |
76 node.event = e; | 72 parent.children.set(id, node); |
77 parent.children.set(id, node); | |
78 } | |
79 parent.selfTime -= time; | |
80 if (parent.selfTime < 0) { | |
81 console.log("Error: Negative self of " + parent.selfTime, e); | |
82 parent.selfTime = 0; | |
83 } | |
84 if (e.endTime) | |
85 parent = node; | |
86 } | 73 } |
| 74 parent.selfTime -= time; |
| 75 if (parent.selfTime < 0) { |
| 76 console.log('Error: Negative self of ' + parent.selfTime, e); |
| 77 parent.selfTime = 0; |
| 78 } |
| 79 if (e.endTime) |
| 80 parent = node; |
| 81 } |
87 | 82 |
88 /** | 83 /** |
89 * @param {!WebInspector.TracingModel.Event} e | 84 * @param {!WebInspector.TracingModel.Event} e |
90 */ | 85 */ |
91 function onEndEvent(e) | 86 function onEndEvent(e) { |
92 { | 87 if (!WebInspector.TimelineModel.isVisible(filters, e)) |
93 if (!WebInspector.TimelineModel.isVisible(filters, e)) | 88 return; |
94 return; | 89 parent = parent.parent; |
95 parent = parent.parent; | 90 } |
96 } | |
97 | 91 |
98 var instantEventCallback = eventIdCallback ? undefined : onStartEvent; // Ig
nore instant events when aggregating. | 92 var instantEventCallback = eventIdCallback ? undefined : onStartEvent; // Ign
ore instant events when aggregating. |
99 WebInspector.TimelineModel.forEachEvent(events, onStartEvent, onEndEvent, in
stantEventCallback, startTime, endTime); | 93 WebInspector.TimelineModel.forEachEvent(events, onStartEvent, onEndEvent, inst
antEventCallback, startTime, endTime); |
100 root.totalTime -= root.selfTime; | 94 root.totalTime -= root.selfTime; |
101 root.selfTime = 0; | 95 root.selfTime = 0; |
102 return root; | 96 return root; |
103 }; | 97 }; |
104 | 98 |
105 /** | 99 /** |
106 * @param {!WebInspector.TimelineProfileTree.Node} topDownTree | 100 * @param {!WebInspector.TimelineProfileTree.Node} topDownTree |
107 * @param {?function(!WebInspector.TimelineProfileTree.Node):!WebInspector.Timel
ineProfileTree.Node=} groupingCallback | 101 * @param {?function(!WebInspector.TimelineProfileTree.Node):!WebInspector.Timel
ineProfileTree.Node=} groupingCallback |
108 * @return {!WebInspector.TimelineProfileTree.Node} | 102 * @return {!WebInspector.TimelineProfileTree.Node} |
109 */ | 103 */ |
110 WebInspector.TimelineProfileTree.buildBottomUp = function(topDownTree, groupingC
allback) | 104 WebInspector.TimelineProfileTree.buildBottomUp = function(topDownTree, groupingC
allback) { |
111 { | 105 var buRoot = new WebInspector.TimelineProfileTree.Node(); |
112 var buRoot = new WebInspector.TimelineProfileTree.Node(); | 106 buRoot.selfTime = 0; |
113 buRoot.selfTime = 0; | 107 buRoot.totalTime = 0; |
114 buRoot.totalTime = 0; | 108 /** @type {!Map<string, !WebInspector.TimelineProfileTree.Node>} */ |
115 /** @type {!Map<string, !WebInspector.TimelineProfileTree.Node>} */ | 109 buRoot.children = new Map(); |
116 buRoot.children = new Map(); | 110 var nodesOnStack = /** @type {!Set<string>} */ (new Set()); |
117 var nodesOnStack = /** @type {!Set<string>} */ (new Set()); | 111 if (topDownTree.children) |
118 if (topDownTree.children) | 112 topDownTree.children.forEach(processNode); |
119 topDownTree.children.forEach(processNode); | 113 buRoot.totalTime = topDownTree.totalTime; |
120 buRoot.totalTime = topDownTree.totalTime; | 114 |
121 | 115 /** |
122 /** | 116 * @param {!WebInspector.TimelineProfileTree.Node} tdNode |
123 * @param {!WebInspector.TimelineProfileTree.Node} tdNode | 117 */ |
124 */ | 118 function processNode(tdNode) { |
125 function processNode(tdNode) | 119 var buParent = groupingCallback && groupingCallback(tdNode) || buRoot; |
126 { | 120 if (buParent !== buRoot) { |
127 var buParent = groupingCallback && groupingCallback(tdNode) || buRoot; | 121 buRoot.children.set(buParent.id, buParent); |
128 if (buParent !== buRoot) { | 122 buParent.parent = buRoot; |
129 buRoot.children.set(buParent.id, buParent); | 123 } |
130 buParent.parent = buRoot; | 124 appendNode(tdNode, buParent); |
131 } | 125 var hadNode = nodesOnStack.has(tdNode.id); |
132 appendNode(tdNode, buParent); | 126 if (!hadNode) |
133 var hadNode = nodesOnStack.has(tdNode.id); | 127 nodesOnStack.add(tdNode.id); |
134 if (!hadNode) | 128 if (tdNode.children) |
135 nodesOnStack.add(tdNode.id); | 129 tdNode.children.forEach(processNode); |
136 if (tdNode.children) | 130 if (!hadNode) |
137 tdNode.children.forEach(processNode); | 131 nodesOnStack.delete(tdNode.id); |
138 if (!hadNode) | 132 } |
139 nodesOnStack.delete(tdNode.id); | 133 |
140 } | 134 /** |
141 | 135 * @param {!WebInspector.TimelineProfileTree.Node} tdNode |
142 /** | 136 * @param {!WebInspector.TimelineProfileTree.Node} buParent |
143 * @param {!WebInspector.TimelineProfileTree.Node} tdNode | 137 */ |
144 * @param {!WebInspector.TimelineProfileTree.Node} buParent | 138 function appendNode(tdNode, buParent) { |
145 */ | 139 var selfTime = tdNode.selfTime; |
146 function appendNode(tdNode, buParent) | 140 var totalTime = tdNode.totalTime; |
147 { | 141 buParent.selfTime += selfTime; |
148 var selfTime = tdNode.selfTime; | 142 buParent.totalTime += selfTime; |
149 var totalTime = tdNode.totalTime; | 143 while (tdNode.parent) { |
150 buParent.selfTime += selfTime; | 144 if (!buParent.children) |
151 buParent.totalTime += selfTime; | 145 buParent.children = /** @type {!Map<string,!WebInspector.TimelineProfile
Tree.Node>} */ (new Map()); |
152 while (tdNode.parent) { | 146 var id = tdNode.id; |
153 if (!buParent.children) | 147 var buNode = buParent.children.get(id); |
154 buParent.children = /** @type {!Map<string,!WebInspector.Timelin
eProfileTree.Node>} */ (new Map()); | 148 if (!buNode) { |
155 var id = tdNode.id; | 149 buNode = new WebInspector.TimelineProfileTree.Node(); |
156 var buNode = buParent.children.get(id); | 150 buNode.selfTime = selfTime; |
157 if (!buNode) { | 151 buNode.totalTime = totalTime; |
158 buNode = new WebInspector.TimelineProfileTree.Node(); | 152 buNode.event = tdNode.event; |
159 buNode.selfTime = selfTime; | 153 buNode.id = id; |
160 buNode.totalTime = totalTime; | 154 buNode.parent = buParent; |
161 buNode.event = tdNode.event; | 155 buParent.children.set(id, buNode); |
162 buNode.id = id; | 156 } else { |
163 buNode.parent = buParent; | 157 buNode.selfTime += selfTime; |
164 buParent.children.set(id, buNode); | 158 if (!nodesOnStack.has(id)) |
165 } else { | 159 buNode.totalTime += totalTime; |
166 buNode.selfTime += selfTime; | 160 } |
167 if (!nodesOnStack.has(id)) | 161 tdNode = tdNode.parent; |
168 buNode.totalTime += totalTime; | 162 buParent = buNode; |
169 } | 163 } |
170 tdNode = tdNode.parent; | 164 } |
171 buParent = buNode; | 165 |
172 } | 166 // Purge zero self time nodes. |
173 } | 167 var rootChildren = buRoot.children; |
174 | 168 for (var item of rootChildren.entries()) { |
175 // Purge zero self time nodes. | 169 if (item[1].selfTime === 0) |
176 var rootChildren = buRoot.children; | 170 rootChildren.delete(/** @type {string} */ (item[0])); |
177 for (var item of rootChildren.entries()) { | 171 } |
178 if (item[1].selfTime === 0) | 172 |
179 rootChildren.delete(/** @type {string} */(item[0])); | 173 return buRoot; |
180 } | |
181 | |
182 return buRoot; | |
183 }; | 174 }; |
184 | 175 |
185 /** | 176 /** |
186 * @param {!WebInspector.TracingModel.Event} event | 177 * @param {!WebInspector.TracingModel.Event} event |
187 * @return {?string} | 178 * @return {?string} |
188 */ | 179 */ |
189 WebInspector.TimelineProfileTree.eventURL = function(event) | 180 WebInspector.TimelineProfileTree.eventURL = function(event) { |
190 { | 181 var data = event.args['data'] || event.args['beginData']; |
191 var data = event.args["data"] || event.args["beginData"]; | 182 if (data && data['url']) |
192 if (data && data["url"]) | 183 return data['url']; |
193 return data["url"]; | 184 var frame = WebInspector.TimelineProfileTree.eventStackFrame(event); |
194 var frame = WebInspector.TimelineProfileTree.eventStackFrame(event); | 185 while (frame) { |
195 while (frame) { | 186 var url = frame['url']; |
196 var url = frame["url"]; | 187 if (url) |
197 if (url) | 188 return url; |
198 return url; | 189 frame = frame.parent; |
199 frame = frame.parent; | 190 } |
200 } | 191 return null; |
201 return null; | |
202 }; | 192 }; |
203 | 193 |
204 /** | 194 /** |
205 * @param {!WebInspector.TracingModel.Event} event | 195 * @param {!WebInspector.TracingModel.Event} event |
206 * @return {?RuntimeAgent.CallFrame} | 196 * @return {?RuntimeAgent.CallFrame} |
207 */ | 197 */ |
208 WebInspector.TimelineProfileTree.eventStackFrame = function(event) | 198 WebInspector.TimelineProfileTree.eventStackFrame = function(event) { |
209 { | 199 if (event.name === WebInspector.TimelineModel.RecordType.JSFrame) |
210 if (event.name === WebInspector.TimelineModel.RecordType.JSFrame) | 200 return /** @type {?RuntimeAgent.CallFrame} */ (event.args['data'] || null); |
211 return /** @type {?RuntimeAgent.CallFrame} */ (event.args["data"] || nul
l); | 201 var topFrame = event.stackTrace && event.stackTrace[0]; |
212 var topFrame = event.stackTrace && event.stackTrace[0]; | 202 if (topFrame) |
213 if (topFrame) | 203 return /** @type {!RuntimeAgent.CallFrame} */ (topFrame); |
214 return /** @type {!RuntimeAgent.CallFrame} */ (topFrame); | 204 var initiator = event.initiator; |
215 var initiator = event.initiator; | 205 return /** @type {?RuntimeAgent.CallFrame} */ (initiator && initiator.stackTra
ce && initiator.stackTrace[0] || null); |
216 return /** @type {?RuntimeAgent.CallFrame} */ (initiator && initiator.stackT
race && initiator.stackTrace[0] || null); | 206 }; |
217 }; | 207 |
218 | 208 /** |
219 /** | 209 * @unrestricted |
220 * @constructor | 210 */ |
221 * @param {function(!WebInspector.TracingModel.Event):string} titleMapper | 211 WebInspector.TimelineAggregator = class { |
222 * @param {function(!WebInspector.TracingModel.Event):string} categoryMapper | 212 /** |
223 */ | 213 * @param {function(!WebInspector.TracingModel.Event):string} titleMapper |
224 WebInspector.TimelineAggregator = function(titleMapper, categoryMapper) | 214 * @param {function(!WebInspector.TracingModel.Event):string} categoryMapper |
225 { | 215 */ |
| 216 constructor(titleMapper, categoryMapper) { |
226 this._titleMapper = titleMapper; | 217 this._titleMapper = titleMapper; |
227 this._categoryMapper = categoryMapper; | 218 this._categoryMapper = categoryMapper; |
228 /** @type {!Map<string, !WebInspector.TimelineProfileTree.Node>} */ | 219 /** @type {!Map<string, !WebInspector.TimelineProfileTree.Node>} */ |
229 this._groupNodes = new Map(); | 220 this._groupNodes = new Map(); |
| 221 } |
| 222 |
| 223 /** |
| 224 * @param {!WebInspector.TracingModel.Event} event |
| 225 * @return {string} |
| 226 */ |
| 227 static eventId(event) { |
| 228 if (event.name === WebInspector.TimelineModel.RecordType.JSFrame) { |
| 229 var data = event.args['data']; |
| 230 return 'f:' + data['functionName'] + '@' + (data['scriptId'] || data['url'
] || ''); |
| 231 } |
| 232 return event.name + ':@' + WebInspector.TimelineProfileTree.eventURL(event); |
| 233 } |
| 234 |
| 235 /** |
| 236 * @param {string} url |
| 237 * @return {boolean} |
| 238 */ |
| 239 static isExtensionInternalURL(url) { |
| 240 return url.startsWith(WebInspector.TimelineAggregator._extensionInternalPref
ix); |
| 241 } |
| 242 |
| 243 /** |
| 244 * @param {!WebInspector.TimelineAggregator.GroupBy} groupBy |
| 245 * @return {?function(!WebInspector.TimelineProfileTree.Node):!WebInspector.Ti
melineProfileTree.Node} |
| 246 */ |
| 247 groupFunction(groupBy) { |
| 248 var idMapper = this._nodeToGroupIdFunction(groupBy); |
| 249 return idMapper && this._nodeToGroupNode.bind(this, idMapper); |
| 250 } |
| 251 |
| 252 /** |
| 253 * @param {!WebInspector.TimelineProfileTree.Node} root |
| 254 * @param {!WebInspector.TimelineAggregator.GroupBy} groupBy |
| 255 * @return {!WebInspector.TimelineProfileTree.Node} |
| 256 */ |
| 257 performGrouping(root, groupBy) { |
| 258 var nodeMapper = this.groupFunction(groupBy); |
| 259 if (!nodeMapper) |
| 260 return root; |
| 261 for (var node of root.children.values()) { |
| 262 var groupNode = nodeMapper(node); |
| 263 groupNode.parent = root; |
| 264 groupNode.selfTime += node.selfTime; |
| 265 groupNode.totalTime += node.totalTime; |
| 266 groupNode.children.set(node.id, node); |
| 267 node.parent = root; |
| 268 } |
| 269 root.children = this._groupNodes; |
| 270 return root; |
| 271 } |
| 272 |
| 273 /** |
| 274 * @param {!WebInspector.TimelineAggregator.GroupBy} groupBy |
| 275 * @return {?function(!WebInspector.TimelineProfileTree.Node):string} |
| 276 */ |
| 277 _nodeToGroupIdFunction(groupBy) { |
| 278 /** |
| 279 * @param {!WebInspector.TimelineProfileTree.Node} node |
| 280 * @return {string} |
| 281 */ |
| 282 function groupByURL(node) { |
| 283 return WebInspector.TimelineProfileTree.eventURL(node.event) || ''; |
| 284 } |
| 285 |
| 286 /** |
| 287 * @param {boolean} groupSubdomains |
| 288 * @param {!WebInspector.TimelineProfileTree.Node} node |
| 289 * @return {string} |
| 290 */ |
| 291 function groupByDomain(groupSubdomains, node) { |
| 292 var url = WebInspector.TimelineProfileTree.eventURL(node.event) || ''; |
| 293 if (WebInspector.TimelineAggregator.isExtensionInternalURL(url)) |
| 294 return WebInspector.TimelineAggregator._extensionInternalPrefix; |
| 295 var parsedURL = url.asParsedURL(); |
| 296 if (!parsedURL) |
| 297 return ''; |
| 298 if (parsedURL.scheme === 'chrome-extension') |
| 299 return parsedURL.scheme + '://' + parsedURL.host; |
| 300 if (!groupSubdomains) |
| 301 return parsedURL.host; |
| 302 if (/^[.0-9]+$/.test(parsedURL.host)) |
| 303 return parsedURL.host; |
| 304 var domainMatch = /([^.]*\.)?[^.]*$/.exec(parsedURL.host); |
| 305 return domainMatch && domainMatch[0] || ''; |
| 306 } |
| 307 |
| 308 switch (groupBy) { |
| 309 case WebInspector.TimelineAggregator.GroupBy.None: |
| 310 return null; |
| 311 case WebInspector.TimelineAggregator.GroupBy.EventName: |
| 312 return node => node.event ? this._titleMapper(node.event) : ''; |
| 313 case WebInspector.TimelineAggregator.GroupBy.Category: |
| 314 return node => node.event ? this._categoryMapper(node.event) : ''; |
| 315 case WebInspector.TimelineAggregator.GroupBy.Subdomain: |
| 316 return groupByDomain.bind(null, false); |
| 317 case WebInspector.TimelineAggregator.GroupBy.Domain: |
| 318 return groupByDomain.bind(null, true); |
| 319 case WebInspector.TimelineAggregator.GroupBy.URL: |
| 320 return groupByURL; |
| 321 default: |
| 322 return null; |
| 323 } |
| 324 } |
| 325 |
| 326 /** |
| 327 * @param {string} id |
| 328 * @param {!WebInspector.TracingModel.Event} event |
| 329 * @return {!WebInspector.TimelineProfileTree.Node} |
| 330 */ |
| 331 _buildGroupNode(id, event) { |
| 332 var groupNode = new WebInspector.TimelineProfileTree.Node(); |
| 333 groupNode.id = id; |
| 334 groupNode.selfTime = 0; |
| 335 groupNode.totalTime = 0; |
| 336 groupNode.children = new Map(); |
| 337 groupNode.event = event; |
| 338 groupNode._isGroupNode = true; |
| 339 this._groupNodes.set(id, groupNode); |
| 340 return groupNode; |
| 341 } |
| 342 |
| 343 /** |
| 344 * @param {function(!WebInspector.TimelineProfileTree.Node):string} nodeToGrou
pId |
| 345 * @param {!WebInspector.TimelineProfileTree.Node} node |
| 346 * @return {!WebInspector.TimelineProfileTree.Node} |
| 347 */ |
| 348 _nodeToGroupNode(nodeToGroupId, node) { |
| 349 var id = nodeToGroupId(node); |
| 350 return this._groupNodes.get(id) || this._buildGroupNode(id, node.event); |
| 351 } |
230 }; | 352 }; |
231 | 353 |
232 /** | 354 /** |
233 * @enum {string} | 355 * @enum {string} |
234 */ | 356 */ |
235 WebInspector.TimelineAggregator.GroupBy = { | 357 WebInspector.TimelineAggregator.GroupBy = { |
236 None: "None", | 358 None: 'None', |
237 EventName: "EventName", | 359 EventName: 'EventName', |
238 Category: "Category", | 360 Category: 'Category', |
239 Domain: "Domain", | 361 Domain: 'Domain', |
240 Subdomain: "Subdomain", | 362 Subdomain: 'Subdomain', |
241 URL: "URL" | 363 URL: 'URL' |
242 }; | 364 }; |
243 | 365 |
244 /** | 366 |
245 * @param {!WebInspector.TracingModel.Event} event | 367 WebInspector.TimelineAggregator._extensionInternalPrefix = 'extensions::'; |
246 * @return {string} | 368 WebInspector.TimelineAggregator._groupNodeFlag = Symbol('groupNode'); |
247 */ | 369 |
248 WebInspector.TimelineAggregator.eventId = function(event) | 370 |
249 { | |
250 if (event.name === WebInspector.TimelineModel.RecordType.JSFrame) { | |
251 var data = event.args["data"]; | |
252 return "f:" + data["functionName"] + "@" + (data["scriptId"] || data["ur
l"] || ""); | |
253 } | |
254 return event.name + ":@" + WebInspector.TimelineProfileTree.eventURL(event); | |
255 }; | |
256 | |
257 WebInspector.TimelineAggregator._extensionInternalPrefix = "extensions::"; | |
258 WebInspector.TimelineAggregator._groupNodeFlag = Symbol("groupNode"); | |
259 | |
260 /** | |
261 * @param {string} url | |
262 * @return {boolean} | |
263 */ | |
264 WebInspector.TimelineAggregator.isExtensionInternalURL = function(url) | |
265 { | |
266 return url.startsWith(WebInspector.TimelineAggregator._extensionInternalPref
ix); | |
267 }; | |
268 | |
269 WebInspector.TimelineAggregator.prototype = { | |
270 /** | |
271 * @param {!WebInspector.TimelineAggregator.GroupBy} groupBy | |
272 * @return {?function(!WebInspector.TimelineProfileTree.Node):!WebInspector.
TimelineProfileTree.Node} | |
273 */ | |
274 groupFunction: function(groupBy) | |
275 { | |
276 var idMapper = this._nodeToGroupIdFunction(groupBy); | |
277 return idMapper && this._nodeToGroupNode.bind(this, idMapper); | |
278 }, | |
279 | |
280 /** | |
281 * @param {!WebInspector.TimelineProfileTree.Node} root | |
282 * @param {!WebInspector.TimelineAggregator.GroupBy} groupBy | |
283 * @return {!WebInspector.TimelineProfileTree.Node} | |
284 */ | |
285 performGrouping: function(root, groupBy) | |
286 { | |
287 var nodeMapper = this.groupFunction(groupBy); | |
288 if (!nodeMapper) | |
289 return root; | |
290 for (var node of root.children.values()) { | |
291 var groupNode = nodeMapper(node); | |
292 groupNode.parent = root; | |
293 groupNode.selfTime += node.selfTime; | |
294 groupNode.totalTime += node.totalTime; | |
295 groupNode.children.set(node.id, node); | |
296 node.parent = root; | |
297 } | |
298 root.children = this._groupNodes; | |
299 return root; | |
300 }, | |
301 | |
302 /** | |
303 * @param {!WebInspector.TimelineAggregator.GroupBy} groupBy | |
304 * @return {?function(!WebInspector.TimelineProfileTree.Node):string} | |
305 */ | |
306 _nodeToGroupIdFunction: function(groupBy) | |
307 { | |
308 /** | |
309 * @param {!WebInspector.TimelineProfileTree.Node} node | |
310 * @return {string} | |
311 */ | |
312 function groupByURL(node) | |
313 { | |
314 return WebInspector.TimelineProfileTree.eventURL(node.event) || ""; | |
315 } | |
316 | |
317 /** | |
318 * @param {boolean} groupSubdomains | |
319 * @param {!WebInspector.TimelineProfileTree.Node} node | |
320 * @return {string} | |
321 */ | |
322 function groupByDomain(groupSubdomains, node) | |
323 { | |
324 var url = WebInspector.TimelineProfileTree.eventURL(node.event) || "
"; | |
325 if (WebInspector.TimelineAggregator.isExtensionInternalURL(url)) | |
326 return WebInspector.TimelineAggregator._extensionInternalPrefix; | |
327 var parsedURL = url.asParsedURL(); | |
328 if (!parsedURL) | |
329 return ""; | |
330 if (parsedURL.scheme === "chrome-extension") | |
331 return parsedURL.scheme + "://" + parsedURL.host; | |
332 if (!groupSubdomains) | |
333 return parsedURL.host; | |
334 if (/^[.0-9]+$/.test(parsedURL.host)) | |
335 return parsedURL.host; | |
336 var domainMatch = /([^.]*\.)?[^.]*$/.exec(parsedURL.host); | |
337 return domainMatch && domainMatch[0] || ""; | |
338 } | |
339 | |
340 switch (groupBy) { | |
341 case WebInspector.TimelineAggregator.GroupBy.None: return null; | |
342 case WebInspector.TimelineAggregator.GroupBy.EventName: return node => n
ode.event ? this._titleMapper(node.event) : ""; | |
343 case WebInspector.TimelineAggregator.GroupBy.Category: return node => no
de.event ? this._categoryMapper(node.event) : ""; | |
344 case WebInspector.TimelineAggregator.GroupBy.Subdomain: return groupByDo
main.bind(null, false); | |
345 case WebInspector.TimelineAggregator.GroupBy.Domain: return groupByDomai
n.bind(null, true); | |
346 case WebInspector.TimelineAggregator.GroupBy.URL: return groupByURL; | |
347 default: return null; | |
348 } | |
349 }, | |
350 | |
351 /** | |
352 * @param {string} id | |
353 * @param {!WebInspector.TracingModel.Event} event | |
354 * @return {!WebInspector.TimelineProfileTree.Node} | |
355 */ | |
356 _buildGroupNode: function(id, event) | |
357 { | |
358 var groupNode = new WebInspector.TimelineProfileTree.Node(); | |
359 groupNode.id = id; | |
360 groupNode.selfTime = 0; | |
361 groupNode.totalTime = 0; | |
362 groupNode.children = new Map(); | |
363 groupNode.event = event; | |
364 groupNode._isGroupNode = true; | |
365 this._groupNodes.set(id, groupNode); | |
366 return groupNode; | |
367 }, | |
368 | |
369 /** | |
370 * @param {function(!WebInspector.TimelineProfileTree.Node):string} nodeToGr
oupId | |
371 * @param {!WebInspector.TimelineProfileTree.Node} node | |
372 * @return {!WebInspector.TimelineProfileTree.Node} | |
373 */ | |
374 _nodeToGroupNode: function(nodeToGroupId, node) | |
375 { | |
376 var id = nodeToGroupId(node); | |
377 return this._groupNodes.get(id) || this._buildGroupNode(id, node.event); | |
378 }, | |
379 }; | |
OLD | NEW |