| Index: Source/devtools/front_end/timeline/TimelineEventOverview.js
|
| diff --git a/Source/devtools/front_end/timeline/TimelineEventOverview.js b/Source/devtools/front_end/timeline/TimelineEventOverview.js
|
| index 078e9a3e008acfb0c8cef8ca5f29e69d5db9bae2..ebd453fad47cbaf14bde51643dd6d1a2cdbce8f9 100644
|
| --- a/Source/devtools/front_end/timeline/TimelineEventOverview.js
|
| +++ b/Source/devtools/front_end/timeline/TimelineEventOverview.js
|
| @@ -50,6 +50,8 @@ WebInspector.TimelineEventOverview = function(model)
|
|
|
| /** @const */
|
| WebInspector.TimelineEventOverview._stripHeight = 10;
|
| +/** @const */
|
| +WebInspector.TimelineEventOverview._maxNetworkStripHeight = 32;
|
|
|
| WebInspector.TimelineEventOverview.prototype = {
|
| /**
|
| @@ -67,14 +69,21 @@ WebInspector.TimelineEventOverview.prototype = {
|
| */
|
| update: function()
|
| {
|
| - var /** @const */ topPadding = 2;
|
| + var /** @const */ padding = 2;
|
| this.resetCanvas();
|
| var threads = this._model.virtualThreads();
|
| - var estimatedHeight = 3 * WebInspector.TimelineEventOverview._stripHeight;
|
| + var mainThreadEvents = this._model.mainThreadEvents();
|
| + var estimatedHeight = padding + 3 * WebInspector.TimelineEventOverview._stripHeight;
|
| + estimatedHeight += padding + WebInspector.TimelineEventOverview._maxNetworkStripHeight;
|
| this._canvas.height = estimatedHeight * window.devicePixelRatio;
|
| this._canvas.style.height = estimatedHeight + "px";
|
| - var position = topPadding;
|
| - position += this._drawEvents(this._model.mainThreadEvents(), position);
|
| + var position = padding;
|
| + if (Runtime.experiments.isEnabled("networkRequestsOnTimeline")) {
|
| + position += this._drawNetwork(mainThreadEvents, position);
|
| + position += padding;
|
| + }
|
| + this._drawEvents(mainThreadEvents, position);
|
| + position += WebInspector.TimelineEventOverview._stripHeight;
|
| for (var thread of threads.filter(function(thread) { return !thread.isWorker(); }))
|
| this._drawEvents(thread.events, position);
|
| position += WebInspector.TimelineEventOverview._stripHeight;
|
| @@ -90,9 +99,162 @@ WebInspector.TimelineEventOverview.prototype = {
|
| * @param {number} position
|
| * @return {number}
|
| */
|
| + _drawNetwork: function(events, position)
|
| + {
|
| + /**
|
| + * @param {!Array.<!WebInspector.TracingModel.Event>} events
|
| + * @return {number}
|
| + */
|
| + function calculateNetworkBandsCount(events)
|
| + {
|
| + var openBands = new Set();
|
| + var maxBands = 0;
|
| + for (var i = 0; i < events.length; ++i) {
|
| + var e = events[i];
|
| + switch (e.name) {
|
| + case WebInspector.TimelineModel.RecordType.ResourceSendRequest:
|
| + case WebInspector.TimelineModel.RecordType.ResourceReceiveResponse:
|
| + case WebInspector.TimelineModel.RecordType.ResourceReceivedData:
|
| + var reqId = e.args["data"]["requestId"];
|
| + openBands.add(reqId);
|
| + maxBands = Math.max(maxBands, openBands.size);
|
| + break;
|
| + case WebInspector.TimelineModel.RecordType.ResourceFinish:
|
| + var reqId = e.args["data"]["requestId"];
|
| + if (!openBands.has(reqId))
|
| + ++maxBands;
|
| + else
|
| + openBands.delete(reqId);
|
| + break;
|
| + }
|
| + }
|
| + return maxBands;
|
| + }
|
| +
|
| + var /** @const */ maxBandHeight = 4;
|
| + var bandsCount = calculateNetworkBandsCount(events);
|
| + var bandInterval = Math.min(maxBandHeight, WebInspector.TimelineEventOverview._maxNetworkStripHeight / (bandsCount || 1));
|
| + var bandHeight = Math.ceil(bandInterval);
|
| + var timeOffset = this._model.minimumRecordTime();
|
| + var timeSpan = this._model.maximumRecordTime() - timeOffset;
|
| + var scale = this._canvas.width / timeSpan;
|
| + var loadingCategory = WebInspector.TimelineUIUtils.categories()["loading"];
|
| + var waitingColor = loadingCategory.fillColorStop0;
|
| + var processingColor = loadingCategory.fillColorStop1;
|
| +
|
| + var bandsInUse = new Array(bandsCount);
|
| + var freeBandsCount = bandsCount;
|
| + var requestsInFlight = new Map();
|
| + var lastBand = 0;
|
| +
|
| + /**
|
| + * @constructor
|
| + * @param {number} band
|
| + * @param {number} lastTime
|
| + * @param {boolean} gotResponse
|
| + */
|
| + function RequestInfo(band, lastTime, gotResponse)
|
| + {
|
| + this.band = band;
|
| + this.lastTime = lastTime;
|
| + this.gotResponse = gotResponse;
|
| + }
|
| +
|
| + /**
|
| + * @return {number}
|
| + */
|
| + function seizeBand()
|
| + {
|
| + console.assert(freeBandsCount);
|
| + do {
|
| + lastBand = (lastBand + 1) % bandsInUse.length;
|
| + } while (bandsInUse[lastBand]);
|
| + bandsInUse[lastBand] = true;
|
| + --freeBandsCount;
|
| + return lastBand;
|
| + }
|
| +
|
| + /**
|
| + * @param {number} band
|
| + */
|
| + function releaseBand(band)
|
| + {
|
| + bandsInUse[band] = false;
|
| + ++freeBandsCount;
|
| + }
|
| +
|
| + /**
|
| + * @param {string} reqId
|
| + * @param {number=} time
|
| + * @return {!RequestInfo}
|
| + */
|
| + function getRequestInfo(reqId, time)
|
| + {
|
| + var reqInfo = requestsInFlight.get(reqId);
|
| + if (!reqInfo) {
|
| + reqInfo = new RequestInfo(seizeBand(), time || timeOffset, false);
|
| + requestsInFlight.set(reqId, reqInfo);
|
| + }
|
| + return reqInfo;
|
| + }
|
| +
|
| + /**
|
| + * @param {string} reqId
|
| + * @param {!RequestInfo} reqInfo
|
| + * @param {number} time
|
| + * @param {boolean=} finish
|
| + * @this {WebInspector.TimelineEventOverview}
|
| + */
|
| + function advanceRequest(reqId, reqInfo, time, finish)
|
| + {
|
| + var band = reqInfo.band;
|
| + var start = (reqInfo.lastTime - timeOffset) * scale;
|
| + var end = (time - timeOffset) * scale;
|
| + var color = reqInfo.gotResponse ? processingColor : waitingColor;
|
| + if (finish) {
|
| + releaseBand(band);
|
| + requestsInFlight.delete(reqId);
|
| + } else {
|
| + reqInfo.lastTime = time;
|
| + reqInfo.gotResponse = true;
|
| + }
|
| + this._renderBar(Math.floor(start), Math.ceil(end), Math.floor(position + band * bandInterval), bandHeight, color);
|
| + }
|
| +
|
| + for (var i = 0; i < events.length; ++i) {
|
| + var event = events[i];
|
| + switch (event.name) {
|
| + case WebInspector.TimelineModel.RecordType.ResourceSendRequest:
|
| + var reqId = event.args["data"]["requestId"];
|
| + getRequestInfo(reqId, event.startTime);
|
| + break;
|
| + case WebInspector.TimelineModel.RecordType.ResourceReceivedData:
|
| + case WebInspector.TimelineModel.RecordType.ResourceReceiveResponse:
|
| + case WebInspector.TimelineModel.RecordType.ResourceFinish:
|
| + var reqId = event.args["data"]["requestId"];
|
| + var reqInfo = getRequestInfo(reqId);
|
| + var finish = event.name === WebInspector.TimelineModel.RecordType.ResourceFinish;
|
| + advanceRequest.call(this, reqId, reqInfo, event.startTime, finish);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + for (var reqId of requestsInFlight.keys())
|
| + advanceRequest.call(this, reqId, requestsInFlight.get(reqId), timeOffset + timeSpan);
|
| +
|
| + return Math.ceil(bandInterval * bandsCount);
|
| + },
|
| +
|
| + /**
|
| + * @param {!Array.<!WebInspector.TracingModel.Event>} events
|
| + * @param {number} position
|
| + * @return {number}
|
| + */
|
| _drawEvents: function(events, position)
|
| {
|
| + var /** @const */ padding = 1;
|
| var stripHeight = WebInspector.TimelineEventOverview._stripHeight;
|
| + var visualHeight = stripHeight - padding;
|
| var timeOffset = this._model.minimumRecordTime();
|
| var timeSpan = this._model.maximumRecordTime() - timeOffset;
|
| var scale = this._canvas.width / timeSpan;
|
| @@ -102,6 +264,16 @@ WebInspector.TimelineEventOverview.prototype = {
|
| var drawn = false;
|
|
|
| /**
|
| + * @param {!WebInspector.TimelineCategory} category
|
| + * @return {string}
|
| + * @this {WebInspector.TimelineEventOverview}
|
| + */
|
| + function categoryColor(category)
|
| + {
|
| + return category.hidden ? this._disabledCategoryFillStyle : this._fillStyles[category.name];
|
| + }
|
| +
|
| + /**
|
| * @param {!WebInspector.TracingModel.Event} e
|
| * @this {WebInspector.TimelineEventOverview}
|
| */
|
| @@ -112,7 +284,7 @@ WebInspector.TimelineEventOverview.prototype = {
|
| var category = categoryStack.peekLast();
|
| var bar = ditherer.appendInterval(category, lastX, pos);
|
| if (bar) {
|
| - this._renderBar(bar.start, bar.end, position, stripHeight, category);
|
| + this._renderBar(bar.start, bar.end, position, visualHeight, categoryColor.call(this, category));
|
| drawn = true;
|
| }
|
| }
|
| @@ -130,7 +302,7 @@ WebInspector.TimelineEventOverview.prototype = {
|
| var pos = (e.endTime - timeOffset) * scale;
|
| var bar = ditherer.appendInterval(category, lastX, pos);
|
| if (bar) {
|
| - this._renderBar(bar.start, bar.end, position, stripHeight, category);
|
| + this._renderBar(bar.start, bar.end, position, visualHeight, categoryColor.call(this, category));
|
| drawn = true;
|
| }
|
| lastX = pos;
|
| @@ -150,17 +322,15 @@ WebInspector.TimelineEventOverview.prototype = {
|
| * @param {number} end
|
| * @param {number} position
|
| * @param {number} height
|
| - * @param {!WebInspector.TimelineCategory} category
|
| + * @param {string} color
|
| */
|
| - _renderBar: function(begin, end, position, height, category)
|
| + _renderBar: function(begin, end, position, height, color)
|
| {
|
| - var /** @const */ stripPadding = 1;
|
| - var innerStripHeight = (height - stripPadding) * window.devicePixelRatio;
|
| var x = begin;
|
| var y = position * window.devicePixelRatio;
|
| var width = end - begin;
|
| - this._context.fillStyle = category.hidden ? this._disabledCategoryFillStyle : this._fillStyles[category.name];
|
| - this._context.fillRect(x, y, width, innerStripHeight);
|
| + this._context.fillStyle = color;
|
| + this._context.fillRect(x, y, width, height * window.devicePixelRatio);
|
| },
|
|
|
| __proto__: WebInspector.TimelineOverviewBase.prototype
|
|
|