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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
11 * copyright notice, this list of conditions and the following disclaimer 11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the 12 * in the documentation and/or other materials provided with the
13 * distribution. 13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its 14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from 15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission. 16 * this software without specific prior written permission.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
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 * @unrestricted
32 * @constructor 32 */
33 * @extends {WebInspector.TimelineOverviewBase} 33 WebInspector.TimelineEventOverview = class extends WebInspector.TimelineOverview Base {
34 * @param {string} id 34 /**
35 * @param {?string} title 35 * @param {string} id
36 * @param {!WebInspector.TimelineModel} model 36 * @param {?string} title
37 */ 37 * @param {!WebInspector.TimelineModel} model
38 WebInspector.TimelineEventOverview = function(id, title, model) 38 */
39 { 39 constructor(id, title, model) {
40 WebInspector.TimelineOverviewBase.call(this); 40 super();
41 this.element.id = "timeline-overview-" + id; 41 this.element.id = 'timeline-overview-' + id;
42 this.element.classList.add("overview-strip"); 42 this.element.classList.add('overview-strip');
43 if (title) 43 if (title)
44 this.element.createChild("div", "timeline-overview-strip-title").textCon tent = title; 44 this.element.createChild('div', 'timeline-overview-strip-title').textConte nt = title;
45 this._model = model; 45 this._model = model;
46 }; 46 }
47 47
48 WebInspector.TimelineEventOverview.prototype = { 48 /**
49 /** 49 * @param {number} begin
50 * @param {number} begin 50 * @param {number} end
51 * @param {number} end 51 * @param {number} position
52 * @param {number} position 52 * @param {number} height
53 * @param {number} height 53 * @param {string} color
54 * @param {string} color 54 */
55 */ 55 _renderBar(begin, end, position, height, color) {
56 _renderBar: function(begin, end, position, height, color) 56 var x = begin;
57 { 57 var width = end - begin;
58 var x = begin; 58 this._context.fillStyle = color;
59 var width = end - begin; 59 this._context.fillRect(x, position, width, height);
60 this._context.fillStyle = color; 60 }
61 this._context.fillRect(x, position, width, height); 61
62 }, 62 /**
63 63 * @override
64 /** 64 * @param {number} windowLeft
65 * @override 65 * @param {number} windowRight
66 * @param {number} windowLeft 66 * @return {!{startTime: number, endTime: number}}
67 * @param {number} windowRight 67 */
68 * @return {!{startTime: number, endTime: number}} 68 windowTimes(windowLeft, windowRight) {
69 */ 69 var absoluteMin = this._model.minimumRecordTime();
70 windowTimes: function(windowLeft, windowRight) 70 var timeSpan = this._model.maximumRecordTime() - absoluteMin;
71 { 71 return {startTime: absoluteMin + timeSpan * windowLeft, endTime: absoluteMin + timeSpan * windowRight};
72 var absoluteMin = this._model.minimumRecordTime(); 72 }
73 var timeSpan = this._model.maximumRecordTime() - absoluteMin; 73
74 return { 74 /**
75 startTime: absoluteMin + timeSpan * windowLeft, 75 * @override
76 endTime: absoluteMin + timeSpan * windowRight 76 * @param {number} startTime
77 }; 77 * @param {number} endTime
78 }, 78 * @return {!{left: number, right: number}}
79 79 */
80 /** 80 windowBoundaries(startTime, endTime) {
81 * @override 81 var absoluteMin = this._model.minimumRecordTime();
82 * @param {number} startTime 82 var timeSpan = this._model.maximumRecordTime() - absoluteMin;
83 * @param {number} endTime 83 var haveRecords = absoluteMin > 0;
84 * @return {!{left: number, right: number}} 84 return {
85 */ 85 left: haveRecords && startTime ? Math.min((startTime - absoluteMin) / time Span, 1) : 0,
86 windowBoundaries: function(startTime, endTime) 86 right: haveRecords && endTime < Infinity ? (endTime - absoluteMin) / timeS pan : 1
87 { 87 };
88 var absoluteMin = this._model.minimumRecordTime(); 88 }
89 var timeSpan = this._model.maximumRecordTime() - absoluteMin; 89 };
90 var haveRecords = absoluteMin > 0; 90
91 return { 91 /**
92 left: haveRecords && startTime ? Math.min((startTime - absoluteMin) / timeSpan, 1) : 0, 92 * @unrestricted
93 right: haveRecords && endTime < Infinity ? (endTime - absoluteMin) / timeSpan : 1 93 */
94 }; 94 WebInspector.TimelineEventOverviewInput = class extends WebInspector.TimelineEve ntOverview {
95 }, 95 /**
96 96 * @param {!WebInspector.TimelineModel} model
97 __proto__: WebInspector.TimelineOverviewBase.prototype 97 */
98 }; 98 constructor(model) {
99 99 super('input', null, model);
100 /** 100 }
101 * @constructor 101
102 * @extends {WebInspector.TimelineEventOverview} 102 /**
103 * @param {!WebInspector.TimelineModel} model 103 * @override
104 */ 104 */
105 WebInspector.TimelineEventOverview.Input = function(model) 105 update() {
106 { 106 super.update();
107 WebInspector.TimelineEventOverview.call(this, "input", null, model); 107 var events = this._model.mainThreadEvents();
108 }; 108 var height = this._canvas.height;
109 109 var descriptors = WebInspector.TimelineUIUtils.eventDispatchDesciptors();
110 WebInspector.TimelineEventOverview.Input.prototype = { 110 /** @type {!Map.<string,!WebInspector.TimelineUIUtils.EventDispatchTypeDescr iptor>} */
111 /** 111 var descriptorsByType = new Map();
112 * @override 112 var maxPriority = -1;
113 */ 113 for (var descriptor of descriptors) {
114 update: function() 114 for (var type of descriptor.eventTypes)
115 { 115 descriptorsByType.set(type, descriptor);
116 WebInspector.TimelineEventOverview.prototype.update.call(this); 116 maxPriority = Math.max(maxPriority, descriptor.priority);
117 var events = this._model.mainThreadEvents(); 117 }
118 var height = this._canvas.height; 118
119 var descriptors = WebInspector.TimelineUIUtils.eventDispatchDesciptors() ; 119 var /** @const */ minWidth = 2 * window.devicePixelRatio;
120 /** @type {!Map.<string,!WebInspector.TimelineUIUtils.EventDispatchTypeD escriptor>} */ 120 var timeOffset = this._model.minimumRecordTime();
121 var descriptorsByType = new Map(); 121 var timeSpan = this._model.maximumRecordTime() - timeOffset;
122 var maxPriority = -1; 122 var canvasWidth = this._canvas.width;
123 for (var descriptor of descriptors) { 123 var scale = canvasWidth / timeSpan;
124 for (var type of descriptor.eventTypes) 124
125 descriptorsByType.set(type, descriptor); 125 for (var priority = 0; priority <= maxPriority; ++priority) {
126 maxPriority = Math.max(maxPriority, descriptor.priority); 126 for (var i = 0; i < events.length; ++i) {
127 var event = events[i];
128 if (event.name !== WebInspector.TimelineModel.RecordType.EventDispatch)
129 continue;
130 var descriptor = descriptorsByType.get(event.args['data']['type']);
131 if (!descriptor || descriptor.priority !== priority)
132 continue;
133 var start = Number.constrain(Math.floor((event.startTime - timeOffset) * scale), 0, canvasWidth);
134 var end = Number.constrain(Math.ceil((event.endTime - timeOffset) * scal e), 0, canvasWidth);
135 var width = Math.max(end - start, minWidth);
136 this._renderBar(start, start + width, 0, height, descriptor.color);
137 }
138 }
139 }
140 };
141
142 /**
143 * @unrestricted
144 */
145 WebInspector.TimelineEventOverviewNetwork = class extends WebInspector.TimelineE ventOverview {
146 /**
147 * @param {!WebInspector.TimelineModel} model
148 */
149 constructor(model) {
150 super('network', WebInspector.UIString('NET'), model);
151 }
152
153 /**
154 * @override
155 */
156 update() {
157 super.update();
158 var height = this._canvas.height;
159 var numBands = categoryBand(WebInspector.TimelineUIUtils.NetworkCategory.Oth er) + 1;
160 var bandHeight = Math.floor(height / numBands);
161 var devicePixelRatio = window.devicePixelRatio;
162 var timeOffset = this._model.minimumRecordTime();
163 var timeSpan = this._model.maximumRecordTime() - timeOffset;
164 var canvasWidth = this._canvas.width;
165 var scale = canvasWidth / timeSpan;
166 var ctx = this._context;
167 var requests = this._model.networkRequests();
168 /** @type {!Map<string,!{waiting:!Path2D,transfer:!Path2D}>} */
169 var paths = new Map();
170 requests.forEach(drawRequest);
171 for (var path of paths) {
172 ctx.fillStyle = path[0];
173 ctx.globalAlpha = 0.3;
174 ctx.fill(path[1]['waiting']);
175 ctx.globalAlpha = 1;
176 ctx.fill(path[1]['transfer']);
177 }
178
179 /**
180 * @param {!WebInspector.TimelineUIUtils.NetworkCategory} category
181 * @return {number}
182 */
183 function categoryBand(category) {
184 var categories = WebInspector.TimelineUIUtils.NetworkCategory;
185 switch (category) {
186 case categories.HTML:
187 return 0;
188 case categories.Script:
189 return 1;
190 case categories.Style:
191 return 2;
192 case categories.Media:
193 return 3;
194 default:
195 return 4;
196 }
197 }
198
199 /**
200 * @param {!WebInspector.TimelineModel.NetworkRequest} request
201 */
202 function drawRequest(request) {
203 var tickWidth = 2 * devicePixelRatio;
204 var category = WebInspector.TimelineUIUtils.networkRequestCategory(request );
205 var style = WebInspector.TimelineUIUtils.networkCategoryColor(category);
206 var band = categoryBand(category);
207 var y = band * bandHeight;
208 var path = paths.get(style);
209 if (!path) {
210 path = {waiting: new Path2D(), transfer: new Path2D()};
211 paths.set(style, path);
212 }
213 var s = Math.max(Math.floor((request.startTime - timeOffset) * scale), 0);
214 var e = Math.min(Math.ceil((request.endTime - timeOffset) * scale), canvas Width);
215 path['waiting'].rect(s, y, e - s, bandHeight - 1);
216 path['transfer'].rect(e - tickWidth / 2, y, tickWidth, bandHeight - 1);
217 if (!request.responseTime)
218 return;
219 var r = Math.ceil((request.responseTime - timeOffset) * scale);
220 path['transfer'].rect(r - tickWidth / 2, y, tickWidth, bandHeight - 1);
221 }
222 }
223 };
224
225 /**
226 * @unrestricted
227 */
228 WebInspector.TimelineEventOverviewCPUActivity = class extends WebInspector.Timel ineEventOverview {
229 /**
230 * @param {!WebInspector.TimelineModel} model
231 */
232 constructor(model) {
233 super('cpu-activity', WebInspector.UIString('CPU'), model);
234 this._backgroundCanvas = this.element.createChild('canvas', 'fill background ');
235 }
236
237 /**
238 * @override
239 */
240 resetCanvas() {
241 super.resetCanvas();
242 this._backgroundCanvas.width = this.element.clientWidth * window.devicePixel Ratio;
243 this._backgroundCanvas.height = this.element.clientHeight * window.devicePix elRatio;
244 }
245
246 /**
247 * @override
248 */
249 update() {
250 super.update();
251 var /** @const */ quantSizePx = 4 * window.devicePixelRatio;
252 var width = this._canvas.width;
253 var height = this._canvas.height;
254 var baseLine = height;
255 var timeOffset = this._model.minimumRecordTime();
256 var timeSpan = this._model.maximumRecordTime() - timeOffset;
257 var scale = width / timeSpan;
258 var quantTime = quantSizePx / scale;
259 var categories = WebInspector.TimelineUIUtils.categories();
260 var categoryOrder = ['idle', 'loading', 'painting', 'rendering', 'scripting' , 'other'];
261 var otherIndex = categoryOrder.indexOf('other');
262 var idleIndex = 0;
263 console.assert(idleIndex === categoryOrder.indexOf('idle'));
264 for (var i = idleIndex + 1; i < categoryOrder.length; ++i)
265 categories[categoryOrder[i]]._overviewIndex = i;
266
267 var backgroundContext = this._backgroundCanvas.getContext('2d');
268 for (var thread of this._model.virtualThreads())
269 drawThreadEvents(backgroundContext, thread.events);
270 applyPattern(backgroundContext);
271 drawThreadEvents(this._context, this._model.mainThreadEvents());
272
273 /**
274 * @param {!CanvasRenderingContext2D} ctx
275 * @param {!Array<!WebInspector.TracingModel.Event>} events
276 */
277 function drawThreadEvents(ctx, events) {
278 var quantizer = new WebInspector.Quantizer(timeOffset, quantTime, drawSamp le);
279 var x = 0;
280 var categoryIndexStack = [];
281 var paths = [];
282 var lastY = [];
283 for (var i = 0; i < categoryOrder.length; ++i) {
284 paths[i] = new Path2D();
285 paths[i].moveTo(0, height);
286 lastY[i] = height;
287 }
288
289 /**
290 * @param {!Array<number>} counters
291 */
292 function drawSample(counters) {
293 var y = baseLine;
294 for (var i = idleIndex + 1; i < categoryOrder.length; ++i) {
295 var h = (counters[i] || 0) / quantTime * height;
296 y -= h;
297 paths[i].bezierCurveTo(x, lastY[i], x, y, x + quantSizePx / 2, y);
298 lastY[i] = y;
127 } 299 }
128 300 x += quantSizePx;
129 var /** @const */ minWidth = 2 * window.devicePixelRatio; 301 }
130 var timeOffset = this._model.minimumRecordTime(); 302
131 var timeSpan = this._model.maximumRecordTime() - timeOffset; 303 /**
132 var canvasWidth = this._canvas.width; 304 * @param {!WebInspector.TracingModel.Event} e
133 var scale = canvasWidth / timeSpan; 305 */
134 306 function onEventStart(e) {
135 for (var priority = 0; priority <= maxPriority; ++priority) { 307 var index = categoryIndexStack.length ? categoryIndexStack.peekLast() : idleIndex;
136 for (var i = 0; i < events.length; ++i) { 308 quantizer.appendInterval(e.startTime, index);
137 var event = events[i]; 309 categoryIndexStack.push(WebInspector.TimelineUIUtils.eventStyle(e).categ ory._overviewIndex || otherIndex);
138 if (event.name !== WebInspector.TimelineModel.RecordType.EventDi spatch) 310 }
139 continue; 311
140 var descriptor = descriptorsByType.get(event.args["data"]["type" ]); 312 /**
141 if (!descriptor || descriptor.priority !== priority) 313 * @param {!WebInspector.TracingModel.Event} e
142 continue; 314 */
143 var start = Number.constrain(Math.floor((event.startTime - timeO ffset) * scale), 0, canvasWidth); 315 function onEventEnd(e) {
144 var end = Number.constrain(Math.ceil((event.endTime - timeOffset ) * scale), 0, canvasWidth); 316 quantizer.appendInterval(e.endTime, categoryIndexStack.pop());
145 var width = Math.max(end - start, minWidth); 317 }
146 this._renderBar(start, start + width, 0, height, descriptor.colo r); 318
147 } 319 WebInspector.TimelineModel.forEachEvent(events, onEventStart, onEventEnd);
148 } 320 quantizer.appendInterval(timeOffset + timeSpan + quantTime, idleIndex); / / Kick drawing the last bucket.
149 }, 321 for (var i = categoryOrder.length - 1; i > 0; --i) {
150 322 paths[i].lineTo(width, height);
151 __proto__: WebInspector.TimelineEventOverview.prototype 323 ctx.fillStyle = categories[categoryOrder[i]].color;
152 }; 324 ctx.fill(paths[i]);
153 325 }
154 /** 326 }
155 * @constructor 327
156 * @extends {WebInspector.TimelineEventOverview} 328 /**
157 * @param {!WebInspector.TimelineModel} model 329 * @param {!CanvasRenderingContext2D} ctx
158 */ 330 */
159 WebInspector.TimelineEventOverview.Network = function(model) 331 function applyPattern(ctx) {
160 { 332 var step = 4 * window.devicePixelRatio;
161 WebInspector.TimelineEventOverview.call(this, "network", WebInspector.UIStri ng("NET"), model); 333 ctx.save();
162 }; 334 ctx.lineWidth = step / Math.sqrt(8);
163 335 for (var x = 0.5; x < width + height; x += step) {
164 WebInspector.TimelineEventOverview.Network.prototype = { 336 ctx.moveTo(x, 0);
165 /** 337 ctx.lineTo(x - height, height);
166 * @override 338 }
167 */ 339 ctx.globalCompositeOperation = 'destination-out';
168 update: function() 340 ctx.stroke();
169 { 341 ctx.restore();
170 WebInspector.TimelineEventOverview.prototype.update.call(this); 342 }
171 var height = this._canvas.height; 343 }
172 var numBands = categoryBand(WebInspector.TimelineUIUtils.NetworkCategory .Other) + 1; 344 };
173 var bandHeight = Math.floor(height / numBands); 345
174 var devicePixelRatio = window.devicePixelRatio; 346 /**
175 var timeOffset = this._model.minimumRecordTime(); 347 * @unrestricted
176 var timeSpan = this._model.maximumRecordTime() - timeOffset; 348 */
177 var canvasWidth = this._canvas.width; 349 WebInspector.TimelineEventOverviewResponsiveness = class extends WebInspector.Ti melineEventOverview {
178 var scale = canvasWidth / timeSpan; 350 /**
179 var ctx = this._context; 351 * @param {!WebInspector.TimelineModel} model
180 var requests = this._model.networkRequests(); 352 * @param {!WebInspector.TimelineFrameModel} frameModel
181 /** @type {!Map<string,!{waiting:!Path2D,transfer:!Path2D}>} */ 353 */
182 var paths = new Map(); 354 constructor(model, frameModel) {
183 requests.forEach(drawRequest); 355 super('responsiveness', null, model);
184 for (var path of paths) {
185 ctx.fillStyle = path[0];
186 ctx.globalAlpha = 0.3;
187 ctx.fill(path[1]["waiting"]);
188 ctx.globalAlpha = 1;
189 ctx.fill(path[1]["transfer"]);
190 }
191
192 /**
193 * @param {!WebInspector.TimelineUIUtils.NetworkCategory} category
194 * @return {number}
195 */
196 function categoryBand(category)
197 {
198 var categories = WebInspector.TimelineUIUtils.NetworkCategory;
199 switch (category) {
200 case categories.HTML: return 0;
201 case categories.Script: return 1;
202 case categories.Style: return 2;
203 case categories.Media: return 3;
204 default: return 4;
205 }
206 }
207
208 /**
209 * @param {!WebInspector.TimelineModel.NetworkRequest} request
210 */
211 function drawRequest(request)
212 {
213 var tickWidth = 2 * devicePixelRatio;
214 var category = WebInspector.TimelineUIUtils.networkRequestCategory(r equest);
215 var style = WebInspector.TimelineUIUtils.networkCategoryColor(catego ry);
216 var band = categoryBand(category);
217 var y = band * bandHeight;
218 var path = paths.get(style);
219 if (!path) {
220 path = { waiting: new Path2D(), transfer: new Path2D() };
221 paths.set(style, path);
222 }
223 var s = Math.max(Math.floor((request.startTime - timeOffset) * scale ), 0);
224 var e = Math.min(Math.ceil((request.endTime - timeOffset) * scale), canvasWidth);
225 path["waiting"].rect(s, y, e - s, bandHeight - 1);
226 path["transfer"].rect(e - tickWidth / 2, y, tickWidth, bandHeight - 1);
227 if (!request.responseTime)
228 return;
229 var r = Math.ceil((request.responseTime - timeOffset) * scale);
230 path["transfer"].rect(r - tickWidth / 2, y, tickWidth, bandHeight - 1);
231 }
232 },
233
234 __proto__: WebInspector.TimelineEventOverview.prototype
235 };
236
237 /**
238 * @constructor
239 * @extends {WebInspector.TimelineEventOverview}
240 * @param {!WebInspector.TimelineModel} model
241 */
242 WebInspector.TimelineEventOverview.CPUActivity = function(model)
243 {
244 WebInspector.TimelineEventOverview.call(this, "cpu-activity", WebInspector.U IString("CPU"), model);
245 this._backgroundCanvas = this.element.createChild("canvas", "fill background ");
246 };
247
248 WebInspector.TimelineEventOverview.CPUActivity.prototype = {
249 /**
250 * @override
251 */
252 resetCanvas: function()
253 {
254 WebInspector.TimelineEventOverview.prototype.resetCanvas.call(this);
255 this._backgroundCanvas.width = this.element.clientWidth * window.deviceP ixelRatio;
256 this._backgroundCanvas.height = this.element.clientHeight * window.devic ePixelRatio;
257 },
258
259 /**
260 * @override
261 */
262 update: function()
263 {
264 WebInspector.TimelineEventOverview.prototype.update.call(this);
265 var /** @const */ quantSizePx = 4 * window.devicePixelRatio;
266 var width = this._canvas.width;
267 var height = this._canvas.height;
268 var baseLine = height;
269 var timeOffset = this._model.minimumRecordTime();
270 var timeSpan = this._model.maximumRecordTime() - timeOffset;
271 var scale = width / timeSpan;
272 var quantTime = quantSizePx / scale;
273 var categories = WebInspector.TimelineUIUtils.categories();
274 var categoryOrder = ["idle", "loading", "painting", "rendering", "script ing", "other"];
275 var otherIndex = categoryOrder.indexOf("other");
276 var idleIndex = 0;
277 console.assert(idleIndex === categoryOrder.indexOf("idle"));
278 for (var i = idleIndex + 1; i < categoryOrder.length; ++i)
279 categories[categoryOrder[i]]._overviewIndex = i;
280
281 var backgroundContext = this._backgroundCanvas.getContext("2d");
282 for (var thread of this._model.virtualThreads())
283 drawThreadEvents(backgroundContext, thread.events);
284 applyPattern(backgroundContext);
285 drawThreadEvents(this._context, this._model.mainThreadEvents());
286
287 /**
288 * @param {!CanvasRenderingContext2D} ctx
289 * @param {!Array<!WebInspector.TracingModel.Event>} events
290 */
291 function drawThreadEvents(ctx, events)
292 {
293 var quantizer = new WebInspector.Quantizer(timeOffset, quantTime, dr awSample);
294 var x = 0;
295 var categoryIndexStack = [];
296 var paths = [];
297 var lastY = [];
298 for (var i = 0; i < categoryOrder.length; ++i) {
299 paths[i] = new Path2D();
300 paths[i].moveTo(0, height);
301 lastY[i] = height;
302 }
303
304 /**
305 * @param {!Array<number>} counters
306 */
307 function drawSample(counters)
308 {
309 var y = baseLine;
310 for (var i = idleIndex + 1; i < categoryOrder.length; ++i) {
311 var h = (counters[i] || 0) / quantTime * height;
312 y -= h;
313 paths[i].bezierCurveTo(x, lastY[i], x, y, x + quantSizePx / 2, y);
314 lastY[i] = y;
315 }
316 x += quantSizePx;
317 }
318
319 /**
320 * @param {!WebInspector.TracingModel.Event} e
321 */
322 function onEventStart(e)
323 {
324 var index = categoryIndexStack.length ? categoryIndexStack.peekL ast() : idleIndex;
325 quantizer.appendInterval(e.startTime, index);
326 categoryIndexStack.push(WebInspector.TimelineUIUtils.eventStyle( e).category._overviewIndex || otherIndex);
327 }
328
329 /**
330 * @param {!WebInspector.TracingModel.Event} e
331 */
332 function onEventEnd(e)
333 {
334 quantizer.appendInterval(e.endTime, categoryIndexStack.pop());
335 }
336
337 WebInspector.TimelineModel.forEachEvent(events, onEventStart, onEven tEnd);
338 quantizer.appendInterval(timeOffset + timeSpan + quantTime, idleInde x); // Kick drawing the last bucket.
339 for (var i = categoryOrder.length - 1; i > 0; --i) {
340 paths[i].lineTo(width, height);
341 ctx.fillStyle = categories[categoryOrder[i]].color;
342 ctx.fill(paths[i]);
343 }
344 }
345
346 /**
347 * @param {!CanvasRenderingContext2D} ctx
348 */
349 function applyPattern(ctx)
350 {
351 var step = 4 * window.devicePixelRatio;
352 ctx.save();
353 ctx.lineWidth = step / Math.sqrt(8);
354 for (var x = 0.5; x < width + height; x += step) {
355 ctx.moveTo(x, 0);
356 ctx.lineTo(x - height, height);
357 }
358 ctx.globalCompositeOperation = "destination-out";
359 ctx.stroke();
360 ctx.restore();
361 }
362 },
363
364 __proto__: WebInspector.TimelineEventOverview.prototype
365 };
366
367 /**
368 * @constructor
369 * @extends {WebInspector.TimelineEventOverview}
370 * @param {!WebInspector.TimelineModel} model
371 * @param {!WebInspector.TimelineFrameModel} frameModel
372 */
373 WebInspector.TimelineEventOverview.Responsiveness = function(model, frameModel)
374 {
375 WebInspector.TimelineEventOverview.call(this, "responsiveness", null, model) ;
376 this._frameModel = frameModel; 356 this._frameModel = frameModel;
377 }; 357 }
378 358
379 WebInspector.TimelineEventOverview.Responsiveness.prototype = { 359 /**
380 /** 360 * @override
381 * @override 361 */
382 */ 362 update() {
383 update: function() 363 super.update();
384 { 364 var height = this._canvas.height;
385 WebInspector.TimelineEventOverview.prototype.update.call(this); 365 var timeOffset = this._model.minimumRecordTime();
386 var height = this._canvas.height; 366 var timeSpan = this._model.maximumRecordTime() - timeOffset;
387 var timeOffset = this._model.minimumRecordTime(); 367 var scale = this._canvas.width / timeSpan;
388 var timeSpan = this._model.maximumRecordTime() - timeOffset; 368 var frames = this._frameModel.frames();
389 var scale = this._canvas.width / timeSpan; 369 var ctx = this._context;
390 var frames = this._frameModel.frames(); 370 var fillPath = new Path2D();
391 var ctx = this._context; 371 var markersPath = new Path2D();
392 var fillPath = new Path2D(); 372 for (var i = 0; i < frames.length; ++i) {
393 var markersPath = new Path2D(); 373 var frame = frames[i];
394 for (var i = 0; i < frames.length; ++i) { 374 if (!frame.hasWarnings())
395 var frame = frames[i]; 375 continue;
396 if (!frame.hasWarnings()) 376 paintWarningDecoration(frame.startTime, frame.duration);
397 continue; 377 }
398 paintWarningDecoration(frame.startTime, frame.duration); 378
399 } 379 var events = this._model.mainThreadEvents();
400 380 for (var i = 0; i < events.length; ++i) {
401 var events = this._model.mainThreadEvents(); 381 if (!events[i].warning)
402 for (var i = 0; i < events.length; ++i) { 382 continue;
403 if (!events[i].warning) 383 paintWarningDecoration(events[i].startTime, events[i].duration);
404 continue; 384 }
405 paintWarningDecoration(events[i].startTime, events[i].duration); 385
406 } 386 ctx.fillStyle = 'hsl(0, 80%, 90%)';
407 387 ctx.strokeStyle = 'red';
408 ctx.fillStyle = "hsl(0, 80%, 90%)"; 388 ctx.lineWidth = 2 * window.devicePixelRatio;
409 ctx.strokeStyle = "red"; 389 ctx.fill(fillPath);
410 ctx.lineWidth = 2 * window.devicePixelRatio; 390 ctx.stroke(markersPath);
411 ctx.fill(fillPath); 391
412 ctx.stroke(markersPath); 392 /**
413 393 * @param {number} time
414 /** 394 * @param {number} duration
415 * @param {number} time 395 */
416 * @param {number} duration 396 function paintWarningDecoration(time, duration) {
417 */ 397 var x = Math.round(scale * (time - timeOffset));
418 function paintWarningDecoration(time, duration) 398 var w = Math.round(scale * duration);
419 { 399 fillPath.rect(x, 0, w, height);
420 var x = Math.round(scale * (time - timeOffset)); 400 markersPath.moveTo(x + w, 0);
421 var w = Math.round(scale * duration); 401 markersPath.lineTo(x + w, height);
422 fillPath.rect(x, 0, w, height); 402 }
423 markersPath.moveTo(x + w, 0); 403 }
424 markersPath.lineTo(x + w, height); 404 };
425 } 405
426 }, 406 /**
427 407 * @unrestricted
428 __proto__: WebInspector.TimelineEventOverview.prototype 408 */
429 }; 409 WebInspector.TimelineFilmStripOverview = class extends WebInspector.TimelineEven tOverview {
430 410 /**
431 /** 411 * @param {!WebInspector.TimelineModel} model
432 * @constructor 412 * @param {!WebInspector.FilmStripModel} filmStripModel
433 * @extends {WebInspector.TimelineEventOverview} 413 */
434 * @param {!WebInspector.TimelineModel} model 414 constructor(model, filmStripModel) {
435 * @param {!WebInspector.FilmStripModel} filmStripModel 415 super('filmstrip', null, model);
436 */
437 WebInspector.TimelineFilmStripOverview = function(model, filmStripModel)
438 {
439 WebInspector.TimelineEventOverview.call(this, "filmstrip", null, model);
440 this._filmStripModel = filmStripModel; 416 this._filmStripModel = filmStripModel;
441 this.reset(); 417 this.reset();
418 }
419
420 /**
421 * @override
422 */
423 update() {
424 super.update();
425 var frames = this._filmStripModel.frames();
426 if (!frames.length)
427 return;
428
429 var drawGeneration = Symbol('drawGeneration');
430 this._drawGeneration = drawGeneration;
431 this._imageByFrame(frames[0]).then(image => {
432 if (this._drawGeneration !== drawGeneration)
433 return;
434 if (!image.naturalWidth || !image.naturalHeight)
435 return;
436 var imageHeight = this._canvas.height - 2 * WebInspector.TimelineFilmStrip Overview.Padding;
437 var imageWidth = Math.ceil(imageHeight * image.naturalWidth / image.natura lHeight);
438 var popoverScale = Math.min(200 / image.naturalWidth, 1);
439 this._emptyImage = new Image(image.naturalWidth * popoverScale, image.natu ralHeight * popoverScale);
440 this._drawFrames(imageWidth, imageHeight);
441 });
442 }
443
444 /**
445 * @param {!WebInspector.FilmStripModel.Frame} frame
446 * @return {!Promise<!HTMLImageElement>}
447 */
448 _imageByFrame(frame) {
449 var imagePromise = this._frameToImagePromise.get(frame);
450 if (!imagePromise) {
451 imagePromise = frame.imageDataPromise().then(createImage);
452 this._frameToImagePromise.set(frame, imagePromise);
453 }
454 return imagePromise;
455
456 /**
457 * @param {?string} data
458 * @return {!Promise<!HTMLImageElement>}
459 */
460 function createImage(data) {
461 var fulfill;
462 var promise = new Promise(f => fulfill = f);
463
464 var image = /** @type {!HTMLImageElement} */ (createElement('img'));
465 if (data)
466 image.src = 'data:image/jpg;base64,' + data;
467 if (image.complete) {
468 fulfill(image);
469 } else {
470 image.addEventListener('load', () => fulfill(image));
471 image.addEventListener('error', () => fulfill(image));
472 }
473 return promise;
474 }
475 }
476
477 /**
478 * @param {number} imageWidth
479 * @param {number} imageHeight
480 */
481 _drawFrames(imageWidth, imageHeight) {
482 if (!imageWidth)
483 return;
484 if (!this._filmStripModel.frames().length)
485 return;
486 var padding = WebInspector.TimelineFilmStripOverview.Padding;
487 var width = this._canvas.width;
488 var zeroTime = this._filmStripModel.zeroTime();
489 var spanTime = this._filmStripModel.spanTime();
490 var scale = spanTime / width;
491 var context = this._canvas.getContext('2d');
492 var drawGeneration = this._drawGeneration;
493
494 context.beginPath();
495 for (var x = padding; x < width; x += imageWidth + 2 * padding) {
496 var time = zeroTime + (x + imageWidth / 2) * scale;
497 var frame = this._filmStripModel.frameByTimestamp(time);
498 if (!frame)
499 continue;
500 context.rect(x - 0.5, 0.5, imageWidth + 1, imageHeight + 1);
501 this._imageByFrame(frame).then(drawFrameImage.bind(this, x));
502 }
503 context.strokeStyle = '#ddd';
504 context.stroke();
505
506 /**
507 * @param {number} x
508 * @param {!HTMLImageElement} image
509 * @this {WebInspector.TimelineFilmStripOverview}
510 */
511 function drawFrameImage(x, image) {
512 // Ignore draws deferred from a previous update call.
513 if (this._drawGeneration !== drawGeneration)
514 return;
515 context.drawImage(image, x, 1, imageWidth, imageHeight);
516 }
517 }
518
519 /**
520 * @override
521 * @param {number} x
522 * @return {!Promise<?Element>}
523 */
524 popoverElementPromise(x) {
525 if (!this._filmStripModel.frames().length)
526 return Promise.resolve(/** @type {?Element} */ (null));
527
528 var time = this._calculator.positionToTime(x);
529 var frame = this._filmStripModel.frameByTimestamp(time);
530 if (frame === this._lastFrame)
531 return Promise.resolve(this._lastElement);
532 var imagePromise = frame ? this._imageByFrame(frame) : Promise.resolve(this. _emptyImage);
533 return imagePromise.then(createFrameElement.bind(this));
534
535 /**
536 * @this {WebInspector.TimelineFilmStripOverview}
537 * @param {!HTMLImageElement} image
538 * @return {?Element}
539 */
540 function createFrameElement(image) {
541 var element = createElementWithClass('div', 'frame');
542 element.createChild('div', 'thumbnail').appendChild(image);
543 WebInspector.appendStyle(element, 'timeline/timelinePanel.css');
544 this._lastFrame = frame;
545 this._lastElement = element;
546 return element;
547 }
548 }
549
550 /**
551 * @override
552 */
553 reset() {
554 this._lastFrame = undefined;
555 this._lastElement = null;
556 /** @type {!Map<!WebInspector.FilmStripModel.Frame,!Promise<!HTMLImageElemen t>>} */
557 this._frameToImagePromise = new Map();
558 this._imageWidth = 0;
559 }
442 }; 560 };
443 561
444 WebInspector.TimelineFilmStripOverview.Padding = 2; 562 WebInspector.TimelineFilmStripOverview.Padding = 2;
445 563
446 WebInspector.TimelineFilmStripOverview.prototype = { 564 /**
447 /** 565 * @unrestricted
448 * @override 566 */
449 */ 567 WebInspector.TimelineEventOverviewFrames = class extends WebInspector.TimelineEv entOverview {
450 update: function() 568 /**
451 { 569 * @param {!WebInspector.TimelineModel} model
452 WebInspector.TimelineEventOverview.prototype.update.call(this); 570 * @param {!WebInspector.TimelineFrameModel} frameModel
453 var frames = this._filmStripModel.frames(); 571 */
454 if (!frames.length) 572 constructor(model, frameModel) {
455 return; 573 super('framerate', WebInspector.UIString('FPS'), model);
456
457 var drawGeneration = Symbol("drawGeneration");
458 this._drawGeneration = drawGeneration;
459 this._imageByFrame(frames[0]).then(image => {
460 if (this._drawGeneration !== drawGeneration)
461 return;
462 if (!image.naturalWidth || !image.naturalHeight)
463 return;
464 var imageHeight = this._canvas.height - 2 * WebInspector.TimelineFil mStripOverview.Padding;
465 var imageWidth = Math.ceil(imageHeight * image.naturalWidth / image. naturalHeight);
466 var popoverScale = Math.min(200 / image.naturalWidth, 1);
467 this._emptyImage = new Image(image.naturalWidth * popoverScale, imag e.naturalHeight * popoverScale);
468 this._drawFrames(imageWidth, imageHeight);
469 });
470 },
471
472 /**
473 * @param {!WebInspector.FilmStripModel.Frame} frame
474 * @return {!Promise<!HTMLImageElement>}
475 */
476 _imageByFrame: function(frame)
477 {
478 var imagePromise = this._frameToImagePromise.get(frame);
479 if (!imagePromise) {
480 imagePromise = frame.imageDataPromise().then(createImage);
481 this._frameToImagePromise.set(frame, imagePromise);
482 }
483 return imagePromise;
484
485 /**
486 * @param {?string} data
487 * @return {!Promise<!HTMLImageElement>}
488 */
489 function createImage(data)
490 {
491 var fulfill;
492 var promise = new Promise(f => fulfill = f);
493
494 var image = /** @type {!HTMLImageElement} */ (createElement("img"));
495 if (data)
496 image.src = "data:image/jpg;base64," + data;
497 if (image.complete) {
498 fulfill(image);
499 } else {
500 image.addEventListener("load", () => fulfill(image));
501 image.addEventListener("error", () => fulfill(image));
502 }
503 return promise;
504 }
505 },
506
507 /**
508 * @param {number} imageWidth
509 * @param {number} imageHeight
510 */
511 _drawFrames: function(imageWidth, imageHeight)
512 {
513 if (!imageWidth)
514 return;
515 if (!this._filmStripModel.frames().length)
516 return;
517 var padding = WebInspector.TimelineFilmStripOverview.Padding;
518 var width = this._canvas.width;
519 var zeroTime = this._filmStripModel.zeroTime();
520 var spanTime = this._filmStripModel.spanTime();
521 var scale = spanTime / width;
522 var context = this._canvas.getContext("2d");
523 var drawGeneration = this._drawGeneration;
524
525 context.beginPath();
526 for (var x = padding; x < width; x += imageWidth + 2 * padding) {
527 var time = zeroTime + (x + imageWidth / 2) * scale;
528 var frame = this._filmStripModel.frameByTimestamp(time);
529 if (!frame)
530 continue;
531 context.rect(x - 0.5, 0.5, imageWidth + 1, imageHeight + 1);
532 this._imageByFrame(frame).then(drawFrameImage.bind(this, x));
533 }
534 context.strokeStyle = "#ddd";
535 context.stroke();
536
537 /**
538 * @param {number} x
539 * @param {!HTMLImageElement} image
540 * @this {WebInspector.TimelineFilmStripOverview}
541 */
542 function drawFrameImage(x, image)
543 {
544 // Ignore draws deferred from a previous update call.
545 if (this._drawGeneration !== drawGeneration)
546 return;
547 context.drawImage(image, x, 1, imageWidth, imageHeight);
548 }
549 },
550
551 /**
552 * @override
553 * @param {number} x
554 * @return {!Promise<?Element>}
555 */
556 popoverElementPromise: function(x)
557 {
558 if (!this._filmStripModel.frames().length)
559 return Promise.resolve(/** @type {?Element} */ (null));
560
561 var time = this._calculator.positionToTime(x);
562 var frame = this._filmStripModel.frameByTimestamp(time);
563 if (frame === this._lastFrame)
564 return Promise.resolve(this._lastElement);
565 var imagePromise = frame ? this._imageByFrame(frame) : Promise.resolve(t his._emptyImage);
566 return imagePromise.then(createFrameElement.bind(this));
567
568 /**
569 * @this {WebInspector.TimelineFilmStripOverview}
570 * @param {!HTMLImageElement} image
571 * @return {?Element}
572 */
573 function createFrameElement(image)
574 {
575 var element = createElementWithClass("div", "frame");
576 element.createChild("div", "thumbnail").appendChild(image);
577 WebInspector.appendStyle(element, "timeline/timelinePanel.css");
578 this._lastFrame = frame;
579 this._lastElement = element;
580 return element;
581 }
582 },
583
584 /**
585 * @override
586 */
587 reset: function()
588 {
589 this._lastFrame = undefined;
590 this._lastElement = null;
591 /** @type {!Map<!WebInspector.FilmStripModel.Frame,!Promise<!HTMLImageEl ement>>} */
592 this._frameToImagePromise = new Map();
593 this._imageWidth = 0;
594 },
595
596 __proto__: WebInspector.TimelineEventOverview.prototype
597 };
598
599 /**
600 * @constructor
601 * @extends {WebInspector.TimelineEventOverview}
602 * @param {!WebInspector.TimelineModel} model
603 * @param {!WebInspector.TimelineFrameModel} frameModel
604 */
605 WebInspector.TimelineEventOverview.Frames = function(model, frameModel)
606 {
607 WebInspector.TimelineEventOverview.call(this, "framerate", WebInspector.UISt ring("FPS"), model);
608 this._frameModel = frameModel; 574 this._frameModel = frameModel;
609 }; 575 }
610 576
611 WebInspector.TimelineEventOverview.Frames.prototype = { 577 /**
612 /** 578 * @override
613 * @override 579 */
614 */ 580 update() {
615 update: function() 581 super.update();
616 { 582 var height = this._canvas.height;
617 WebInspector.TimelineEventOverview.prototype.update.call(this); 583 var /** @const */ padding = 1 * window.devicePixelRatio;
618 var height = this._canvas.height; 584 var /** @const */ baseFrameDurationMs = 1e3 / 60;
619 var /** @const */ padding = 1 * window.devicePixelRatio; 585 var visualHeight = height - 2 * padding;
620 var /** @const */ baseFrameDurationMs = 1e3 / 60; 586 var timeOffset = this._model.minimumRecordTime();
621 var visualHeight = height - 2 * padding; 587 var timeSpan = this._model.maximumRecordTime() - timeOffset;
622 var timeOffset = this._model.minimumRecordTime(); 588 var scale = this._canvas.width / timeSpan;
623 var timeSpan = this._model.maximumRecordTime() - timeOffset; 589 var frames = this._frameModel.frames();
624 var scale = this._canvas.width / timeSpan; 590 var baseY = height - padding;
625 var frames = this._frameModel.frames(); 591 var ctx = this._context;
626 var baseY = height - padding; 592 var bottomY = baseY + 10 * window.devicePixelRatio;
627 var ctx = this._context; 593 var y = bottomY;
628 var bottomY = baseY + 10 * window.devicePixelRatio; 594 if (!frames.length)
629 var y = bottomY; 595 return;
630 if (!frames.length) 596
631 return; 597 var lineWidth = window.devicePixelRatio;
632 598 var offset = lineWidth & 1 ? 0.5 : 0;
633 var lineWidth = window.devicePixelRatio; 599 var tickDepth = 1.5 * window.devicePixelRatio;
634 var offset = lineWidth & 1 ? 0.5 : 0; 600 ctx.beginPath();
635 var tickDepth = 1.5 * window.devicePixelRatio; 601 ctx.moveTo(0, y);
636 ctx.beginPath(); 602 for (var i = 0; i < frames.length; ++i) {
637 ctx.moveTo(0, y); 603 var frame = frames[i];
638 for (var i = 0; i < frames.length; ++i) { 604 var x = Math.round((frame.startTime - timeOffset) * scale) + offset;
639 var frame = frames[i]; 605 ctx.lineTo(x, y);
640 var x = Math.round((frame.startTime - timeOffset) * scale) + offset; 606 ctx.lineTo(x, y + tickDepth);
641 ctx.lineTo(x, y); 607 y = frame.idle ? bottomY :
642 ctx.lineTo(x, y + tickDepth); 608 Math.round(baseY - visualHeight * Math.min(baseFrameDurat ionMs / frame.duration, 1)) - offset;
643 y = frame.idle ? bottomY : Math.round(baseY - visualHeight * Math.mi n(baseFrameDurationMs / frame.duration, 1)) - offset; 609 ctx.lineTo(x, y + tickDepth);
644 ctx.lineTo(x, y + tickDepth); 610 ctx.lineTo(x, y);
645 ctx.lineTo(x, y); 611 }
646 } 612 if (frames.length) {
647 if (frames.length) { 613 var lastFrame = frames.peekLast();
648 var lastFrame = frames.peekLast(); 614 var x = Math.round((lastFrame.startTime + lastFrame.duration - timeOffset) * scale) + offset;
649 var x = Math.round((lastFrame.startTime + lastFrame.duration - timeO ffset) * scale) + offset; 615 ctx.lineTo(x, y);
650 ctx.lineTo(x, y); 616 }
651 } 617 ctx.lineTo(x, bottomY);
652 ctx.lineTo(x, bottomY); 618 ctx.fillStyle = 'hsl(110, 50%, 88%)';
653 ctx.fillStyle = "hsl(110, 50%, 88%)"; 619 ctx.strokeStyle = 'hsl(110, 50%, 60%)';
654 ctx.strokeStyle = "hsl(110, 50%, 60%)"; 620 ctx.lineWidth = lineWidth;
655 ctx.lineWidth = lineWidth; 621 ctx.fill();
656 ctx.fill(); 622 ctx.stroke();
657 ctx.stroke(); 623 }
658 }, 624 };
659 625
660 __proto__: WebInspector.TimelineEventOverview.prototype 626 /**
661 }; 627 * @unrestricted
662 628 */
663 /** 629 WebInspector.TimelineEventOverviewMemory = class extends WebInspector.TimelineEv entOverview {
664 * @constructor 630 /**
665 * @extends {WebInspector.TimelineEventOverview} 631 * @param {!WebInspector.TimelineModel} model
666 * @param {!WebInspector.TimelineModel} model 632 */
667 */ 633 constructor(model) {
668 WebInspector.TimelineEventOverview.Memory = function(model) 634 super('memory', WebInspector.UIString('HEAP'), model);
669 { 635 this._heapSizeLabel = this.element.createChild('div', 'memory-graph-label');
670 WebInspector.TimelineEventOverview.call(this, "memory", WebInspector.UIStrin g("HEAP"), model); 636 }
671 this._heapSizeLabel = this.element.createChild("div", "memory-graph-label"); 637
672 }; 638 resetHeapSizeLabels() {
673 639 this._heapSizeLabel.textContent = '';
674 WebInspector.TimelineEventOverview.Memory.prototype = { 640 }
675 resetHeapSizeLabels: function() 641
676 { 642 /**
677 this._heapSizeLabel.textContent = ""; 643 * @override
678 }, 644 */
679 645 update() {
680 /** 646 super.update();
681 * @override 647 var ratio = window.devicePixelRatio;
682 */ 648
683 update: function() 649 var events = this._model.mainThreadEvents();
684 { 650 if (!events.length) {
685 WebInspector.TimelineEventOverview.prototype.update.call(this); 651 this.resetHeapSizeLabels();
686 var ratio = window.devicePixelRatio; 652 return;
687 653 }
688 var events = this._model.mainThreadEvents(); 654
689 if (!events.length) { 655 var lowerOffset = 3 * ratio;
690 this.resetHeapSizeLabels(); 656 var maxUsedHeapSize = 0;
691 return; 657 var minUsedHeapSize = 100000000000;
692 } 658 var minTime = this._model.minimumRecordTime();
693 659 var maxTime = this._model.maximumRecordTime();
694 var lowerOffset = 3 * ratio; 660 /**
695 var maxUsedHeapSize = 0; 661 * @param {!WebInspector.TracingModel.Event} event
696 var minUsedHeapSize = 100000000000; 662 * @return {boolean}
697 var minTime = this._model.minimumRecordTime(); 663 */
698 var maxTime = this._model.maximumRecordTime(); 664 function isUpdateCountersEvent(event) {
699 /** 665 return event.name === WebInspector.TimelineModel.RecordType.UpdateCounters ;
700 * @param {!WebInspector.TracingModel.Event} event 666 }
701 * @return {boolean} 667 events = events.filter(isUpdateCountersEvent);
702 */ 668 /**
703 function isUpdateCountersEvent(event) 669 * @param {!WebInspector.TracingModel.Event} event
704 { 670 */
705 return event.name === WebInspector.TimelineModel.RecordType.UpdateCo unters; 671 function calculateMinMaxSizes(event) {
706 } 672 var counters = event.args.data;
707 events = events.filter(isUpdateCountersEvent); 673 if (!counters || !counters.jsHeapSizeUsed)
708 /** 674 return;
709 * @param {!WebInspector.TracingModel.Event} event 675 maxUsedHeapSize = Math.max(maxUsedHeapSize, counters.jsHeapSizeUsed);
710 */ 676 minUsedHeapSize = Math.min(minUsedHeapSize, counters.jsHeapSizeUsed);
711 function calculateMinMaxSizes(event) 677 }
712 { 678 events.forEach(calculateMinMaxSizes);
713 var counters = event.args.data; 679 minUsedHeapSize = Math.min(minUsedHeapSize, maxUsedHeapSize);
714 if (!counters || !counters.jsHeapSizeUsed) 680
715 return; 681 var lineWidth = 1;
716 maxUsedHeapSize = Math.max(maxUsedHeapSize, counters.jsHeapSizeUsed) ; 682 var width = this._canvas.width;
717 minUsedHeapSize = Math.min(minUsedHeapSize, counters.jsHeapSizeUsed) ; 683 var height = this._canvas.height - lowerOffset;
718 } 684 var xFactor = width / (maxTime - minTime);
719 events.forEach(calculateMinMaxSizes); 685 var yFactor = (height - lineWidth) / Math.max(maxUsedHeapSize - minUsedHeapS ize, 1);
720 minUsedHeapSize = Math.min(minUsedHeapSize, maxUsedHeapSize); 686
721 687 var histogram = new Array(width);
722 var lineWidth = 1; 688
723 var width = this._canvas.width; 689 /**
724 var height = this._canvas.height - lowerOffset; 690 * @param {!WebInspector.TracingModel.Event} event
725 var xFactor = width / (maxTime - minTime); 691 */
726 var yFactor = (height - lineWidth) / Math.max(maxUsedHeapSize - minUsedH eapSize, 1); 692 function buildHistogram(event) {
727 693 var counters = event.args.data;
728 var histogram = new Array(width); 694 if (!counters || !counters.jsHeapSizeUsed)
729 695 return;
730 /** 696 var x = Math.round((event.startTime - minTime) * xFactor);
731 * @param {!WebInspector.TracingModel.Event} event 697 var y = Math.round((counters.jsHeapSizeUsed - minUsedHeapSize) * yFactor);
732 */ 698 histogram[x] = Math.max(histogram[x] || 0, y);
733 function buildHistogram(event) 699 }
734 { 700 events.forEach(buildHistogram);
735 var counters = event.args.data; 701
736 if (!counters || !counters.jsHeapSizeUsed) 702 var ctx = this._context;
737 return; 703 var heightBeyondView = height + lowerOffset + lineWidth;
738 var x = Math.round((event.startTime - minTime) * xFactor); 704
739 var y = Math.round((counters.jsHeapSizeUsed - minUsedHeapSize) * yFa ctor); 705 ctx.translate(0.5, 0.5);
740 histogram[x] = Math.max(histogram[x] || 0, y); 706 ctx.beginPath();
741 } 707 ctx.moveTo(-lineWidth, heightBeyondView);
742 events.forEach(buildHistogram); 708 var y = 0;
743 709 var isFirstPoint = true;
744 var ctx = this._context; 710 var lastX = 0;
745 var heightBeyondView = height + lowerOffset + lineWidth; 711 for (var x = 0; x < histogram.length; x++) {
746 712 if (typeof histogram[x] === 'undefined')
747 ctx.translate(0.5, 0.5); 713 continue;
748 ctx.beginPath(); 714 if (isFirstPoint) {
749 ctx.moveTo(-lineWidth, heightBeyondView); 715 isFirstPoint = false;
750 var y = 0; 716 y = histogram[x];
751 var isFirstPoint = true; 717 ctx.lineTo(-lineWidth, height - y);
752 var lastX = 0; 718 }
753 for (var x = 0; x < histogram.length; x++) { 719 var nextY = histogram[x];
754 if (typeof histogram[x] === "undefined") 720 if (Math.abs(nextY - y) > 2 && Math.abs(x - lastX) > 1)
755 continue; 721 ctx.lineTo(x, height - y);
756 if (isFirstPoint) { 722 y = nextY;
757 isFirstPoint = false; 723 ctx.lineTo(x, height - y);
758 y = histogram[x]; 724 lastX = x;
759 ctx.lineTo(-lineWidth, height - y); 725 }
760 } 726 ctx.lineTo(width + lineWidth, height - y);
761 var nextY = histogram[x]; 727 ctx.lineTo(width + lineWidth, heightBeyondView);
762 if (Math.abs(nextY - y) > 2 && Math.abs(x - lastX) > 1) 728 ctx.closePath();
763 ctx.lineTo(x, height - y); 729
764 y = nextY; 730 ctx.fillStyle = 'hsla(220, 90%, 70%, 0.2)';
765 ctx.lineTo(x, height - y); 731 ctx.fill();
766 lastX = x; 732 ctx.lineWidth = lineWidth;
767 } 733 ctx.strokeStyle = 'hsl(220, 90%, 70%)';
768 ctx.lineTo(width + lineWidth, height - y); 734 ctx.stroke();
769 ctx.lineTo(width + lineWidth, heightBeyondView); 735
770 ctx.closePath(); 736 this._heapSizeLabel.textContent = WebInspector.UIString(
771 737 '%s \u2013 %s', Number.bytesToString(minUsedHeapSize), Number.bytesToStr ing(maxUsedHeapSize));
772 ctx.fillStyle = "hsla(220, 90%, 70%, 0.2)"; 738 }
773 ctx.fill(); 739 };
774 ctx.lineWidth = lineWidth; 740
775 ctx.strokeStyle = "hsl(220, 90%, 70%)"; 741 /**
776 ctx.stroke(); 742 * @unrestricted
777 743 */
778 this._heapSizeLabel.textContent = WebInspector.UIString("%s \u2013 %s", Number.bytesToString(minUsedHeapSize), Number.bytesToString(maxUsedHeapSize)); 744 WebInspector.Quantizer = class {
779 }, 745 /**
780 746 * @param {number} startTime
781 __proto__: WebInspector.TimelineEventOverview.prototype 747 * @param {number} quantDuration
782 }; 748 * @param {function(!Array<number>)} callback
783 749 */
784 /** 750 constructor(startTime, quantDuration, callback) {
785 * @constructor
786 * @param {number} startTime
787 * @param {number} quantDuration
788 * @param {function(!Array<number>)} callback
789 */
790 WebInspector.Quantizer = function(startTime, quantDuration, callback)
791 {
792 this._lastTime = startTime; 751 this._lastTime = startTime;
793 this._quantDuration = quantDuration; 752 this._quantDuration = quantDuration;
794 this._callback = callback; 753 this._callback = callback;
795 this._counters = []; 754 this._counters = [];
796 this._remainder = quantDuration; 755 this._remainder = quantDuration;
797 }; 756 }
798 757
799 WebInspector.Quantizer.prototype = { 758 /**
800 /** 759 * @param {number} time
801 * @param {number} time 760 * @param {number} group
802 * @param {number} group 761 */
803 */ 762 appendInterval(time, group) {
804 appendInterval: function(time, group) 763 var interval = time - this._lastTime;
805 { 764 if (interval <= this._remainder) {
806 var interval = time - this._lastTime; 765 this._counters[group] = (this._counters[group] || 0) + interval;
807 if (interval <= this._remainder) { 766 this._remainder -= interval;
808 this._counters[group] = (this._counters[group] || 0) + interval; 767 this._lastTime = time;
809 this._remainder -= interval; 768 return;
810 this._lastTime = time; 769 }
811 return; 770 this._counters[group] = (this._counters[group] || 0) + this._remainder;
812 } 771 this._callback(this._counters);
813 this._counters[group] = (this._counters[group] || 0) + this._remainder; 772 interval -= this._remainder;
814 this._callback(this._counters); 773 while (interval >= this._quantDuration) {
815 interval -= this._remainder; 774 var counters = [];
816 while (interval >= this._quantDuration) { 775 counters[group] = this._quantDuration;
817 var counters = []; 776 this._callback(counters);
818 counters[group] = this._quantDuration; 777 interval -= this._quantDuration;
819 this._callback(counters); 778 }
820 interval -= this._quantDuration; 779 this._counters = [];
821 } 780 this._counters[group] = interval;
822 this._counters = []; 781 this._lastTime = time;
823 this._counters[group] = interval; 782 this._remainder = this._quantDuration - interval;
824 this._lastTime = time; 783 }
825 this._remainder = this._quantDuration - interval; 784 };
826 }
827 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698