| 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 |