Index: third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js |
deleted file mode 100644 |
index 093d87e3aefc03b9be00ae9eb488c772b7a6122b..0000000000000000000000000000000000000000 |
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js |
+++ /dev/null |
@@ -1,878 +0,0 @@ |
-/* |
- * Copyright (C) 2014 Google Inc. All rights reserved. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions are |
- * met: |
- * |
- * * Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * * Redistributions in binary form must reproduce the above |
- * copyright notice, this list of conditions and the following disclaimer |
- * in the documentation and/or other materials provided with the |
- * distribution. |
- * * Neither the name of Google Inc. nor the names of its |
- * contributors may be used to endorse or promote products derived from |
- * this software without specific prior written permission. |
- * |
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-/** |
- * @implements {PerfUI.FlameChartDataProvider} |
- * @unrestricted |
- */ |
-Timeline.TimelineFlameChartDataProvider = class { |
- /** |
- * @param {!Array<!TimelineModel.TimelineModelFilter>} filters |
- */ |
- constructor(filters) { |
- this.reset(); |
- this._font = '11px ' + Host.fontFamily(); |
- this._filters = filters; |
- /** @type {?PerfUI.FlameChart.TimelineData} */ |
- this._timelineData = null; |
- this._currentLevel = 0; |
- /** @type {?Timeline.PerformanceModel} */ |
- this._performanceModel = null; |
- /** @type {?TimelineModel.TimelineModel} */ |
- this._model = null; |
- |
- this._consoleColorGenerator = |
- new PerfUI.FlameChart.ColorGenerator({min: 30, max: 55}, {min: 70, max: 100, count: 6}, 50, 0.7); |
- this._extensionColorGenerator = |
- new PerfUI.FlameChart.ColorGenerator({min: 210, max: 300}, {min: 70, max: 100, count: 6}, 70, 0.7); |
- |
- var defaultGroupStyle = { |
- padding: 4, |
- height: 17, |
- collapsible: true, |
- color: UI.themeSupport.patchColor('#222', UI.ThemeSupport.ColorUsage.Foreground), |
- backgroundColor: UI.themeSupport.patchColor('white', UI.ThemeSupport.ColorUsage.Background), |
- font: this._font, |
- nestingLevel: 0, |
- shareHeaderLine: true |
- }; |
- |
- this._headerLevel1 = /** @type {!PerfUI.FlameChart.GroupStyle} */ |
- (Object.assign({}, defaultGroupStyle, {shareHeaderLine: false})); |
- this._headerLevel2 = /** @type {!PerfUI.FlameChart.GroupStyle} */ |
- (Object.assign({}, defaultGroupStyle, {padding: 2, nestingLevel: 1, collapsible: false})); |
- this._staticHeader = /** @type {!PerfUI.FlameChart.GroupStyle} */ |
- (Object.assign({}, defaultGroupStyle, {collapsible: false})); |
- this._interactionsHeaderLevel1 = /** @type {!PerfUI.FlameChart.GroupStyle} */ |
- (Object.assign({useFirstLineForOverview: true}, defaultGroupStyle)); |
- this._interactionsHeaderLevel2 = /** @type {!PerfUI.FlameChart.GroupStyle} */ |
- (Object.assign({}, defaultGroupStyle, {padding: 2, nestingLevel: 1})); |
- |
- /** @type {!Map<string, number>} */ |
- this._flowEventIndexById = new Map(); |
- } |
- |
- /** |
- * @param {?Timeline.PerformanceModel} performanceModel |
- */ |
- setModel(performanceModel) { |
- this.reset(); |
- this._performanceModel = performanceModel; |
- this._model = performanceModel && performanceModel.timelineModel(); |
- } |
- |
- /** |
- * @override |
- * @param {number} entryIndex |
- * @return {?string} |
- */ |
- entryTitle(entryIndex) { |
- var entryType = this._entryType(entryIndex); |
- if (entryType === Timeline.TimelineFlameChartEntryType.Event) { |
- var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); |
- if (event.phase === SDK.TracingModel.Phase.AsyncStepInto || event.phase === SDK.TracingModel.Phase.AsyncStepPast) |
- return event.name + ':' + event.args['step']; |
- if (event._blackboxRoot) |
- return Common.UIString('Blackboxed'); |
- var name = Timeline.TimelineUIUtils.eventStyle(event).title; |
- // TODO(yurys): support event dividers |
- var detailsText = Timeline.TimelineUIUtils.buildDetailsTextForTraceEvent(event, this._model.targetByEvent(event)); |
- if (event.name === TimelineModel.TimelineModel.RecordType.JSFrame && detailsText) |
- return detailsText; |
- return detailsText ? Common.UIString('%s (%s)', name, detailsText) : name; |
- } |
- if (entryType === Timeline.TimelineFlameChartEntryType.ExtensionEvent) { |
- var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); |
- return event.name; |
- } |
- var title = this._entryIndexToTitle[entryIndex]; |
- if (!title) { |
- title = Common.UIString('Unexpected entryIndex %d', entryIndex); |
- console.error(title); |
- } |
- return title; |
- } |
- |
- /** |
- * @override |
- * @param {number} index |
- * @return {string} |
- */ |
- textColor(index) { |
- var event = this._entryData[index]; |
- return event && event._blackboxRoot ? '#888' : Timeline.FlameChartStyle.textColor; |
- } |
- |
- /** |
- * @override |
- * @param {number} index |
- * @return {?string} |
- */ |
- entryFont(index) { |
- return this._font; |
- } |
- |
- reset() { |
- this._currentLevel = 0; |
- this._timelineData = null; |
- /** @type {!Array<!SDK.TracingModel.Event|!TimelineModel.TimelineFrame|!TimelineModel.TimelineIRModel.Phases>} */ |
- this._entryData = []; |
- /** @type {!Array<!Timeline.TimelineFlameChartEntryType>} */ |
- this._entryTypeByLevel = []; |
- /** @type {!Array<string>} */ |
- this._entryIndexToTitle = []; |
- /** @type {!Array<!Timeline.TimelineFlameChartMarker>} */ |
- this._markers = []; |
- /** @type {!Map<!Timeline.TimelineCategory, string>} */ |
- this._asyncColorByCategory = new Map(); |
- /** @type {!Map<!TimelineModel.TimelineIRModel.Phases, string>} */ |
- this._asyncColorByInteractionPhase = new Map(); |
- /** @type {!Array<!{title: string, model: !SDK.TracingModel}>} */ |
- this._extensionInfo = []; |
- } |
- |
- /** |
- * @override |
- * @return {number} |
- */ |
- maxStackDepth() { |
- return this._currentLevel; |
- } |
- |
- /** |
- * @override |
- * @return {!PerfUI.FlameChart.TimelineData} |
- */ |
- timelineData() { |
- if (this._timelineData) |
- return this._timelineData; |
- |
- this._timelineData = new PerfUI.FlameChart.TimelineData([], [], [], []); |
- if (!this._model) |
- return this._timelineData; |
- |
- this._flowEventIndexById.clear(); |
- |
- this._minimumBoundary = this._model.minimumRecordTime(); |
- this._timeSpan = this._model.isEmpty() ? 1000 : this._model.maximumRecordTime() - this._minimumBoundary; |
- this._currentLevel = 0; |
- |
- this._appendHeader(Common.UIString('Frames'), this._staticHeader); |
- this._appendFrameBars(this._performanceModel.frames()); |
- |
- this._appendHeader(Common.UIString('Interactions'), this._interactionsHeaderLevel1); |
- this._appendInteractionRecords(); |
- |
- var eventEntryType = Timeline.TimelineFlameChartEntryType.Event; |
- |
- var asyncEventGroups = TimelineModel.TimelineModel.AsyncEventGroup; |
- var inputLatencies = this._model.mainThreadAsyncEvents().get(asyncEventGroups.input); |
- if (inputLatencies && inputLatencies.length) { |
- var title = Timeline.TimelineUIUtils.titleForAsyncEventGroup(asyncEventGroups.input); |
- this._appendAsyncEventsGroup(title, inputLatencies, this._interactionsHeaderLevel2, eventEntryType); |
- } |
- var animations = this._model.mainThreadAsyncEvents().get(asyncEventGroups.animation); |
- if (animations && animations.length) { |
- var title = Timeline.TimelineUIUtils.titleForAsyncEventGroup(asyncEventGroups.animation); |
- this._appendAsyncEventsGroup(title, animations, this._interactionsHeaderLevel2, eventEntryType); |
- } |
- var threads = this._model.virtualThreads(); |
- if (!Runtime.experiments.isEnabled('timelinePerFrameTrack')) { |
- this._appendThreadTimelineData( |
- Common.UIString('Main'), this._model.mainThreadEvents(), this._model.mainThreadAsyncEvents(), true); |
- } else { |
- this._appendThreadTimelineData( |
- Common.UIString('Page'), this._model.eventsForFrame(TimelineModel.TimelineModel.PageFrame.mainFrameId), |
- this._model.mainThreadAsyncEvents(), true); |
- for (var frame of this._model.rootFrames()) { |
- // Ignore top frame itself, since it should be part of page events. |
- frame.children.forEach(this._appendFrameEvents.bind(this, 0)); |
- } |
- } |
- var compositorThreads = threads.filter(thread => thread.name.startsWith('CompositorTileWorker')); |
- var otherThreads = threads.filter(thread => !thread.name.startsWith('CompositorTileWorker')); |
- if (compositorThreads.length) { |
- this._appendHeader(Common.UIString('Raster'), this._headerLevel1); |
- for (var i = 0; i < compositorThreads.length; ++i) { |
- this._appendSyncEvents( |
- compositorThreads[i].events, Common.UIString('Rasterizer Thread %d', i), this._headerLevel2, |
- eventEntryType); |
- } |
- } |
- this._appendGPUEvents(); |
- |
- otherThreads.forEach( |
- thread => this._appendThreadTimelineData( |
- thread.name || Common.UIString('Thread %d', thread.id), thread.events, thread.asyncEventsByGroup)); |
- |
- for (let extensionIndex = 0; extensionIndex < this._extensionInfo.length; extensionIndex++) |
- this._innerAppendExtensionEvents(extensionIndex); |
- |
- /** |
- * @param {!Timeline.TimelineFlameChartMarker} a |
- * @param {!Timeline.TimelineFlameChartMarker} b |
- */ |
- function compareStartTime(a, b) { |
- return a.startTime() - b.startTime(); |
- } |
- |
- this._markers.sort(compareStartTime); |
- this._timelineData.markers = this._markers; |
- this._flowEventIndexById.clear(); |
- |
- return this._timelineData; |
- } |
- |
- /** |
- * @override |
- * @return {number} |
- */ |
- minimumBoundary() { |
- return this._minimumBoundary; |
- } |
- |
- /** |
- * @override |
- * @return {number} |
- */ |
- totalTime() { |
- return this._timeSpan; |
- } |
- |
- /** |
- * @param {number} level |
- * @param {!TimelineModel.TimelineModel.PageFrame} frame |
- */ |
- _appendFrameEvents(level, frame) { |
- var events = this._model.eventsForFrame(frame.id); |
- var clonedHeader = Object.assign({}, this._headerLevel1); |
- clonedHeader.nestingLevel = level; |
- this._appendSyncEvents( |
- events, Timeline.TimelineUIUtils.displayNameForFrame(frame), |
- /** @type {!PerfUI.FlameChart.GroupStyle} */ (clonedHeader), Timeline.TimelineFlameChartEntryType.Event); |
- frame.children.forEach(this._appendFrameEvents.bind(this, level + 1)); |
- } |
- |
- /** |
- * @param {string} threadTitle |
- * @param {!Array<!SDK.TracingModel.Event>} syncEvents |
- * @param {!Map<!TimelineModel.TimelineModel.AsyncEventGroup, !Array<!SDK.TracingModel.AsyncEvent>>} asyncEvents |
- * @param {boolean=} forceExpanded |
- */ |
- _appendThreadTimelineData(threadTitle, syncEvents, asyncEvents, forceExpanded) { |
- var entryType = Timeline.TimelineFlameChartEntryType.Event; |
- this._appendAsyncEvents(asyncEvents); |
- this._appendSyncEvents(syncEvents, threadTitle, this._headerLevel1, entryType, forceExpanded); |
- } |
- |
- /** |
- * @param {!Array<!SDK.TracingModel.Event>} events |
- * @param {string} title |
- * @param {!PerfUI.FlameChart.GroupStyle} style |
- * @param {!Timeline.TimelineFlameChartEntryType} entryType |
- * @param {boolean=} forceExpanded |
- */ |
- _appendSyncEvents(events, title, style, entryType, forceExpanded) { |
- var isExtension = entryType === Timeline.TimelineFlameChartEntryType.ExtensionEvent; |
- var openEvents = []; |
- var flowEventsEnabled = Runtime.experiments.isEnabled('timelineFlowEvents'); |
- var blackboxingEnabled = !isExtension && Runtime.experiments.isEnabled('blackboxJSFramesOnTimeline'); |
- var maxStackDepth = 0; |
- for (var i = 0; i < events.length; ++i) { |
- var e = events[i]; |
- if (!isExtension && TimelineModel.TimelineModel.isMarkerEvent(e)) { |
- this._markers.push(new Timeline.TimelineFlameChartMarker( |
- e.startTime, e.startTime - this._model.minimumRecordTime(), |
- Timeline.TimelineUIUtils.markerStyleForEvent(e))); |
- } |
- if (!SDK.TracingModel.isFlowPhase(e.phase)) { |
- if (!e.endTime && e.phase !== SDK.TracingModel.Phase.Instant) |
- continue; |
- if (SDK.TracingModel.isAsyncPhase(e.phase)) |
- continue; |
- if (!isExtension && !this._isVisible(e)) |
- continue; |
- } |
- while (openEvents.length && openEvents.peekLast().endTime <= e.startTime) |
- openEvents.pop(); |
- e._blackboxRoot = false; |
- if (blackboxingEnabled && this._isBlackboxedEvent(e)) { |
- var parent = openEvents.peekLast(); |
- if (parent && parent._blackboxRoot) |
- continue; |
- e._blackboxRoot = true; |
- } |
- if (title) { |
- this._appendHeader(title, style, forceExpanded); |
- title = ''; |
- } |
- |
- var level = this._currentLevel + openEvents.length; |
- if (flowEventsEnabled) |
- this._appendFlowEvent(e, level); |
- if (e.phase !== SDK.TracingModel.Phase.FlowEnd) |
- this._appendEvent(e, level); |
- if (!isExtension && TimelineModel.TimelineModel.isMarkerEvent(e)) |
- this._timelineData.entryTotalTimes[this._entryData.length] = undefined; |
- |
- maxStackDepth = Math.max(maxStackDepth, openEvents.length + 1); |
- if (e.endTime) |
- openEvents.push(e); |
- } |
- this._entryTypeByLevel.length = this._currentLevel + maxStackDepth; |
- this._entryTypeByLevel.fill(entryType, this._currentLevel); |
- this._currentLevel += maxStackDepth; |
- } |
- |
- /** |
- * @param {!SDK.TracingModel.Event} event |
- * @return {boolean} |
- */ |
- _isBlackboxedEvent(event) { |
- if (event.name !== TimelineModel.TimelineModel.RecordType.JSFrame) |
- return false; |
- var url = event.args['data']['url']; |
- return url && this._isBlackboxedURL(url); |
- } |
- |
- /** |
- * @param {string} url |
- * @return {boolean} |
- */ |
- _isBlackboxedURL(url) { |
- return Bindings.blackboxManager.isBlackboxedURL(url); |
- } |
- |
- /** |
- * @param {!Map<!TimelineModel.TimelineModel.AsyncEventGroup, !Array<!SDK.TracingModel.AsyncEvent>>} asyncEvents |
- */ |
- _appendAsyncEvents(asyncEvents) { |
- var entryType = Timeline.TimelineFlameChartEntryType.Event; |
- var groups = TimelineModel.TimelineModel.AsyncEventGroup; |
- var groupArray = Object.keys(groups).map(key => groups[key]); |
- |
- groupArray.remove(groups.animation); |
- groupArray.remove(groups.input); |
- |
- for (var groupIndex = 0; groupIndex < groupArray.length; ++groupIndex) { |
- var group = groupArray[groupIndex]; |
- var events = asyncEvents.get(group); |
- if (!events) |
- continue; |
- var title = Timeline.TimelineUIUtils.titleForAsyncEventGroup(group); |
- this._appendAsyncEventsGroup(title, events, this._headerLevel1, entryType); |
- } |
- } |
- |
- /** |
- * @param {string} header |
- * @param {!Array<!SDK.TracingModel.AsyncEvent>} events |
- * @param {!PerfUI.FlameChart.GroupStyle} style |
- * @param {!Timeline.TimelineFlameChartEntryType} entryType |
- */ |
- _appendAsyncEventsGroup(header, events, style, entryType) { |
- var lastUsedTimeByLevel = []; |
- var groupHeaderAppended = false; |
- for (var i = 0; i < events.length; ++i) { |
- var asyncEvent = events[i]; |
- if (!this._isVisible(asyncEvent)) |
- continue; |
- if (!groupHeaderAppended) { |
- this._appendHeader(header, style); |
- groupHeaderAppended = true; |
- } |
- var startTime = asyncEvent.startTime; |
- var level; |
- for (level = 0; level < lastUsedTimeByLevel.length && lastUsedTimeByLevel[level] > startTime; ++level) { |
- } |
- this._appendAsyncEvent(asyncEvent, this._currentLevel + level); |
- lastUsedTimeByLevel[level] = asyncEvent.endTime; |
- } |
- this._entryTypeByLevel.length = this._currentLevel + lastUsedTimeByLevel.length; |
- this._entryTypeByLevel.fill(entryType, this._currentLevel); |
- this._currentLevel += lastUsedTimeByLevel.length; |
- } |
- |
- _appendGPUEvents() { |
- var eventType = Timeline.TimelineFlameChartEntryType.Event; |
- var gpuEvents = this._model.gpuEvents(); |
- if (this._appendSyncEvents(gpuEvents, Common.UIString('GPU'), this._headerLevel1, eventType, false)) |
- ++this._currentLevel; |
- } |
- |
- _appendInteractionRecords() { |
- this._performanceModel.interactionRecords().forEach(this._appendSegment, this); |
- this._entryTypeByLevel[this._currentLevel++] = Timeline.TimelineFlameChartEntryType.InteractionRecord; |
- } |
- |
- /** |
- * @param {!Array.<!TimelineModel.TimelineFrame>} frames |
- */ |
- _appendFrameBars(frames) { |
- var style = Timeline.TimelineUIUtils.markerStyleForFrame(); |
- this._entryTypeByLevel[this._currentLevel] = Timeline.TimelineFlameChartEntryType.Frame; |
- for (var i = 0; i < frames.length; ++i) { |
- this._markers.push(new Timeline.TimelineFlameChartMarker( |
- frames[i].startTime, frames[i].startTime - this._model.minimumRecordTime(), style)); |
- this._appendFrame(frames[i]); |
- } |
- ++this._currentLevel; |
- } |
- |
- /** |
- * @param {number} entryIndex |
- * @return {!Timeline.TimelineFlameChartEntryType} |
- */ |
- _entryType(entryIndex) { |
- return this._entryTypeByLevel[this._timelineData.entryLevels[entryIndex]]; |
- } |
- |
- /** |
- * @override |
- * @param {number} entryIndex |
- * @return {?Element} |
- */ |
- prepareHighlightedEntryInfo(entryIndex) { |
- var time = ''; |
- var title; |
- var warning; |
- var type = this._entryType(entryIndex); |
- if (type === Timeline.TimelineFlameChartEntryType.Event) { |
- var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); |
- var totalTime = event.duration; |
- var selfTime = event.selfTime; |
- var /** @const */ eps = 1e-6; |
- if (typeof totalTime === 'number') { |
- time = Math.abs(totalTime - selfTime) > eps && selfTime > eps ? |
- Common.UIString( |
- '%s (self %s)', Number.millisToString(totalTime, true), Number.millisToString(selfTime, true)) : |
- Number.millisToString(totalTime, true); |
- } |
- title = this.entryTitle(entryIndex); |
- warning = Timeline.TimelineUIUtils.eventWarning(event); |
- } else if (type === Timeline.TimelineFlameChartEntryType.Frame) { |
- var frame = /** @type {!TimelineModel.TimelineFrame} */ (this._entryData[entryIndex]); |
- time = Common.UIString( |
- '%s ~ %.0f\u2009fps', Number.preciseMillisToString(frame.duration, 1), (1000 / frame.duration)); |
- title = frame.idle ? Common.UIString('Idle Frame') : Common.UIString('Frame'); |
- if (frame.hasWarnings()) { |
- warning = createElement('span'); |
- warning.textContent = Common.UIString('Long frame'); |
- } |
- } else { |
- return null; |
- } |
- var element = createElement('div'); |
- var root = UI.createShadowRootWithCoreStyles(element, 'timeline/timelineFlamechartPopover.css'); |
- var contents = root.createChild('div', 'timeline-flamechart-popover'); |
- contents.createChild('span', 'timeline-info-time').textContent = time; |
- contents.createChild('span', 'timeline-info-title').textContent = title; |
- if (warning) { |
- warning.classList.add('timeline-info-warning'); |
- contents.appendChild(warning); |
- } |
- return element; |
- } |
- |
- /** |
- * @override |
- * @param {number} entryIndex |
- */ |
- highlightEntry(entryIndex) { |
- SDK.DOMModel.hideDOMNodeHighlight(); |
- if (this._entryType(entryIndex) !== Timeline.TimelineFlameChartEntryType.Event) |
- return; |
- var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); |
- var target = this._model.targetByEvent(event); |
- if (!target) |
- return; |
- var timelineData = TimelineModel.TimelineData.forEvent(event); |
- var backendNodeId = timelineData.backendNodeId; |
- if (!backendNodeId) |
- return; |
- new SDK.DeferredDOMNode(target, backendNodeId).highlight(); |
- } |
- |
- /** |
- * @override |
- * @param {number} entryIndex |
- * @return {string} |
- */ |
- entryColor(entryIndex) { |
- // This is not annotated due to closure compiler failure to properly infer cache container's template type. |
- function patchColorAndCache(cache, key, lookupColor) { |
- var color = cache.get(key); |
- if (color) |
- return color; |
- var parsedColor = Common.Color.parse(lookupColor(key)); |
- color = parsedColor.setAlpha(0.7).asString(Common.Color.Format.RGBA) || ''; |
- cache.set(key, color); |
- return color; |
- } |
- |
- var type = this._entryType(entryIndex); |
- if (type === Timeline.TimelineFlameChartEntryType.Event) { |
- var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); |
- if (!SDK.TracingModel.isAsyncPhase(event.phase)) |
- return Timeline.TimelineUIUtils.eventColor(event); |
- if (event.hasCategory(TimelineModel.TimelineModel.Category.Console) || |
- event.hasCategory(TimelineModel.TimelineModel.Category.UserTiming)) |
- return this._consoleColorGenerator.colorForID(event.name); |
- if (event.hasCategory(TimelineModel.TimelineModel.Category.LatencyInfo)) { |
- var phase = |
- TimelineModel.TimelineIRModel.phaseForEvent(event) || TimelineModel.TimelineIRModel.Phases.Uncategorized; |
- return patchColorAndCache( |
- this._asyncColorByInteractionPhase, phase, Timeline.TimelineUIUtils.interactionPhaseColor); |
- } |
- var category = Timeline.TimelineUIUtils.eventStyle(event).category; |
- return patchColorAndCache(this._asyncColorByCategory, category, () => category.color); |
- } |
- if (type === Timeline.TimelineFlameChartEntryType.Frame) |
- return 'white'; |
- if (type === Timeline.TimelineFlameChartEntryType.InteractionRecord) |
- return 'transparent'; |
- if (type === Timeline.TimelineFlameChartEntryType.ExtensionEvent) { |
- var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); |
- return this._extensionColorGenerator.colorForID(event.name); |
- } |
- return ''; |
- } |
- |
- /** |
- * @override |
- * @param {number} entryIndex |
- * @param {!CanvasRenderingContext2D} context |
- * @param {?string} text |
- * @param {number} barX |
- * @param {number} barY |
- * @param {number} barWidth |
- * @param {number} barHeight |
- * @param {number} unclippedBarX |
- * @param {number} timeToPixels |
- * @return {boolean} |
- */ |
- decorateEntry(entryIndex, context, text, barX, barY, barWidth, barHeight, unclippedBarX, timeToPixels) { |
- var data = this._entryData[entryIndex]; |
- var type = this._entryType(entryIndex); |
- if (type === Timeline.TimelineFlameChartEntryType.Frame) { |
- var /** @const */ vPadding = 1; |
- var /** @const */ hPadding = 1; |
- var frame = /** {!TimelineModel.TimelineFrame} */ (data); |
- barX += hPadding; |
- barWidth -= 2 * hPadding; |
- barY += vPadding; |
- barHeight -= 2 * vPadding + 1; |
- context.fillStyle = frame.idle ? 'white' : (frame.hasWarnings() ? '#fad1d1' : '#d7f0d1'); |
- context.fillRect(barX, barY, barWidth, barHeight); |
- var frameDurationText = Number.preciseMillisToString(frame.duration, 1); |
- var textWidth = context.measureText(frameDurationText).width; |
- if (barWidth >= textWidth) { |
- context.fillStyle = this.textColor(entryIndex); |
- context.fillText(frameDurationText, barX + (barWidth - textWidth) / 2, barY + barHeight - 3); |
- } |
- return true; |
- } |
- |
- if (type === Timeline.TimelineFlameChartEntryType.InteractionRecord) { |
- var color = Timeline.TimelineUIUtils.interactionPhaseColor( |
- /** @type {!TimelineModel.TimelineIRModel.Phases} */ (data)); |
- context.fillStyle = color; |
- context.fillRect(barX, barY, barWidth - 1, 2); |
- context.fillRect(barX, barY - 3, 2, 3); |
- context.fillRect(barX + barWidth - 3, barY - 3, 2, 3); |
- return false; |
- } |
- |
- if (type === Timeline.TimelineFlameChartEntryType.Event) { |
- var event = /** @type {!SDK.TracingModel.Event} */ (data); |
- if (event.hasCategory(TimelineModel.TimelineModel.Category.LatencyInfo)) { |
- var timeWaitingForMainThread = TimelineModel.TimelineData.forEvent(event).timeWaitingForMainThread; |
- if (timeWaitingForMainThread) { |
- context.fillStyle = 'hsla(0, 70%, 60%, 1)'; |
- var width = Math.floor(unclippedBarX - barX + timeWaitingForMainThread * timeToPixels); |
- context.fillRect(barX, barY + barHeight - 3, width, 2); |
- } |
- } |
- if (TimelineModel.TimelineData.forEvent(event).warning) |
- paintWarningDecoration(barX, barWidth - 1.5); |
- } |
- |
- /** |
- * @param {number} x |
- * @param {number} width |
- */ |
- function paintWarningDecoration(x, width) { |
- var /** @const */ triangleSize = 8; |
- context.save(); |
- context.beginPath(); |
- context.rect(x, barY, width, barHeight); |
- context.clip(); |
- context.beginPath(); |
- context.fillStyle = 'red'; |
- context.moveTo(x + width - triangleSize, barY); |
- context.lineTo(x + width, barY); |
- context.lineTo(x + width, barY + triangleSize); |
- context.fill(); |
- context.restore(); |
- } |
- |
- return false; |
- } |
- |
- /** |
- * @override |
- * @param {number} entryIndex |
- * @return {boolean} |
- */ |
- forceDecoration(entryIndex) { |
- var type = this._entryType(entryIndex); |
- if (type === Timeline.TimelineFlameChartEntryType.Frame) |
- return true; |
- |
- if (type === Timeline.TimelineFlameChartEntryType.Event) { |
- var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); |
- return !!TimelineModel.TimelineData.forEvent(event).warning; |
- } |
- return false; |
- } |
- |
- /** |
- * @param {!{title: string, model: !SDK.TracingModel}} entry |
- */ |
- appendExtensionEvents(entry) { |
- this._extensionInfo.push(entry); |
- if (this._timelineData) |
- this._innerAppendExtensionEvents(this._extensionInfo.length - 1); |
- } |
- |
- /** |
- * @param {number} index |
- */ |
- _innerAppendExtensionEvents(index) { |
- var entry = this._extensionInfo[index]; |
- var entryType = Timeline.TimelineFlameChartEntryType.ExtensionEvent; |
- var allThreads = [].concat(...entry.model.sortedProcesses().map(process => process.sortedThreads())); |
- if (!allThreads.length) |
- return; |
- |
- this._appendHeader(entry.title, this._headerLevel1); |
- for (let thread of allThreads) { |
- this._appendAsyncEventsGroup(thread.name(), thread.asyncEvents(), this._headerLevel2, entryType); |
- this._appendSyncEvents(thread.events(), thread.name(), this._headerLevel2, entryType, false); |
- } |
- } |
- |
- /** |
- * @param {string} title |
- * @param {!PerfUI.FlameChart.GroupStyle} style |
- * @param {boolean=} expanded |
- */ |
- _appendHeader(title, style, expanded) { |
- this._timelineData.groups.push({startLevel: this._currentLevel, name: title, expanded: expanded, style: style}); |
- } |
- |
- /** |
- * @param {!SDK.TracingModel.Event} event |
- * @param {number} level |
- */ |
- _appendEvent(event, level) { |
- var index = this._entryData.length; |
- this._entryData.push(event); |
- this._timelineData.entryLevels[index] = level; |
- this._timelineData.entryTotalTimes[index] = |
- event.duration || Timeline.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs; |
- this._timelineData.entryStartTimes[index] = event.startTime; |
- } |
- |
- /** |
- * @param {!SDK.TracingModel.AsyncEvent} asyncEvent |
- * @param {number} level |
- */ |
- _appendAsyncEvent(asyncEvent, level) { |
- if (SDK.TracingModel.isNestableAsyncPhase(asyncEvent.phase)) { |
- // FIXME: also add steps once we support event nesting in the FlameChart. |
- this._appendEvent(asyncEvent, level); |
- return; |
- } |
- var steps = asyncEvent.steps; |
- // If we have past steps, put the end event for each range rather than start one. |
- var eventOffset = steps.length > 1 && steps[1].phase === SDK.TracingModel.Phase.AsyncStepPast ? 1 : 0; |
- for (var i = 0; i < steps.length - 1; ++i) { |
- var index = this._entryData.length; |
- this._entryData.push(steps[i + eventOffset]); |
- var startTime = steps[i].startTime; |
- this._timelineData.entryLevels[index] = level; |
- this._timelineData.entryTotalTimes[index] = steps[i + 1].startTime - startTime; |
- this._timelineData.entryStartTimes[index] = startTime; |
- } |
- } |
- |
- /** |
- * @param {!SDK.TracingModel.Event} event |
- * @param {number} level |
- */ |
- _appendFlowEvent(event, level) { |
- var timelineData = this._timelineData; |
- /** |
- * @param {!SDK.TracingModel.Event} event |
- * @return {number} |
- */ |
- function pushStartFlow(event) { |
- var flowIndex = timelineData.flowStartTimes.length; |
- timelineData.flowStartTimes.push(event.startTime); |
- timelineData.flowStartLevels.push(level); |
- return flowIndex; |
- } |
- |
- /** |
- * @param {!SDK.TracingModel.Event} event |
- * @param {number} flowIndex |
- */ |
- function pushEndFlow(event, flowIndex) { |
- timelineData.flowEndTimes[flowIndex] = event.startTime; |
- timelineData.flowEndLevels[flowIndex] = level; |
- } |
- |
- switch (event.phase) { |
- case SDK.TracingModel.Phase.FlowBegin: |
- this._flowEventIndexById.set(event.id, pushStartFlow(event)); |
- break; |
- case SDK.TracingModel.Phase.FlowStep: |
- pushEndFlow(event, this._flowEventIndexById.get(event.id)); |
- this._flowEventIndexById.set(event.id, pushStartFlow(event)); |
- break; |
- case SDK.TracingModel.Phase.FlowEnd: |
- pushEndFlow(event, this._flowEventIndexById.get(event.id)); |
- this._flowEventIndexById.delete(event.id); |
- break; |
- } |
- } |
- |
- /** |
- * @param {!TimelineModel.TimelineFrame} frame |
- */ |
- _appendFrame(frame) { |
- var index = this._entryData.length; |
- this._entryData.push(frame); |
- this._entryIndexToTitle[index] = Number.millisToString(frame.duration, true); |
- this._timelineData.entryLevels[index] = this._currentLevel; |
- this._timelineData.entryTotalTimes[index] = frame.duration; |
- this._timelineData.entryStartTimes[index] = frame.startTime; |
- } |
- |
- /** |
- * @param {!Common.Segment} segment |
- */ |
- _appendSegment(segment) { |
- var index = this._entryData.length; |
- this._entryData.push(/** @type {!TimelineModel.TimelineIRModel.Phases} */ (segment.data)); |
- this._entryIndexToTitle[index] = /** @type {string} */ (segment.data); |
- this._timelineData.entryLevels[index] = this._currentLevel; |
- this._timelineData.entryTotalTimes[index] = segment.end - segment.begin; |
- this._timelineData.entryStartTimes[index] = segment.begin; |
- } |
- |
- /** |
- * @param {number} entryIndex |
- * @return {?Timeline.TimelineSelection} |
- */ |
- createSelection(entryIndex) { |
- var type = this._entryType(entryIndex); |
- var timelineSelection = null; |
- if (type === Timeline.TimelineFlameChartEntryType.Event) { |
- timelineSelection = Timeline.TimelineSelection.fromTraceEvent( |
- /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex])); |
- } else if (type === Timeline.TimelineFlameChartEntryType.Frame) { |
- timelineSelection = Timeline.TimelineSelection.fromFrame( |
- /** @type {!TimelineModel.TimelineFrame} */ (this._entryData[entryIndex])); |
- } |
- if (timelineSelection) |
- this._lastSelection = new Timeline.TimelineFlameChartView.Selection(timelineSelection, entryIndex); |
- return timelineSelection; |
- } |
- |
- /** |
- * @override |
- * @param {number} value |
- * @param {number=} precision |
- * @return {string} |
- */ |
- formatValue(value, precision) { |
- return Number.preciseMillisToString(value, precision); |
- } |
- |
- /** |
- * @override |
- * @param {number} entryIndex |
- * @return {boolean} |
- */ |
- canJumpToEntry(entryIndex) { |
- return false; |
- } |
- |
- /** |
- * @param {?Timeline.TimelineSelection} selection |
- * @return {number} |
- */ |
- entryIndexForSelection(selection) { |
- if (!selection || selection.type() === Timeline.TimelineSelection.Type.Range) |
- return -1; |
- |
- if (this._lastSelection && this._lastSelection.timelineSelection.object() === selection.object()) |
- return this._lastSelection.entryIndex; |
- var index = this._entryData.indexOf( |
- /** @type {!SDK.TracingModel.Event|!TimelineModel.TimelineFrame|!TimelineModel.TimelineIRModel.Phases} */ |
- (selection.object())); |
- if (index !== -1) |
- this._lastSelection = new Timeline.TimelineFlameChartView.Selection(selection, index); |
- return index; |
- } |
- |
- /** |
- * @param {!SDK.TracingModel.Event} event |
- * @return {?Timeline.TimelineSelection} selection |
- */ |
- selectionForEvent(event) { |
- var entryIndex = this._entryData.indexOf(event); |
- return this.createSelection(entryIndex); |
- } |
- |
- /** |
- * @param {!SDK.TracingModel.Event} event |
- * @return {boolean} |
- */ |
- _isVisible(event) { |
- return this._filters.every(function(filter) { |
- return filter.accept(event); |
- }); |
- } |
-}; |
- |
-Timeline.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs = 0.001; |