Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 /** | 31 /** |
| 32 * @constructor | 32 * @constructor |
| 33 * @extends {WebInspector.TimelineOverviewBase} | 33 * @extends {WebInspector.TimelineOverviewBase} |
| 34 * @param {string} id | |
|
caseq
2015/06/26 15:53:47
nit: id -> class or name?
alph
2015/06/26 16:11:19
it's in fact part of id, not the class. so let me
| |
| 34 * @param {!WebInspector.TimelineModel} model | 35 * @param {!WebInspector.TimelineModel} model |
| 35 * @param {!WebInspector.TimelineFrameModelBase} frameModel | |
| 36 */ | 36 */ |
| 37 WebInspector.TimelineEventOverview = function(model, frameModel) | 37 WebInspector.TimelineEventOverview = function(id, model) |
| 38 { | 38 { |
| 39 WebInspector.TimelineOverviewBase.call(this); | 39 WebInspector.TimelineOverviewBase.call(this); |
| 40 this.element.id = "timeline-overview-events"; | 40 this.element.id = "timeline-overview-" + id; |
| 41 this.element.classList.add("overview-strip"); | |
| 41 this._model = model; | 42 this._model = model; |
| 42 this._frameModel = frameModel; | |
| 43 | |
| 44 this._fillStyles = {}; | |
| 45 var categories = WebInspector.TimelineUIUtils.categories(); | |
| 46 for (var category in categories) { | |
| 47 this._fillStyles[category] = categories[category].fillColorStop1; | |
| 48 categories[category].addEventListener(WebInspector.TimelineCategory.Even ts.VisibilityChanged, this._onCategoryVisibilityChanged, this); | |
| 49 } | |
| 50 | |
| 51 this._disabledCategoryFillStyle = "hsl(0, 0%, 67%)"; | |
| 52 } | 43 } |
| 53 | 44 |
| 54 /** @const */ | |
| 55 WebInspector.TimelineEventOverview._fullStripHeight = 24; | |
| 56 /** @const */ | |
| 57 WebInspector.TimelineEventOverview._smallStripHeight = 8; | |
| 58 | |
| 59 WebInspector.TimelineEventOverview.prototype = { | 45 WebInspector.TimelineEventOverview.prototype = { |
| 60 /** | 46 /** |
| 61 * @override | 47 * @param {number} y |
| 48 * @param {string} label | |
| 62 */ | 49 */ |
| 63 dispose: function() | 50 _drawHorizontalGuide: function(y, label) |
| 64 { | 51 { |
| 65 WebInspector.TimelineOverviewBase.prototype.dispose.call(this); | 52 var ctx = this._context; |
| 66 var categories = WebInspector.TimelineUIUtils.categories(); | 53 ctx.save(); |
| 67 for (var category in categories) | 54 ctx.translate(0, y); |
| 68 categories[category].removeEventListener(WebInspector.TimelineCatego ry.Events.VisibilityChanged, this._onCategoryVisibilityChanged, this); | 55 ctx.scale(window.devicePixelRatio, window.devicePixelRatio); |
| 56 ctx.beginPath(); | |
| 57 ctx.moveTo(0, 0); | |
| 58 ctx.lineTo(this._canvas.width, 0); | |
| 59 ctx.strokeStyle = "hsl(0, 0%, 85%)"; | |
| 60 ctx.setLineDash([3]); | |
| 61 ctx.lineWidth = 1; | |
| 62 ctx.stroke(); | |
| 63 ctx.fillStyle = "hsl(0, 0%, 60%)"; | |
| 64 ctx.font = "9px " + WebInspector.fontFamily(); | |
| 65 ctx.fillText(label, 5, 9); | |
| 66 ctx.restore(); | |
| 69 }, | 67 }, |
| 70 | 68 |
| 71 /** | 69 /** |
| 70 * @param {number} begin | |
| 71 * @param {number} end | |
| 72 * @param {number} position | |
| 73 * @param {number} height | |
| 74 * @param {string} color | |
| 75 */ | |
| 76 _renderBar: function(begin, end, position, height, color) | |
| 77 { | |
| 78 var x = begin; | |
| 79 var width = end - begin; | |
| 80 this._context.fillStyle = color; | |
| 81 this._context.fillRect(x, position, width, height); | |
| 82 }, | |
| 83 | |
| 84 /** | |
| 85 * @override | |
| 86 * @param {number} windowLeft | |
| 87 * @param {number} windowRight | |
| 88 * @return {!{startTime: number, endTime: number}} | |
| 89 */ | |
| 90 windowTimes: function(windowLeft, windowRight) | |
| 91 { | |
| 92 var absoluteMin = this._model.minimumRecordTime(); | |
| 93 var timeSpan = this._model.maximumRecordTime() - absoluteMin; | |
| 94 return { | |
| 95 startTime: absoluteMin + timeSpan * windowLeft, | |
| 96 endTime: absoluteMin + timeSpan * windowRight | |
| 97 }; | |
| 98 }, | |
| 99 | |
| 100 /** | |
| 101 * @override | |
| 102 * @param {number} startTime | |
| 103 * @param {number} endTime | |
| 104 * @return {!{left: number, right: number}} | |
| 105 */ | |
| 106 windowBoundaries: function(startTime, endTime) | |
| 107 { | |
| 108 var absoluteMin = this._model.minimumRecordTime(); | |
| 109 var timeSpan = this._model.maximumRecordTime() - absoluteMin; | |
| 110 var haveRecords = absoluteMin > 0; | |
| 111 return { | |
| 112 left: haveRecords && startTime ? Math.min((startTime - absoluteMin) / timeSpan, 1) : 0, | |
| 113 right: haveRecords && endTime < Infinity ? (endTime - absoluteMin) / timeSpan : 1 | |
| 114 }; | |
| 115 }, | |
| 116 | |
| 117 __proto__: WebInspector.TimelineOverviewBase.prototype | |
| 118 } | |
| 119 | |
| 120 /** | |
| 121 * @constructor | |
| 122 * @extends {WebInspector.TimelineEventOverview} | |
| 123 * @param {!WebInspector.TimelineModel} model | |
| 124 */ | |
| 125 WebInspector.TimelineEventOverview.Input = function(model) | |
| 126 { | |
| 127 WebInspector.TimelineEventOverview.call(this, "input", model); | |
| 128 } | |
| 129 | |
| 130 WebInspector.TimelineEventOverview.Input.prototype = { | |
| 131 /** | |
| 72 * @override | 132 * @override |
| 73 */ | 133 */ |
| 74 update: function() | 134 update: function() |
| 75 { | 135 { |
| 76 var /** @const */ fpsStripHeight = 20; | |
| 77 this.resetCanvas(); | 136 this.resetCanvas(); |
| 78 var threads = this._model.virtualThreads(); | 137 var events = this._model.mainThreadEvents(); |
| 79 var mainThreadEvents = this._model.mainThreadEvents(); | 138 var height = this._canvas.height; |
| 80 var networkHeight = this._canvas.clientHeight | |
| 81 - WebInspector.TimelineEventOverview._fullStripHeight | |
| 82 - fpsStripHeight | |
| 83 - 3 * WebInspector.TimelineEventOverview._smallStripHeight; | |
| 84 var position = 0; | |
| 85 if (Runtime.experiments.isEnabled("inputEventsOnTimelineOverview")) { | |
| 86 var inputHeight = this._drawInputEvents(mainThreadEvents, position, WebInspector.TimelineEventOverview._smallStripHeight); | |
| 87 position += inputHeight; | |
| 88 networkHeight -= inputHeight; | |
| 89 } | |
| 90 position += this._drawNetwork(mainThreadEvents, position, networkHeight) ; | |
| 91 position += this._drawStackedUtilizationChart(mainThreadEvents, position , WebInspector.TimelineEventOverview._fullStripHeight); | |
| 92 for (var thread of threads.filter(function(thread) { return !thread.isWo rker(); })) | |
| 93 this._drawEvents(thread.events, position, WebInspector.TimelineEvent Overview._smallStripHeight); | |
| 94 position += WebInspector.TimelineEventOverview._smallStripHeight; | |
| 95 for (var thread of threads.filter(function(thread) { return thread.isWor ker(); })) | |
| 96 this._drawEvents(thread.events, position, WebInspector.TimelineEvent Overview._smallStripHeight); | |
| 97 position += WebInspector.TimelineEventOverview._smallStripHeight; | |
| 98 position += this._drawResponsivenessStrip(position, WebInspector.Timelin eEventOverview._smallStripHeight); | |
| 99 position += this._drawFrames(position, fpsStripHeight); | |
| 100 console.assert(position === this._canvas.clientHeight); | |
| 101 }, | |
| 102 | |
| 103 /** | |
| 104 * @param {!Array.<!WebInspector.TracingModel.Event>} events | |
| 105 * @param {number} position | |
| 106 * @param {number} height | |
| 107 * @return {number} | |
| 108 */ | |
| 109 _drawInputEvents: function(events, position, height) | |
| 110 { | |
| 111 var /** @const */ padding = 1; | |
| 112 var descriptors = WebInspector.TimelineUIUtils.eventDispatchDesciptors() ; | 139 var descriptors = WebInspector.TimelineUIUtils.eventDispatchDesciptors() ; |
| 113 /** @type {!Map.<string,!WebInspector.TimelineUIUtils.EventDispatchTypeD escriptor>} */ | 140 /** @type {!Map.<string,!WebInspector.TimelineUIUtils.EventDispatchTypeD escriptor>} */ |
| 114 var descriptorsByType = new Map(); | 141 var descriptorsByType = new Map(); |
| 115 var maxPriority = -1; | 142 var maxPriority = -1; |
| 116 for (var descriptor of descriptors) { | 143 for (var descriptor of descriptors) { |
| 117 for (var type of descriptor.eventTypes) | 144 for (var type of descriptor.eventTypes) |
| 118 descriptorsByType.set(type, descriptor); | 145 descriptorsByType.set(type, descriptor); |
| 119 maxPriority = Math.max(maxPriority, descriptor.priority); | 146 maxPriority = Math.max(maxPriority, descriptor.priority); |
| 120 } | 147 } |
| 121 | 148 |
| 122 var devicePixelRatio = window.devicePixelRatio; | 149 var /** @const */ minWidth = 2 * window.devicePixelRatio; |
| 123 var /** @const */ minWidth = 2 * devicePixelRatio; | |
| 124 var stripHeight = (height - padding) * devicePixelRatio; | |
| 125 var timeOffset = this._model.minimumRecordTime(); | 150 var timeOffset = this._model.minimumRecordTime(); |
| 126 var timeSpan = this._model.maximumRecordTime() - timeOffset; | 151 var timeSpan = this._model.maximumRecordTime() - timeOffset; |
| 127 var canvasWidth = this._canvas.width; | 152 var canvasWidth = this._canvas.width; |
| 128 var scale = canvasWidth / timeSpan; | 153 var scale = canvasWidth / timeSpan; |
| 129 position = (position + padding) * devicePixelRatio; | |
| 130 | 154 |
| 131 for (var priority = 0; priority <= maxPriority; ++priority) { | 155 for (var priority = 0; priority <= maxPriority; ++priority) { |
| 132 for (var i = 0; i < events.length; ++i) { | 156 for (var i = 0; i < events.length; ++i) { |
| 133 var event = events[i]; | 157 var event = events[i]; |
| 134 if (event.name !== WebInspector.TimelineModel.RecordType.EventDi spatch) | 158 if (event.name !== WebInspector.TimelineModel.RecordType.EventDi spatch) |
| 135 continue; | 159 continue; |
| 136 var descriptor = descriptorsByType.get(event.args["data"]["type" ]); | 160 var descriptor = descriptorsByType.get(event.args["data"]["type" ]); |
| 137 if (!descriptor || descriptor.priority !== priority) | 161 if (!descriptor || descriptor.priority !== priority) |
| 138 continue; | 162 continue; |
| 139 var start = Number.constrain(Math.floor((event.startTime - timeO ffset) * scale), 0, canvasWidth); | 163 var start = Number.constrain(Math.floor((event.startTime - timeO ffset) * scale), 0, canvasWidth); |
| 140 var end = Number.constrain(Math.ceil((event.endTime - timeOffset ) * scale), 0, canvasWidth); | 164 var end = Number.constrain(Math.ceil((event.endTime - timeOffset ) * scale), 0, canvasWidth); |
| 141 var width = Math.max(end - start, minWidth); | 165 var width = Math.max(end - start, minWidth); |
| 142 this._renderBar(start, start + width, position, stripHeight, des criptor.color); | 166 this._renderBar(start, start + width, 0, height, descriptor.colo r); |
| 143 } | 167 } |
| 144 } | 168 } |
| 145 | |
| 146 return height; | |
| 147 }, | 169 }, |
| 148 | 170 |
| 171 __proto__: WebInspector.TimelineEventOverview.prototype | |
| 172 } | |
| 173 | |
| 174 /** | |
| 175 * @constructor | |
| 176 * @extends {WebInspector.TimelineEventOverview} | |
| 177 * @param {!WebInspector.TimelineModel} model | |
| 178 */ | |
| 179 WebInspector.TimelineEventOverview.Network = function(model) | |
| 180 { | |
| 181 WebInspector.TimelineEventOverview.call(this, "network", model); | |
| 182 } | |
| 183 | |
| 184 WebInspector.TimelineEventOverview.Network.prototype = { | |
| 149 /** | 185 /** |
| 150 * @param {!Array.<!WebInspector.TracingModel.Event>} events | 186 * @override |
| 151 * @param {number} position | |
| 152 * @param {number} height | |
| 153 * @return {number} | |
| 154 */ | 187 */ |
| 155 _drawNetwork: function(events, position, height) | 188 update: function() |
| 156 { | 189 { |
| 157 var /** @const */ padding = 1; | 190 this.resetCanvas(); |
| 158 var /** @const */ maxBandHeight = 4; | 191 var events = this._model.mainThreadEvents(); |
| 159 position += padding; | 192 var height = this._canvas.height; |
| 160 var devicePixelRatio = window.devicePixelRatio; | 193 var /** @const */ maxBandHeight = 4 * window.devicePixelRatio; |
| 161 var bandsCount = WebInspector.TimelineUIUtils.calculateNetworkBandsCount (events); | 194 var bandsCount = WebInspector.TimelineUIUtils.calculateNetworkBandsCount (events); |
| 162 var bandInterval = Math.min(maxBandHeight, (height - padding) / (bandsCo unt || 1)); | 195 var bandInterval = Math.min(maxBandHeight, height / (bandsCount || 1)); |
| 163 var bandHeight = Math.ceil(bandInterval * devicePixelRatio); | 196 var bandHeight = Math.ceil(bandInterval); |
| 164 var timeOffset = this._model.minimumRecordTime(); | 197 var timeOffset = this._model.minimumRecordTime(); |
| 165 var timeSpan = this._model.maximumRecordTime() - timeOffset; | 198 var timeSpan = this._model.maximumRecordTime() - timeOffset; |
| 166 var canvasWidth = this._canvas.width; | 199 var canvasWidth = this._canvas.width; |
| 167 var scale = canvasWidth / timeSpan; | 200 var scale = canvasWidth / timeSpan; |
| 168 var loadingCategory = WebInspector.TimelineUIUtils.categories()["loading "]; | 201 var loadingCategory = WebInspector.TimelineUIUtils.categories()["loading "]; |
| 169 var waitingColor = loadingCategory.backgroundColor; | 202 var waitingColor = loadingCategory.backgroundColor; |
| 170 var processingColor = loadingCategory.fillColorStop1; | 203 var processingColor = loadingCategory.fillColorStop1; |
| 171 | 204 |
| 172 /** | 205 /** |
| 173 * @param {number} band | 206 * @param {number} band |
| 174 * @param {number} startTime | 207 * @param {number} startTime |
| 175 * @param {number} endTime | 208 * @param {number} endTime |
| 176 * @param {?WebInspector.TracingModel.Event} event | 209 * @param {?WebInspector.TracingModel.Event} event |
| 177 * @this {WebInspector.TimelineEventOverview} | 210 * @this {WebInspector.TimelineEventOverview.Network} |
| 178 */ | 211 */ |
| 179 function drawBar(band, startTime, endTime, event) | 212 function drawBar(band, startTime, endTime, event) |
| 180 { | 213 { |
| 181 var start = Number.constrain((startTime - timeOffset) * scale, 0, ca nvasWidth); | 214 var start = Number.constrain((startTime - timeOffset) * scale, 0, ca nvasWidth); |
| 182 var end = Number.constrain((endTime - timeOffset) * scale, 0, canvas Width); | 215 var end = Number.constrain((endTime - timeOffset) * scale, 0, canvas Width); |
| 183 var color = !event || | 216 var color = !event || |
| 184 event.name === WebInspector.TimelineModel.RecordType.ResourceRec eiveResponse || | 217 event.name === WebInspector.TimelineModel.RecordType.ResourceRec eiveResponse || |
| 185 event.name === WebInspector.TimelineModel.RecordType.ResourceSen dRequest ? waitingColor : processingColor; | 218 event.name === WebInspector.TimelineModel.RecordType.ResourceSen dRequest ? waitingColor : processingColor; |
| 186 this._renderBar(Math.floor(start), Math.ceil(end), Math.floor(device PixelRatio * (position + band * bandInterval)), bandHeight, color); | 219 this._renderBar(Math.floor(start), Math.ceil(end), Math.floor(band * bandInterval), bandHeight, color); |
| 187 } | 220 } |
| 188 | 221 |
| 189 WebInspector.TimelineUIUtils.iterateNetworkRequestsInRoundRobin(events, bandsCount, drawBar.bind(this)); | 222 WebInspector.TimelineUIUtils.iterateNetworkRequestsInRoundRobin(events, bandsCount, drawBar.bind(this)); |
| 190 return height; | 223 }, |
| 224 | |
| 225 __proto__: WebInspector.TimelineEventOverview.prototype | |
| 226 } | |
| 227 | |
| 228 /** | |
| 229 * @constructor | |
| 230 * @extends {WebInspector.TimelineEventOverview} | |
| 231 * @param {string} id | |
| 232 * @param {!WebInspector.TimelineModel} model | |
| 233 */ | |
| 234 WebInspector.TimelineEventOverview.Thread = function(id, model) | |
| 235 { | |
| 236 WebInspector.TimelineEventOverview.call(this, id, model) | |
| 237 this._fillStyles = {}; | |
| 238 var categories = WebInspector.TimelineUIUtils.categories(); | |
| 239 for (var category in categories) { | |
| 240 this._fillStyles[category] = categories[category].fillColorStop1; | |
| 241 categories[category].addEventListener(WebInspector.TimelineCategory.Even ts.VisibilityChanged, this._onCategoryVisibilityChanged, this); | |
| 242 } | |
| 243 this._disabledCategoryFillStyle = "hsl(0, 0%, 67%)"; | |
| 244 } | |
| 245 | |
| 246 WebInspector.TimelineEventOverview.Thread.prototype = { | |
| 247 /** | |
| 248 * @override | |
| 249 */ | |
| 250 dispose: function() | |
| 251 { | |
| 252 WebInspector.TimelineOverviewBase.prototype.dispose.call(this); | |
| 253 var categories = WebInspector.TimelineUIUtils.categories(); | |
| 254 for (var category in categories) | |
| 255 categories[category].removeEventListener(WebInspector.TimelineCatego ry.Events.VisibilityChanged, this._onCategoryVisibilityChanged, this); | |
| 256 }, | |
| 257 | |
| 258 _onCategoryVisibilityChanged: function() | |
| 259 { | |
| 260 this.update(); | |
| 191 }, | 261 }, |
| 192 | 262 |
| 193 /** | 263 /** |
| 194 * @param {!Array.<!WebInspector.TracingModel.Event>} events | 264 * @param {!WebInspector.TimelineCategory} category |
| 195 * @param {number} position | 265 * @return {string} |
| 196 * @param {number} height | |
| 197 * @return {number} | |
| 198 */ | 266 */ |
| 199 _drawStackedUtilizationChart: function(events, position, height) | 267 _categoryColor: function(category) |
| 200 { | 268 { |
| 269 return category.hidden ? this._disabledCategoryFillStyle : this._fillSty les[category.name]; | |
| 270 }, | |
| 271 | |
| 272 __proto__: WebInspector.TimelineEventOverview.prototype | |
| 273 } | |
| 274 | |
| 275 /** | |
| 276 * @constructor | |
| 277 * @extends {WebInspector.TimelineEventOverview.Thread} | |
| 278 * @param {!WebInspector.TimelineModel} model | |
| 279 */ | |
| 280 WebInspector.TimelineEventOverview.MainThread = function(model) | |
| 281 { | |
| 282 WebInspector.TimelineEventOverview.Thread.call(this, "main-thread", model) | |
| 283 } | |
| 284 | |
| 285 WebInspector.TimelineEventOverview.MainThread.prototype = { | |
| 286 /** | |
| 287 * @override | |
| 288 */ | |
| 289 update: function() | |
| 290 { | |
| 291 this.resetCanvas(); | |
| 292 var events = this._model.mainThreadEvents(); | |
| 201 if (!events.length) | 293 if (!events.length) |
| 202 return height; | 294 return; |
| 203 var /** @const */ quantSizePx = 4 * window.devicePixelRatio; | 295 var /** @const */ quantSizePx = 4 * window.devicePixelRatio; |
| 204 var /** @const */ padding = 1; | 296 var height = this._canvas.height; |
| 205 var visualHeight = (height - padding) * window.devicePixelRatio; | 297 var baseLine = height; |
| 206 var baseLine = (position + height) * window.devicePixelRatio; | |
| 207 var timeOffset = this._model.minimumRecordTime(); | 298 var timeOffset = this._model.minimumRecordTime(); |
| 208 var timeSpan = this._model.maximumRecordTime() - timeOffset; | 299 var timeSpan = this._model.maximumRecordTime() - timeOffset; |
| 209 var scale = this._canvas.width / timeSpan; | 300 var scale = this._canvas.width / timeSpan; |
| 210 var quantTime = quantSizePx / scale; | 301 var quantTime = quantSizePx / scale; |
| 211 var quantizer = new WebInspector.Quantizer(timeOffset, quantTime, drawSa mple.bind(this)); | 302 var quantizer = new WebInspector.Quantizer(timeOffset, quantTime, drawSa mple.bind(this)); |
| 212 var ctx = this._context; | 303 var ctx = this._context; |
| 213 var x = 0; | 304 var x = 0; |
| 214 var categories = WebInspector.TimelineUIUtils.categories(); | 305 var categories = WebInspector.TimelineUIUtils.categories(); |
| 215 var categoryOrder = ["idle", "scripting", "rendering", "painting", "load ing", "other"]; | 306 var categoryOrder = ["idle", "scripting", "rendering", "painting", "load ing", "other"]; |
| 216 var otherIndex = categoryOrder.indexOf("other"); | 307 var otherIndex = categoryOrder.indexOf("other"); |
| 217 var idleIndex = 0; | 308 var idleIndex = 0; |
| 218 console.assert(idleIndex === categoryOrder.indexOf("idle")); | 309 console.assert(idleIndex === categoryOrder.indexOf("idle")); |
| 219 for (var i = idleIndex + 1; i < categoryOrder.length; ++i) | 310 for (var i = idleIndex + 1; i < categoryOrder.length; ++i) |
| 220 categories[categoryOrder[i]]._overviewIndex = i; | 311 categories[categoryOrder[i]]._overviewIndex = i; |
| 221 var categoryIndexStack = []; | 312 var categoryIndexStack = []; |
| 222 | 313 |
| 223 this._drawHorizontalGuide(baseLine - visualHeight + 0.5, WebInspector.UI String("100%")); | 314 this._drawHorizontalGuide(baseLine - height + 0.5, WebInspector.UIString ("100%")); |
| 224 | 315 |
| 225 /** | 316 /** |
| 226 * @param {!Array<number>} counters | 317 * @param {!Array<number>} counters |
| 227 * @this {WebInspector.TimelineEventOverview} | 318 * @this {WebInspector.TimelineEventOverview} |
| 228 */ | 319 */ |
| 229 function drawSample(counters) | 320 function drawSample(counters) |
| 230 { | 321 { |
| 231 var y = baseLine; | 322 var y = baseLine; |
| 232 for (var i = idleIndex + 1; i < counters.length; ++i) { | 323 for (var i = idleIndex + 1; i < counters.length; ++i) { |
| 233 if (!counters[i]) | 324 if (!counters[i]) |
| 234 continue; | 325 continue; |
| 235 var h = counters[i] / quantTime * visualHeight; | 326 var h = counters[i] / quantTime * height; |
| 236 ctx.fillStyle = this._categoryColor(categories[categoryOrder[i]] ); | 327 ctx.fillStyle = this._categoryColor(categories[categoryOrder[i]] ); |
| 237 ctx.fillRect(x, y - h, quantSizePx, h); | 328 ctx.fillRect(x, y - h, quantSizePx, h); |
| 238 y -= h; | 329 y -= h; |
| 239 } | 330 } |
| 240 x += quantSizePx; | 331 x += quantSizePx; |
| 241 } | 332 } |
| 242 | 333 |
| 243 /** | 334 /** |
| 244 * @param {!WebInspector.TracingModel.Event} e | 335 * @param {!WebInspector.TracingModel.Event} e |
| 245 */ | 336 */ |
| 246 function onEventStart(e) | 337 function onEventStart(e) |
| 247 { | 338 { |
| 248 var index = categoryIndexStack.length ? categoryIndexStack.peekLast( ) : idleIndex; | 339 var index = categoryIndexStack.length ? categoryIndexStack.peekLast( ) : idleIndex; |
| 249 quantizer.appendInterval(e.startTime, index); | 340 quantizer.appendInterval(e.startTime, index); |
| 250 categoryIndexStack.push(WebInspector.TimelineUIUtils.eventStyle(e).c ategory._overviewIndex || otherIndex); | 341 categoryIndexStack.push(WebInspector.TimelineUIUtils.eventStyle(e).c ategory._overviewIndex || otherIndex); |
| 251 } | 342 } |
| 252 | 343 |
| 253 /** | 344 /** |
| 254 * @param {!WebInspector.TracingModel.Event} e | 345 * @param {!WebInspector.TracingModel.Event} e |
| 255 */ | 346 */ |
| 256 function onEventEnd(e) | 347 function onEventEnd(e) |
| 257 { | 348 { |
| 258 quantizer.appendInterval(e.endTime, categoryIndexStack.pop()); | 349 quantizer.appendInterval(e.endTime, categoryIndexStack.pop()); |
| 259 } | 350 } |
| 260 | 351 |
| 261 WebInspector.TimelineModel.forEachEvent(events, onEventStart, onEventEnd ); | 352 WebInspector.TimelineModel.forEachEvent(events, onEventStart, onEventEnd ); |
| 262 quantizer.appendInterval(timeOffset + timeSpan + quantTime, idleIndex); // Kick drawing the last bucket. | 353 quantizer.appendInterval(timeOffset + timeSpan + quantTime, idleIndex); // Kick drawing the last bucket. |
| 263 return height; | 354 }, |
| 355 | |
| 356 __proto__: WebInspector.TimelineEventOverview.Thread.prototype | |
| 357 } | |
| 358 | |
| 359 /** | |
| 360 * @constructor | |
| 361 * @extends {WebInspector.TimelineEventOverview.Thread} | |
| 362 * @param {!WebInspector.TimelineModel} model | |
| 363 */ | |
| 364 WebInspector.TimelineEventOverview.OtherThreads = function(model) | |
| 365 { | |
| 366 WebInspector.TimelineEventOverview.Thread.call(this, "other-threads", model) ; | |
| 367 } | |
| 368 | |
| 369 WebInspector.TimelineEventOverview.OtherThreads.prototype = { | |
| 370 /** | |
| 371 * @override | |
| 372 */ | |
| 373 update: function() | |
| 374 { | |
| 375 this.resetCanvas(); | |
| 376 this._model.virtualThreads().forEach(this._drawThread.bind(this)); | |
| 264 }, | 377 }, |
| 265 | 378 |
| 266 /** | 379 /** |
| 267 * @param {!Array.<!WebInspector.TracingModel.Event>} events | 380 * @param {!WebInspector.TimelineModel.VirtualThread} thread |
| 268 * @param {number} position | |
| 269 * @param {number} stripHeight | |
| 270 * @return {number} | |
| 271 */ | 381 */ |
| 272 _drawEvents: function(events, position, stripHeight) | 382 _drawThread: function(thread) |
| 273 { | 383 { |
| 274 var /** @const */ padding = 1; | 384 var events = thread.events; |
| 275 var visualHeight = (stripHeight - padding) * window.devicePixelRatio; | 385 var height = this._canvas.height; |
| 276 var timeOffset = this._model.minimumRecordTime(); | 386 var timeOffset = this._model.minimumRecordTime(); |
| 277 var timeSpan = this._model.maximumRecordTime() - timeOffset; | 387 var timeSpan = this._model.maximumRecordTime() - timeOffset; |
| 278 var scale = this._canvas.width / timeSpan; | 388 var scale = this._canvas.width / timeSpan; |
| 279 var ditherer = new WebInspector.Dithering(); | 389 var ditherer = new WebInspector.Dithering(); |
| 280 var categoryStack = []; | 390 var categoryStack = []; |
| 281 var lastX = 0; | 391 var lastX = 0; |
| 282 position += padding; | |
| 283 position *= window.devicePixelRatio; | |
| 284 | 392 |
| 285 /** | 393 /** |
| 286 * @param {!WebInspector.TracingModel.Event} e | 394 * @param {!WebInspector.TracingModel.Event} e |
| 287 * @this {WebInspector.TimelineEventOverview} | 395 * @this {WebInspector.TimelineEventOverview} |
| 288 */ | 396 */ |
| 289 function onEventStart(e) | 397 function onEventStart(e) |
| 290 { | 398 { |
| 291 var pos = (e.startTime - timeOffset) * scale; | 399 var pos = (e.startTime - timeOffset) * scale; |
| 292 if (categoryStack.length) { | 400 if (categoryStack.length) { |
| 293 var category = categoryStack.peekLast(); | 401 var category = categoryStack.peekLast(); |
| 294 var bar = ditherer.appendInterval(category, lastX, pos); | 402 var bar = ditherer.appendInterval(category, lastX, pos); |
| 295 if (bar) | 403 if (bar) |
| 296 this._renderBar(bar.start, bar.end, position, visualHeight, this._categoryColor(category)); | 404 this._renderBar(bar.start, bar.end, 0, height, this._categor yColor(category)); |
| 297 } | 405 } |
| 298 categoryStack.push(WebInspector.TimelineUIUtils.eventStyle(e).catego ry); | 406 categoryStack.push(WebInspector.TimelineUIUtils.eventStyle(e).catego ry); |
| 299 lastX = pos; | 407 lastX = pos; |
| 300 } | 408 } |
| 301 | 409 |
| 302 /** | 410 /** |
| 303 * @param {!WebInspector.TracingModel.Event} e | 411 * @param {!WebInspector.TracingModel.Event} e |
| 304 * @this {WebInspector.TimelineEventOverview} | 412 * @this {WebInspector.TimelineEventOverview} |
| 305 */ | 413 */ |
| 306 function onEventEnd(e) | 414 function onEventEnd(e) |
| 307 { | 415 { |
| 308 var category = categoryStack.pop(); | 416 var category = categoryStack.pop(); |
| 309 var pos = (e.endTime - timeOffset) * scale; | 417 var pos = (e.endTime - timeOffset) * scale; |
| 310 var bar = ditherer.appendInterval(category, lastX, pos); | 418 var bar = ditherer.appendInterval(category, lastX, pos); |
| 311 if (bar) | 419 if (bar) |
| 312 this._renderBar(bar.start, bar.end, position, visualHeight, this ._categoryColor(category)); | 420 this._renderBar(bar.start, bar.end, 0, height, this._categoryCol or(category)); |
| 313 lastX = pos; | 421 lastX = pos; |
| 314 } | 422 } |
| 315 | 423 |
| 316 WebInspector.TimelineModel.forEachEvent(events, onEventStart.bind(this), onEventEnd.bind(this)); | 424 WebInspector.TimelineModel.forEachEvent(events, onEventStart.bind(this), onEventEnd.bind(this)); |
| 317 return stripHeight; | |
| 318 }, | 425 }, |
| 319 | 426 |
| 427 __proto__: WebInspector.TimelineEventOverview.Thread.prototype | |
| 428 } | |
| 429 | |
| 430 /** | |
| 431 * @constructor | |
| 432 * @extends {WebInspector.TimelineEventOverview} | |
| 433 * @param {!WebInspector.TimelineModel} model | |
| 434 * @param {!WebInspector.TimelineFrameModelBase} frameModel | |
| 435 */ | |
| 436 WebInspector.TimelineEventOverview.Responsiveness = function(model, frameModel) | |
| 437 { | |
| 438 WebInspector.TimelineEventOverview.call(this, "responsiveness", model) | |
| 439 this._frameModel = frameModel; | |
| 440 } | |
| 441 | |
| 442 WebInspector.TimelineEventOverview.Responsiveness.prototype = { | |
| 320 /** | 443 /** |
| 321 * @param {!WebInspector.TimelineCategory} category | 444 * @override |
| 322 * @return {string} | |
| 323 */ | 445 */ |
| 324 _categoryColor: function(category) | 446 update: function() |
| 325 { | 447 { |
| 326 return category.hidden ? this._disabledCategoryFillStyle : this._fillSty les[category.name]; | 448 this.resetCanvas(); |
| 327 }, | 449 var height = this._canvas.height; |
| 328 | |
| 329 /** | |
| 330 * @param {number} position | |
| 331 * @param {number} height | |
| 332 * @return {number} | |
| 333 */ | |
| 334 _drawResponsivenessStrip: function(position, height) | |
| 335 { | |
| 336 var /** @const */ padding = 1; | |
| 337 var visualHeight = (height - padding) * window.devicePixelRatio; | |
| 338 var timeOffset = this._model.minimumRecordTime(); | 450 var timeOffset = this._model.minimumRecordTime(); |
| 339 var timeSpan = this._model.maximumRecordTime() - timeOffset; | 451 var timeSpan = this._model.maximumRecordTime() - timeOffset; |
| 340 var scale = this._canvas.width / timeSpan; | 452 var scale = this._canvas.width / timeSpan; |
| 341 var frames = this._frameModel.frames(); | 453 var frames = this._frameModel.frames(); |
| 342 var ctx = this._context; | 454 var ctx = this._context; |
| 343 ctx.beginPath(); | 455 ctx.beginPath(); |
| 344 var responsivenessStripY = (position + padding) * window.devicePixelRati o; | 456 var responsivenessStripY = (0 + 0) * window.devicePixelRatio; |
| 345 for (var i = 0; i < frames.length; ++i) { | 457 for (var i = 0; i < frames.length; ++i) { |
| 346 var frame = frames[i]; | 458 var frame = frames[i]; |
| 347 if (!frame.hasWarnings()) | 459 if (!frame.hasWarnings()) |
| 348 continue; | 460 continue; |
| 349 var x = scale * (frame.startTime - timeOffset); | 461 var x = scale * (frame.startTime - timeOffset); |
| 350 var w = scale * frame.duration; | 462 var w = scale * frame.duration; |
| 351 ctx.rect(x, responsivenessStripY, w, visualHeight); | 463 ctx.rect(x, responsivenessStripY, w, height); |
| 352 } | 464 } |
| 353 ctx.fillStyle = "hsl(0, 80%, 70%)"; | 465 ctx.fillStyle = "hsl(0, 80%, 70%)"; |
| 354 ctx.fill(); | 466 ctx.fill(); |
| 355 return height; | |
| 356 }, | 467 }, |
| 357 | 468 |
| 469 __proto__: WebInspector.TimelineEventOverview.prototype | |
| 470 } | |
| 471 | |
| 472 /** | |
| 473 * @constructor | |
| 474 * @extends {WebInspector.TimelineEventOverview} | |
| 475 * @param {!WebInspector.TimelineModel} model | |
| 476 * @param {!WebInspector.TimelineFrameModelBase} frameModel | |
| 477 */ | |
| 478 WebInspector.TimelineEventOverview.Frames = function(model, frameModel) | |
| 479 { | |
| 480 WebInspector.TimelineEventOverview.call(this, "framerate", model); | |
| 481 this._frameModel = frameModel; | |
| 482 } | |
| 483 | |
| 484 WebInspector.TimelineEventOverview.Frames.prototype = { | |
| 358 /** | 485 /** |
| 359 * @param {number} position | 486 * @override |
| 360 * @param {number} height | |
| 361 * @return {number} | |
| 362 */ | 487 */ |
| 363 _drawFrames: function(position, height) | 488 update: function() |
| 364 { | 489 { |
| 365 var /** @const */ padding = 2; | 490 this.resetCanvas(); |
| 491 var height = this._canvas.height; | |
| 492 var /** @const */ padding = 1 * window.devicePixelRatio; | |
| 366 var /** @const */ baseFrameDurationMs = 1e3 / 60; | 493 var /** @const */ baseFrameDurationMs = 1e3 / 60; |
| 367 var visualHeight = (height - padding) * window.devicePixelRatio; | 494 var visualHeight = height - 2 * padding; |
| 368 var timeOffset = this._model.minimumRecordTime(); | 495 var timeOffset = this._model.minimumRecordTime(); |
| 369 var timeSpan = this._model.maximumRecordTime() - timeOffset; | 496 var timeSpan = this._model.maximumRecordTime() - timeOffset; |
| 370 var scale = this._canvas.width / timeSpan; | 497 var scale = this._canvas.width / timeSpan; |
| 371 var frames = this._frameModel.frames(); | 498 var frames = this._frameModel.frames(); |
| 372 var baseY = height * window.devicePixelRatio; | 499 var baseY = height - padding; |
| 373 var ctx = this._context; | 500 var ctx = this._context; |
| 374 var y = baseY + 10; | 501 var bottomY = baseY + 10 * window.devicePixelRatio; |
| 502 var y = bottomY; | |
| 375 if (!frames.length) | 503 if (!frames.length) |
| 376 return height; | 504 return; |
| 377 | |
| 378 ctx.save(); | |
| 379 ctx.translate(0, position * window.devicePixelRatio); | |
| 380 ctx.beginPath(); | |
| 381 ctx.rect(0, 0, this._canvas.width, height * window.devicePixelRatio); | |
| 382 ctx.clip(); | |
| 383 | 505 |
| 384 this._drawHorizontalGuide(baseY - visualHeight - 0.5, WebInspector.UIStr ing("60\u2009fps")); | 506 this._drawHorizontalGuide(baseY - visualHeight - 0.5, WebInspector.UIStr ing("60\u2009fps")); |
| 385 | 507 |
| 386 var lineWidth = window.devicePixelRatio; | 508 var lineWidth = window.devicePixelRatio; |
| 387 var offset = lineWidth & 1 ? 0.5 : 0; | 509 var offset = lineWidth & 1 ? 0.5 : 0; |
| 388 var tickDepth = 1.5 * window.devicePixelRatio; | 510 var tickDepth = 1.5 * window.devicePixelRatio; |
| 389 ctx.beginPath(); | 511 ctx.beginPath(); |
| 390 ctx.moveTo(0, y); | 512 ctx.moveTo(0, y); |
| 391 for (var i = 0; i < frames.length; ++i) { | 513 for (var i = 0; i < frames.length; ++i) { |
| 392 var frame = frames[i]; | 514 var frame = frames[i]; |
| 393 var x = Math.round((frame.startTime - timeOffset) * scale) + offset; | 515 var x = Math.round((frame.startTime - timeOffset) * scale) + offset; |
| 394 ctx.lineTo(x, y); | 516 ctx.lineTo(x, y); |
| 395 ctx.lineTo(x, y + tickDepth); | 517 ctx.lineTo(x, y + tickDepth); |
| 396 y = frame.idle ? baseY + 1 : Math.round(baseY - visualHeight * Math. min(baseFrameDurationMs / frame.duration, 1)) - offset; | 518 y = frame.idle ? bottomY : Math.round(baseY - visualHeight * Math.mi n(baseFrameDurationMs / frame.duration, 1)) - offset; |
| 397 ctx.lineTo(x, y + tickDepth); | 519 ctx.lineTo(x, y + tickDepth); |
| 398 ctx.lineTo(x, y); | 520 ctx.lineTo(x, y); |
| 399 } | 521 } |
| 400 if (frames.length) { | 522 if (frames.length) { |
| 401 var lastFrame = frames.peekLast(); | 523 var lastFrame = frames.peekLast(); |
| 402 var x = Math.round((lastFrame.startTime + lastFrame.duration - timeO ffset) * scale) + offset; | 524 var x = Math.round((lastFrame.startTime + lastFrame.duration - timeO ffset) * scale) + offset; |
| 403 ctx.lineTo(x, y); | 525 ctx.lineTo(x, y); |
| 404 } | 526 } |
| 405 ctx.lineTo(x, baseY + 10); | 527 ctx.lineTo(x, bottomY); |
| 406 ctx.fillStyle = "hsl(110, 50%, 88%)"; | 528 ctx.fillStyle = "hsl(110, 50%, 88%)"; |
| 407 ctx.strokeStyle = "hsl(110, 50%, 60%)"; | 529 ctx.strokeStyle = "hsl(110, 50%, 60%)"; |
| 408 ctx.lineWidth = lineWidth; | 530 ctx.lineWidth = lineWidth; |
| 409 ctx.fill(); | 531 ctx.fill(); |
| 410 ctx.stroke(); | 532 ctx.stroke(); |
| 411 ctx.restore(); | |
| 412 return height; | |
| 413 }, | 533 }, |
| 414 | 534 |
| 415 /** | 535 __proto__: WebInspector.TimelineEventOverview.prototype |
| 416 * @param {number} y | |
| 417 * @param {string} label | |
| 418 */ | |
| 419 _drawHorizontalGuide: function(y, label) | |
| 420 { | |
| 421 var ctx = this._context; | |
| 422 ctx.save(); | |
| 423 ctx.translate(0, y); | |
| 424 ctx.scale(window.devicePixelRatio, window.devicePixelRatio); | |
| 425 ctx.beginPath(); | |
| 426 ctx.moveTo(0, 0); | |
| 427 ctx.lineTo(this._canvas.width, 0); | |
| 428 ctx.strokeStyle = "hsl(0, 0%, 85%)"; | |
| 429 ctx.setLineDash([3]); | |
| 430 ctx.lineWidth = 1; | |
| 431 ctx.stroke(); | |
| 432 ctx.fillStyle = "hsl(0, 0%, 70%)"; | |
| 433 ctx.font = "9px " + WebInspector.fontFamily(); | |
| 434 ctx.fillText(label, 4, 9); | |
| 435 ctx.restore(); | |
| 436 }, | |
| 437 | |
| 438 _onCategoryVisibilityChanged: function() | |
| 439 { | |
| 440 this.update(); | |
| 441 }, | |
| 442 | |
| 443 /** | |
| 444 * @param {number} begin | |
| 445 * @param {number} end | |
| 446 * @param {number} position | |
| 447 * @param {number} height | |
| 448 * @param {string} color | |
| 449 */ | |
| 450 _renderBar: function(begin, end, position, height, color) | |
| 451 { | |
| 452 var x = begin; | |
| 453 var width = end - begin; | |
| 454 this._context.fillStyle = color; | |
| 455 this._context.fillRect(x, position, width, height); | |
| 456 }, | |
| 457 | |
| 458 /** | |
| 459 * @override | |
| 460 * @param {number} windowLeft | |
| 461 * @param {number} windowRight | |
| 462 * @return {!{startTime: number, endTime: number}} | |
| 463 */ | |
| 464 windowTimes: function(windowLeft, windowRight) | |
| 465 { | |
| 466 var absoluteMin = this._model.minimumRecordTime(); | |
| 467 var timeSpan = this._model.maximumRecordTime() - absoluteMin; | |
| 468 return { | |
| 469 startTime: absoluteMin + timeSpan * windowLeft, | |
| 470 endTime: absoluteMin + timeSpan * windowRight | |
| 471 }; | |
| 472 }, | |
| 473 | |
| 474 /** | |
| 475 * @override | |
| 476 * @param {number} startTime | |
| 477 * @param {number} endTime | |
| 478 * @return {!{left: number, right: number}} | |
| 479 */ | |
| 480 windowBoundaries: function(startTime, endTime) | |
| 481 { | |
| 482 var absoluteMin = this._model.minimumRecordTime(); | |
| 483 var timeSpan = this._model.maximumRecordTime() - absoluteMin; | |
| 484 var haveRecords = absoluteMin > 0; | |
| 485 return { | |
| 486 left: haveRecords && startTime ? Math.min((startTime - absoluteMin) / timeSpan, 1) : 0, | |
| 487 right: haveRecords && endTime < Infinity ? (endTime - absoluteMin) / timeSpan : 1 | |
| 488 }; | |
| 489 }, | |
| 490 | |
| 491 __proto__: WebInspector.TimelineOverviewBase.prototype | |
| 492 } | 536 } |
| 493 | 537 |
| 494 /** | 538 /** |
| 495 * @constructor | 539 * @constructor |
| 496 * @template T | 540 * @template T |
| 497 */ | 541 */ |
| 498 WebInspector.Dithering = function() | 542 WebInspector.Dithering = function() |
| 499 { | 543 { |
| 500 /** @type {!Map.<?T,number>} */ | 544 /** @type {!Map.<?T,number>} */ |
| 501 this._groupError = new Map(); | 545 this._groupError = new Map(); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 606 counters[group] = this._quantDuration; | 650 counters[group] = this._quantDuration; |
| 607 this._callback(counters); | 651 this._callback(counters); |
| 608 interval -= this._quantDuration; | 652 interval -= this._quantDuration; |
| 609 } | 653 } |
| 610 this._counters = []; | 654 this._counters = []; |
| 611 this._counters[group] = interval; | 655 this._counters[group] = interval; |
| 612 this._lastTime = time; | 656 this._lastTime = time; |
| 613 this._remainder = this._quantDuration - interval; | 657 this._remainder = this._quantDuration - interval; |
| 614 } | 658 } |
| 615 } | 659 } |
| OLD | NEW |