|
| 1 | +import TimelineUIUtils from './../devtools/timelineModel/timelineUIUtils' |
| 2 | +import { StatsArray } from './../devtools/types' |
| 3 | +import TimelineModel from './../devtools/timelineModel' |
| 4 | +import Event from './../devtools/tracingModel/event' |
| 5 | +import TracingModel from './../devtools/tracingModel' |
| 6 | + |
| 7 | +export default class CustomUtils extends TimelineUIUtils { |
| 8 | + /** |
| 9 | + * @param {!Array<!SDK.TracingModel.Event>} events |
| 10 | + * @param {number} startTime |
| 11 | + * @param {number} endTime |
| 12 | + * @return {!Object<string, number>} |
| 13 | + */ |
| 14 | + public detailStatsForTimeRange(events: Event[], startTime: number, endTime: number): StatsArray { |
| 15 | + const eventStyle = this.eventStyle.bind(this) |
| 16 | + const visibleEventsFilterFunc = this.visibleEventsFilter.bind(this) |
| 17 | + |
| 18 | + if (!events.length) { |
| 19 | + return { |
| 20 | + idle: { |
| 21 | + 'time': [endTime - startTime], |
| 22 | + 'value': [endTime - startTime] |
| 23 | + } |
| 24 | + } |
| 25 | + } |
| 26 | + |
| 27 | + // aggeregatedStats is a map by categories. For each category there's an array |
| 28 | + // containing sorted time points which records accumulated value of the category. |
| 29 | + const aggregatedStats: StatsArray = {} |
| 30 | + const categoryStack: string[] = [] |
| 31 | + let lastTime = 0 |
| 32 | + TimelineModel.forEachEvent( |
| 33 | + events, |
| 34 | + onStartEvent, |
| 35 | + onEndEvent, |
| 36 | + undefined, |
| 37 | + undefined, |
| 38 | + undefined, |
| 39 | + filterForStats() |
| 40 | + ) |
| 41 | + |
| 42 | + /** |
| 43 | + * @return {function(!SDK.TracingModel.Event):boolean} |
| 44 | + */ |
| 45 | + function filterForStats(): any { |
| 46 | + const visibleEventsFilter = visibleEventsFilterFunc() |
| 47 | + return (event: Event): any => visibleEventsFilter.accept(event) || TracingModel.isTopLevelEvent(event) |
| 48 | + } |
| 49 | + |
| 50 | + /** |
| 51 | + * @param {string} category |
| 52 | + * @param {number} time |
| 53 | + */ |
| 54 | + function updateCategory(category: string, time: number): void { |
| 55 | + let statsArrays = aggregatedStats[category] |
| 56 | + if (!statsArrays) { |
| 57 | + statsArrays = { time: [], value: [] } |
| 58 | + aggregatedStats[category] = statsArrays |
| 59 | + } |
| 60 | + if (statsArrays.time.length && statsArrays.time[statsArrays.time.length - 1] === time) { |
| 61 | + return |
| 62 | + } |
| 63 | + // const lastValue = statsArrays.value.length ? statsArrays.value[statsArrays.value.length - 1] : 0 |
| 64 | + statsArrays.value.push(time - lastTime) |
| 65 | + statsArrays.time.push(time) |
| 66 | + } |
| 67 | + |
| 68 | + /** |
| 69 | + * @param {?string} from |
| 70 | + * @param {?string} to |
| 71 | + * @param {number} time |
| 72 | + */ |
| 73 | + function categoryChange(from?: string, to?: string, time?: number): void { |
| 74 | + if (from) { |
| 75 | + updateCategory(from, time) |
| 76 | + } |
| 77 | + |
| 78 | + lastTime = time |
| 79 | + |
| 80 | + if (to) { |
| 81 | + updateCategory(to, time) |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + /** |
| 86 | + * @param {!SDK.TracingModel.Event} e |
| 87 | + */ |
| 88 | + function onStartEvent(e: Event): void { |
| 89 | + const category = eventStyle(e).category.name |
| 90 | + const parentCategory = categoryStack.length ? categoryStack[categoryStack.length - 1] : null |
| 91 | + if (category !== parentCategory) { |
| 92 | + categoryChange(parentCategory, category, e.startTime) |
| 93 | + } |
| 94 | + categoryStack.push(category) |
| 95 | + } |
| 96 | + |
| 97 | + /** |
| 98 | + * @param {!SDK.TracingModel.Event} e |
| 99 | + */ |
| 100 | + function onEndEvent(e: Event): void { |
| 101 | + const category = categoryStack.pop() |
| 102 | + const parentCategory = categoryStack.length ? categoryStack[categoryStack.length - 1] : null |
| 103 | + if (category !== parentCategory) { |
| 104 | + categoryChange(category, parentCategory, e.endTime) |
| 105 | + } |
| 106 | + } |
| 107 | + return aggregatedStats |
| 108 | + } |
| 109 | +} |
0 commit comments