@paulirish/trace_engine 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/trace.mjs.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../../front_end/models/trace/trace.ts", "../../../../front_end/models/trace/handlers/handlers.ts", "../../../../front_end/models/trace/handlers/Migration.ts", "../../../../front_end/models/trace/handlers/AnimationHandler.ts", "../../../../front_end/core/platform/array-utilities.ts", "../../../../front_end/core/platform/map-utilities.ts", "../../../../front_end/core/platform/number-utilities.ts", "../../../../front_end/core/platform/typescript-utilities.ts", "../../../../front_end/models/trace/types/types.ts", "../../../../front_end/models/trace/types/Configuration.ts", "../../../../front_end/models/trace/types/File.ts", "../../../../front_end/models/trace/types/Timing.ts", "../../../../front_end/models/trace/types/TraceEvents.ts", "../../../../front_end/models/trace/handlers/types.ts", "../../../../front_end/models/trace/handlers/GPUHandler.ts", "../../../../front_end/models/trace/handlers/MetaHandler.ts", "../../../../front_end/models/trace/helpers/helpers.ts", "../../../../front_end/models/trace/helpers/SamplesIntegrator.ts", "../../../../front_end/models/trace/helpers/Timing.ts", "../../../../front_end/models/trace/helpers/Trace.ts", "../../../../front_end/models/trace/handlers/LayoutShiftsHandler.ts", "../../../../front_end/models/trace/handlers/PageLoadMetricsHandler.ts", "../../../../front_end/models/trace/handlers/ScreenshotsHandler.ts", "../../../../front_end/models/trace/handlers/MemoryHandler.ts", "../../../../front_end/models/trace/handlers/NetworkRequestsHandler.ts", "../../../../front_end/models/trace/handlers/UserInteractionsHandler.ts", "../../../../front_end/models/trace/handlers/UserTimingsHandler.ts", "../../../../front_end/models/trace/handlers/WarningsHandler.ts", "../../../../front_end/models/trace/handlers/WorkersHandler.ts", "../../../../front_end/models/trace/handlers/ModelHandlers.ts", "../../../../front_end/models/trace/handlers/AuctionWorkletsHandler.ts", "../../../../front_end/models/trace/handlers/LargestImagePaintHandler.ts", "../../../../front_end/models/trace/handlers/LargestTextPaintHandler.ts", "../../../../front_end/models/trace/handlers/RendererHandler.ts", "../../../../front_end/models/trace/handlers/SamplesHandler.ts", "../../../../front_end/models/cpu_profile/CPUProfileDataModel.ts", "../../../../front_end/models/cpu_profile/ProfileTreeModel.ts", "../../../../front_end/models/trace/LegacyTracingModel.ts", "../../../../front_end/models/trace/ModelImpl.ts", "../../../../front_end/models/trace/Processor.ts", "../../../../front_end/models/trace/TreeManipulator.ts"],
4
- "sourcesContent": ["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Extras from './extras/extras.js';\nimport * as Handlers from './handlers/handlers.js';\nimport * as Helpers from './helpers/helpers.js';\n// Purposefully use a shorter name here so references to this are\n// Legacy.TracingModel.\nimport * as Legacy from './LegacyTracingModel.js';\nimport * as TraceModel from './ModelImpl.js';\nimport * as Processor from './Processor.js';\nimport * as TracingManager from './TracingManager.js';\nimport * as TreeManipulator from './TreeManipulator.js';\nimport * as Types from './types/types.js';\n\nexport {\n Extras,\n Handlers,\n Helpers,\n Legacy,\n Processor,\n TraceModel,\n TracingManager,\n TreeManipulator,\n Types,\n};\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as Migration from './Migration.js';\nexport * as ModelHandlers from './ModelHandlers.js';\nexport * as Types from './types.js';\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Animations from './AnimationHandler.js';\nimport * as GPU from './GPUHandler.js';\nimport * as LayoutShifts from './LayoutShiftsHandler.js';\nimport * as Memory from './MemoryHandler.js';\nimport * as NetworkRequests from './NetworkRequestsHandler.js';\nimport * as PageLoadMetrics from './PageLoadMetricsHandler.js';\nimport * as Screenshots from './ScreenshotsHandler.js';\nimport type * as Renderer from './RendererHandler.js';\nimport type * as Samples from './SamplesHandler.js';\nimport * as UserInteractions from './UserInteractionsHandler.js';\nimport * as UserTimings from './UserTimingsHandler.js';\nimport * as Warnings from './WarningsHandler.js';\nimport * as Workers from './WorkersHandler.js';\n\nimport type * as Types from './types.js';\n\n// As we migrate the data engine we are incrementally enabling the new handlers\n// one by one, so we do not waste effort parsing data that we do not use. This\n// object should be updated when we add a new handler to enable it.\nexport const ENABLED_TRACE_HANDLERS = {\n Animations,\n UserTimings,\n PageLoadMetrics,\n UserInteractions,\n LayoutShifts,\n Screenshots,\n GPU,\n Memory,\n NetworkRequests,\n Warnings,\n Workers,\n};\n\nexport type EnabledHandlersDuringMigration = typeof ENABLED_TRACE_HANDLERS;\n\n// Renderer and Samples handler are only executed when the panel is run\n// from the component examples server. Thus we mark them as optional\n// properties during the migration.\nexport type PartialTraceData = Readonly<Types.EnabledHandlerDataWithMeta<EnabledHandlersDuringMigration>>&{\n // eslint-disable-next-line @typescript-eslint/naming-convention\n readonly Renderer?: Readonly<ReturnType<typeof Renderer['data']>>,\n // eslint-disable-next-line @typescript-eslint/naming-convention\n readonly Samples?: Readonly<ReturnType<typeof Samples['data']>>,\n};\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\nconst animations: Types.TraceEvents.TraceEventAnimation[] = [];\nconst animationsSyntheticEvents: Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[] = [];\n\nexport interface AnimationData {\n animations: readonly Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[];\n}\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function reset(): void {\n animations.length = 0;\n animationsSyntheticEvents.length = 0;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (Types.TraceEvents.isTraceEventAnimation(event)) {\n animations.push(event);\n return;\n }\n}\n\nexport async function finalize(): Promise<void> {\n const matchedEvents = matchBeginningAndEndEvents();\n\n createSortedAnimationsSyntheticEvents(matchedEvents);\n\n handlerState = HandlerState.FINALIZED;\n}\n\nfunction matchBeginningAndEndEvents(): Map<string, {\n begin: Types.TraceEvents.TraceEventNestableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventNestableAsyncEnd | null,\n}> {\n // map to store begin and end of the event\n const matchedEvents: Map<string, {\n begin: Types.TraceEvents.TraceEventNestableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventNestableAsyncEnd | null,\n }> = new Map();\n\n // looking for start and end\n for (const event of animations) {\n const id = event.id2;\n\n if (id === undefined) {\n continue;\n }\n\n const syntheticId = `${event.cat}:${id.local}:${event.name}`;\n\n const otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedEvents, syntheticId, () => {\n return {begin: null, end: null};\n });\n\n const isStartEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_START;\n const isEndEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_END;\n\n if (isStartEvent) {\n otherEventsWithID.begin = {\n ...event,\n ph: Types.TraceEvents.Phase.ASYNC_NESTABLE_START,\n id2: {\n local: event.id2?.local,\n },\n id: event.args?.id,\n };\n } else if (isEndEvent) {\n otherEventsWithID.end = {\n ...event,\n ph: Types.TraceEvents.Phase.ASYNC_NESTABLE_END,\n id2: {\n local: event.id2?.local,\n },\n id: event.args?.id,\n };\n }\n }\n\n return matchedEvents;\n}\n\nfunction createSortedAnimationsSyntheticEvents(matchedEvents: Map<string, {\n begin: Types.TraceEvents.TraceEventNestableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventNestableAsyncEnd | null,\n}>): void {\n for (const [id, eventsPair] of matchedEvents.entries()) {\n if (!eventsPair.begin || !eventsPair.end) {\n continue;\n }\n\n const event: Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent = {\n cat: eventsPair.end.cat,\n ph: eventsPair.end.ph,\n pid: eventsPair.end.pid,\n tid: eventsPair.end.tid,\n id,\n name: eventsPair.begin.name,\n dur: Types.Timing.MicroSeconds(eventsPair.end.ts - eventsPair.begin.ts),\n ts: eventsPair.begin.ts,\n args: {\n data: {\n beginEvent: eventsPair.begin,\n endEvent: eventsPair.end,\n },\n },\n };\n\n if (event.dur < 0) {\n // We have seen in the backend that sometimes animation events get\n // generated with multiple begin entries, or multiple end entries, and this\n // can cause invalid data on the performance panel, so we drop them.\n // crbug.com/1472375\n continue;\n }\n animationsSyntheticEvents.push(event);\n }\n\n animationsSyntheticEvents.sort((a, b) => a.ts - b.ts);\n}\n\nexport function data(): AnimationData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Animation handler is not finalized');\n }\n\n return {\n animations: Array.from(animationsSyntheticEvents),\n };\n}\n", "// Copyright (c) 2020 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport const removeElement = <T>(array: T[], element: T, firstOnly?: boolean): boolean => {\n let index = array.indexOf(element);\n if (index === -1) {\n return false;\n }\n if (firstOnly) {\n array.splice(index, 1);\n return true;\n }\n for (let i = index + 1, n = array.length; i < n; ++i) {\n if (array[i] !== element) {\n array[index++] = array[i];\n }\n }\n array.length = index;\n return true;\n};\n\ntype NumberComparator = (a: number, b: number) => number;\n\nfunction swap(array: number[], i1: number, i2: number): void {\n const temp = array[i1];\n array[i1] = array[i2];\n array[i2] = temp;\n}\n\nfunction partition(\n array: number[], comparator: NumberComparator, left: number, right: number, pivotIndex: number): number {\n const pivotValue = array[pivotIndex];\n swap(array, right, pivotIndex);\n let storeIndex = left;\n for (let i = left; i < right; ++i) {\n if (comparator(array[i], pivotValue) < 0) {\n swap(array, storeIndex, i);\n ++storeIndex;\n }\n }\n swap(array, right, storeIndex);\n return storeIndex;\n}\n\nfunction quickSortRange(\n array: number[], comparator: NumberComparator, left: number, right: number, sortWindowLeft: number,\n sortWindowRight: number): void {\n if (right <= left) {\n return;\n }\n const pivotIndex = Math.floor(Math.random() * (right - left)) + left;\n const pivotNewIndex = partition(array, comparator, left, right, pivotIndex);\n if (sortWindowLeft < pivotNewIndex) {\n quickSortRange(array, comparator, left, pivotNewIndex - 1, sortWindowLeft, sortWindowRight);\n }\n if (pivotNewIndex < sortWindowRight) {\n quickSortRange(array, comparator, pivotNewIndex + 1, right, sortWindowLeft, sortWindowRight);\n }\n}\n\nexport function sortRange(\n array: number[], comparator: NumberComparator, leftBound: number, rightBound: number, sortWindowLeft: number,\n sortWindowRight: number): number[] {\n if (leftBound === 0 && rightBound === (array.length - 1) && sortWindowLeft === 0 && sortWindowRight >= rightBound) {\n array.sort(comparator);\n } else {\n quickSortRange(array, comparator, leftBound, rightBound, sortWindowLeft, sortWindowRight);\n }\n return array;\n}\nexport const binaryIndexOf = <T, S>(array: T[], value: S, comparator: (a: S, b: T) => number): number => {\n const index = lowerBound(array, value, comparator);\n return index < array.length && comparator(value, array[index]) === 0 ? index : -1;\n};\n\nfunction mergeOrIntersect<T>(\n array1: T[], array2: T[], comparator: (a: T, b: T) => number, mergeNotIntersect: boolean): T[] {\n const result = [];\n let i = 0;\n let j = 0;\n while (i < array1.length && j < array2.length) {\n const compareValue = comparator(array1[i], array2[j]);\n if (mergeNotIntersect || !compareValue) {\n result.push(compareValue <= 0 ? array1[i] : array2[j]);\n }\n if (compareValue <= 0) {\n i++;\n }\n if (compareValue >= 0) {\n j++;\n }\n }\n if (mergeNotIntersect) {\n while (i < array1.length) {\n result.push(array1[i++]);\n }\n while (j < array2.length) {\n result.push(array2[j++]);\n }\n }\n return result;\n}\n\nexport const intersectOrdered = <T>(array1: T[], array2: T[], comparator: (a: T, b: T) => number): T[] => {\n return mergeOrIntersect(array1, array2, comparator, false);\n};\n\nexport const mergeOrdered = <T>(array1: T[], array2: T[], comparator: (a: T, b: T) => number): T[] => {\n return mergeOrIntersect(array1, array2, comparator, true);\n};\n\nexport const DEFAULT_COMPARATOR = (a: string|number, b: string|number): -1|0|1 => {\n return a < b ? -1 : (a > b ? 1 : 0);\n};\n\n/**\n * Returns the index of the element closest to the needle that is equal to or\n * greater than it. Assumes that the provided array is sorted.\n *\n * If no element is found, the right bound is returned.\n *\n * Uses the provided comparator function to determine if two items are equal or\n * if one is greater than the other. If you are working with strings or\n * numbers, you can use ArrayUtilities.DEFAULT_COMPARATOR. Otherwise, you\n * should define one that takes the needle element and an element from the\n * array and returns a positive or negative number to indicate which is greater\n * than the other.\n *\n * When specified, |left| (inclusive) and |right| (exclusive) indices\n * define the search window.\n */\nexport function lowerBound<T>(\n array: Uint32Array|Int32Array, needle: T, comparator: (needle: T, b: number) => number, left?: number,\n right?: number): number;\nexport function lowerBound<S, T>(\n array: S[], needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number;\nexport function lowerBound<S, T, A extends S[]>(\n array: A, needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number {\n let l = left || 0;\n let r = right !== undefined ? right : array.length;\n while (l < r) {\n const m = (l + r) >> 1;\n if (comparator(needle, array[m]) > 0) {\n l = m + 1;\n } else {\n r = m;\n }\n }\n return r;\n}\n\n/**\n * Returns the index of the element closest to the needle that is greater than\n * it. Assumes that the provided array is sorted.\n *\n * If no element is found, the right bound is returned.\n *\n * Uses the provided comparator function to determine if two items are equal or\n * if one is greater than the other. If you are working with strings or\n * numbers, you can use ArrayUtilities.DEFAULT_COMPARATOR. Otherwise, you\n * should define one that takes the needle element and an element from the\n * array and returns a positive or negative number to indicate which is greater\n * than the other.\n *\n * When specified, |left| (inclusive) and |right| (exclusive) indices\n * define the search window.\n */\nexport function upperBound<T>(\n array: Uint32Array, needle: T, comparator: (needle: T, b: number) => number, left?: number, right?: number): number;\nexport function upperBound<S, T>(\n array: S[], needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number;\nexport function upperBound<S, T, A extends S[]>(\n array: A, needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number {\n let l = left || 0;\n let r = right !== undefined ? right : array.length;\n while (l < r) {\n const m = (l + r) >> 1;\n if (comparator(needle, array[m]) >= 0) {\n l = m + 1;\n } else {\n r = m;\n }\n }\n return r;\n}\n\nconst enum NearestSearchStart {\n BEGINNING = 'BEGINNING',\n END = 'END',\n}\n/**\n * Obtains the first or last item in the array that satisfies the predicate function.\n * So, for example, if the array were arr = [2, 4, 6, 8, 10], and you are looking for\n * the last item arr[i] such that arr[i] < 5 you would be returned 1, because\n * array[1] is 4, the last item in the array that satisfies the\n * predicate function.\n *\n * If instead you were looking for the first item in the same array that satisfies\n * arr[i] > 5 you would be returned 2 because array[2] = 6.\n *\n * Please note: this presupposes that the array is already ordered.\n */\nfunction nearestIndex<T>(\n arr: readonly T[], predicate: (arrayItem: T) => boolean, searchStart: NearestSearchStart): number|null {\n const searchFromEnd = searchStart === NearestSearchStart.END;\n if (arr.length === 0) {\n return null;\n }\n\n let left = 0;\n let right = arr.length - 1;\n let pivot = 0;\n let matchesPredicate = false;\n let moveToTheRight = false;\n let middle = 0;\n do {\n middle = left + (right - left) / 2;\n pivot = searchFromEnd ? Math.ceil(middle) : Math.floor(middle);\n matchesPredicate = predicate(arr[pivot]);\n moveToTheRight = matchesPredicate === searchFromEnd;\n if (moveToTheRight) {\n left = Math.min(right, pivot + (left === pivot ? 1 : 0));\n } else {\n right = Math.max(left, pivot + (right === pivot ? -1 : 0));\n }\n } while (right !== left);\n\n // Special-case: the indexed item doesn't pass the predicate. This\n // occurs when none of the items in the array are a match for the\n // predicate.\n if (!predicate(arr[left])) {\n return null;\n }\n return left;\n}\n\n/**\n * Obtains the first item in the array that satisfies the predicate function.\n * So, for example, if the array was arr = [2, 4, 6, 8, 10], and you are looking for\n * the first item arr[i] such that arr[i] > 5 you would be returned 2, because\n * array[2] is 6, the first item in the array that satisfies the\n * predicate function.\n *\n * Please note: this presupposes that the array is already ordered.\n */\nexport function nearestIndexFromBeginning<T>(arr: T[], predicate: (arrayItem: T) => boolean): number|null {\n return nearestIndex(arr, predicate, NearestSearchStart.BEGINNING);\n}\n\n/**\n * Obtains the last item in the array that satisfies the predicate function.\n * So, for example, if the array was arr = [2, 4, 6, 8, 10], and you are looking for\n * the last item arr[i] such that arr[i] < 5 you would be returned 1, because\n * arr[1] is 4, the last item in the array that satisfies the\n * predicate function.\n *\n * Please note: this presupposes that the array is already ordered.\n */\n\nexport function nearestIndexFromEnd<T>(arr: readonly T[], predicate: (arrayItem: T) => boolean): number|null {\n return nearestIndex(arr, predicate, NearestSearchStart.END);\n}\n\n// Type guard for ensuring that `arr` does not contain null or undefined\nexport function arrayDoesNotContainNullOrUndefined<T>(arr: (T|null|undefined)[]): arr is T[] {\n return !arr.includes(null) && !arr.includes(undefined);\n}\n", "// Copyright (c) 2020 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport const inverse = function<K, V>(map: Map<K, V>): Multimap<V, K> {\n const result = new Multimap<V, K>();\n for (const [key, value] of map.entries()) {\n result.set(value, key);\n }\n return result;\n};\n\nexport class Multimap<K, V> {\n private map = new Map<K, Set<V>>();\n\n set(key: K, value: V): void {\n let set = this.map.get(key);\n if (!set) {\n set = new Set();\n this.map.set(key, set);\n }\n set.add(value);\n }\n\n get(key: K): Set<V> {\n return this.map.get(key) || new Set();\n }\n\n has(key: K): boolean {\n return this.map.has(key);\n }\n\n hasValue(key: K, value: V): boolean {\n const set = this.map.get(key);\n if (!set) {\n return false;\n }\n return set.has(value);\n }\n\n get size(): number {\n return this.map.size;\n }\n\n delete(key: K, value: V): boolean {\n const values = this.get(key);\n if (!values) {\n return false;\n }\n const result = values.delete(value);\n if (!values.size) {\n this.map.delete(key);\n }\n return result;\n }\n\n deleteAll(key: K): void {\n this.map.delete(key);\n }\n\n keysArray(): K[] {\n return [...this.map.keys()];\n }\n\n valuesArray(): V[] {\n const result = [];\n for (const set of this.map.values()) {\n result.push(...set.values());\n }\n return result;\n }\n\n clear(): void {\n this.map.clear();\n }\n}\n\n/**\n * Gets value for key, assigning a default if value is falsy.\n */\nexport function getWithDefault<K extends {}, V>(\n map: WeakMap<K, V>|Map<K, V>, key: K, defaultValueFactory: (key?: K) => V): V {\n let value = map.get(key);\n if (!value) {\n value = defaultValueFactory(key);\n map.set(key, value);\n }\n\n return value;\n}\n", "// Copyright (c) 2020 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport const clamp = (num: number, min: number, max: number): number => {\n let clampedNumber = num;\n if (num < min) {\n clampedNumber = min;\n } else if (num > max) {\n clampedNumber = max;\n }\n return clampedNumber;\n};\n\nexport const mod = (m: number, n: number): number => {\n return ((m % n) + n) % n;\n};\n\nexport const bytesToString = (bytes: number): string => {\n if (bytes < 1000) {\n return `${bytes.toFixed(0)}\\xA0B`;\n }\n\n const kilobytes = bytes / 1000;\n if (kilobytes < 100) {\n return `${kilobytes.toFixed(1)}\\xA0kB`;\n }\n if (kilobytes < 1000) {\n return `${kilobytes.toFixed(0)}\\xA0kB`;\n }\n\n const megabytes = kilobytes / 1000;\n if (megabytes < 100) {\n return `${megabytes.toFixed(1)}\\xA0MB`;\n }\n return `${megabytes.toFixed(0)}\\xA0MB`;\n};\n\nexport const toFixedIfFloating = (value: string): string => {\n if (!value || Number.isNaN(Number(value))) {\n return value;\n }\n const number = Number(value);\n return number % 1 ? number.toFixed(3) : String(number);\n};\n\n/**\n * Rounds a number (including float) down.\n */\nexport const floor = (value: number, precision: number = 0): number => {\n const mult = Math.pow(10, precision);\n return Math.floor(value * mult) / mult;\n};\n\n/**\n * Computes the great common divisor for two numbers.\n * If the numbers are floats, they will be rounded to an integer.\n */\nexport const greatestCommonDivisor = (a: number, b: number): number => {\n a = Math.round(a);\n b = Math.round(b);\n while (b !== 0) {\n const t = b;\n b = a % b;\n a = t;\n }\n return a;\n};\n\nconst commonRatios = new Map([\n ['8\u22365', '16\u223610'],\n]);\n\nexport const aspectRatio = (width: number, height: number): string => {\n const divisor = greatestCommonDivisor(width, height);\n if (divisor !== 0) {\n width /= divisor;\n height /= divisor;\n }\n const result = `${width}\u2236${height}`;\n return commonRatios.get(result) || result;\n};\n\nexport const withThousandsSeparator = function(num: number): string {\n let str = String(num);\n const re = /(\\d+)(\\d{3})/;\n while (str.match(re)) {\n str = str.replace(re, '$1\\xA0$2');\n } // \\xa0 is a non-breaking space\n return str;\n};\n", "// Copyright 2020 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * This is useful to keep TypeScript happy in a test - if you have a value\n * that's potentially `null` you can use this function to assert that it isn't,\n * and satisfy TypeScript that the value is present.\n */\nexport function assertNotNullOrUndefined<T>(val: T): asserts val is NonNullable<T> {\n if (val === null || val === undefined) {\n throw new Error(`Expected given value to not be null/undefined but it was: ${val}`);\n }\n}\n\nexport function assertNever(type: never, message: string): never {\n throw new Error(message);\n}\n\n/**\n * This is useful to check on the type-level that the unhandled cases of\n * a switch are exactly `T` (where T is usually a union type of enum values).\n * @param caseVariable\n */\nexport function assertUnhandled<T>(_caseVariable: T): T {\n return _caseVariable;\n}\n\nexport type FieldsThatExtend<Type, Selector> = {\n [Key in keyof Type]: Type[Key] extends Selector ? Key : never;\n}[keyof Type];\n\nexport type PickFieldsThatExtend<Type, Selector> = Pick<Type, FieldsThatExtend<Type, Selector>>;\n\n/**\n * Turns a Union type (a | b) into an Intersection type (a & b).\n * This is a helper type to implement the \"NoUnion\" guard.\n *\n * Adapted from https://stackoverflow.com/a/50375286.\n *\n * The tautological `T extends any` is necessary to trigger distributivity for\n * plain unions, e.g. in IntersectionFromUnion<'a'|'b'> TypeScript expands it\n * to ('a' extends any ? (arg: 'a') => void : never)\n * | ('b' extends any ? (arg: 'b') => void : never)\n *\n * The second extends clause then asks TypeScript to find a type of the form\n * `(arg: infer U) => void` that upper-bounds the union, i.e., intuitively,\n * a type that converts to each of the union members. This forces U to be the\n * intersection of 'a' and 'b' in the example.\n *\n * Please note that some intersection types are simply impossible, e.g.\n * `string & number`. There is no type that fulfills both at the same time. A\n * union of this kind is reduced to `never`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype IntersectionFromUnion<T> = (T extends any ? (arg: T) => void : never) extends((arg: infer U) => void) ? U : never;\n\n/**\n * When writing generic code it may be desired to disallow Union types from\n * being passed. This type can be used in those cases.\n *\n * function foo<T>(argument: NoUnion<T>) {...}\n *\n * Would result in a compile error for foo<a|b>(...); invocations as `argument`\n * would be typed as `never`.\n *\n * Adapted from https://stackoverflow.com/a/50641073.\n *\n * Conditional types become distributive when receiving a union type. To\n * prevent this from happening, we use `[T] extends [IntersectionFromUnion<T>]`\n * instead of `T extends IntersectionFromUnion<T>`.\n * See: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html\n */\nexport type NoUnion<T> = [T] extends [IntersectionFromUnion<T>] ? T : never;\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as Configuration from './Configuration.js';\nexport * as File from './File.js';\nexport * as Timing from './Timing.js';\nexport * as TraceEvents from './TraceEvents.js';\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport type Configuration = Readonly<{\n settings: {\n // Currently empty but defining here as we will migrate more settings into this.\n },\n experiments: {\n /**\n * Include V8 RCS in the timeline\n */\n timelineV8RuntimeCallStats: boolean,\n /**\n * Show all events: disable the default filtering which hides and excludes some events.\n */\n timelineShowAllEvents: boolean,\n },\n processing: {\n /**\n * How long the processor should pause between event chunks.\n */\n pauseDuration: number,\n /**\n * How many events should be processed before yielding to the main thread for a pause.\n */\n eventsPerChunk: number,\n },\n}>;\n\nexport const DEFAULT: Configuration = {\n settings: {},\n experiments: {\n timelineV8RuntimeCallStats: false,\n timelineShowAllEvents: false,\n },\n processing: {\n eventsPerChunk: 15_000,\n pauseDuration: 1,\n },\n};\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport {type TraceEventData} from './TraceEvents.js';\nexport type TraceFile = {\n traceEvents: readonly TraceEventData[],\n metadata: MetaData,\n};\n\nexport const enum DataOrigin {\n CPUProfile = 'CPUProfile',\n TraceEvents = 'TraceEvents',\n}\n\n/**\n * Trace metadata that we persist to the file. This will allow us to\n * store specifics for the trace, e.g., which tracks should be visible\n * on load.\n */\nexport interface MetaData {\n source?: 'DevTools';\n startTime?: string;\n networkThrottling?: string;\n cpuThrottling?: number;\n hardwareConcurrency?: number;\n dataOrigin?: DataOrigin;\n}\n\nexport type Contents = TraceFile|TraceEventData[];\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/* eslint-disable no-unused-private-class-members */\n\nexport type MicroSeconds = number&{_tag: 'MicroSeconds'};\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function MicroSeconds(value: number): MicroSeconds {\n return value as MicroSeconds;\n}\n\nexport type MilliSeconds = number&{_tag: 'MilliSeconds'};\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function MilliSeconds(value: number): MilliSeconds {\n return value as MilliSeconds;\n}\nexport type Seconds = number&{_tag: 'Seconds'};\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function Seconds(value: number): Seconds {\n return value as Seconds;\n}\n\nexport const enum TimeUnit {\n MICROSECONDS = 0,\n MILLISECONDS = 1,\n SECONDS = 2,\n MINUTES = 3,\n}\n\n// Other types.\n\nexport interface TraceWindow {\n min: MicroSeconds;\n max: MicroSeconds;\n range: MicroSeconds;\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/* eslint-disable no-unused-private-class-members */\nimport type * as Protocol from '../../../generated/protocol.js';\n\nimport {type MicroSeconds, type MilliSeconds, type Seconds} from './Timing.js';\n\n// Trace Events.\nexport const enum Phase {\n // Standard\n BEGIN = 'B',\n END = 'E',\n COMPLETE = 'X',\n INSTANT = 'I',\n COUNTER = 'C',\n\n // Async\n ASYNC_NESTABLE_START = 'b',\n ASYNC_NESTABLE_INSTANT = 'n',\n ASYNC_NESTABLE_END = 'e',\n ASYNC_STEP_INTO = 'T',\n ASYNC_BEGIN = 'S',\n ASYNC_END = 'F',\n ASYNC_STEP_PAST = 'p',\n\n // Flow\n FLOW_START = 's',\n FLOW_STEP = 't',\n FLOW_END = 'f',\n\n // Sample\n SAMPLE = 'P',\n\n // Object\n OBJECT_CREATED = 'N',\n OBJECT_SNAPSHOT = 'O',\n OBJECT_DESTROYED = 'D',\n\n // Metadata\n METADATA = 'M',\n\n // Memory Dump\n MEMORY_DUMP_GLOBAL = 'V',\n MEMORY_DUMP_PROCESS = 'v',\n\n // Mark\n MARK = 'R',\n\n // Clock sync\n CLOCK_SYNC = 'c',\n}\n\nexport function isNestableAsyncPhase(phase: Phase): boolean {\n return phase === Phase.ASYNC_NESTABLE_START || phase === Phase.ASYNC_NESTABLE_END ||\n phase === Phase.ASYNC_NESTABLE_INSTANT;\n}\n\nexport function isAsyncPhase(phase: Phase): boolean {\n return isNestableAsyncPhase(phase) || phase === Phase.ASYNC_BEGIN || phase === Phase.ASYNC_STEP_INTO ||\n phase === Phase.ASYNC_END || phase === Phase.ASYNC_STEP_PAST;\n}\n\nexport function isFlowPhase(phase: Phase): boolean {\n return phase === Phase.FLOW_START || phase === Phase.FLOW_STEP || phase === Phase.FLOW_END;\n}\n\nexport const enum TraceEventScope {\n THREAD = 't',\n PROCESS = 'p',\n GLOBAL = 'g',\n}\n\nexport interface TraceEventData {\n args?: TraceEventArgs;\n cat: string;\n name: string;\n ph: Phase;\n pid: ProcessID;\n tid: ThreadID;\n tts?: MicroSeconds;\n ts: MicroSeconds;\n tdur?: MicroSeconds;\n dur?: MicroSeconds;\n}\n\nexport interface TraceEventArgs {\n data?: TraceEventArgsData;\n}\n\nexport interface TraceEventArgsData {\n stackTrace?: TraceEventCallFrame[];\n navigationId?: string;\n frame?: string;\n}\n\nexport interface TraceEventCallFrame {\n codeType?: string;\n functionName: string;\n scriptId: number;\n columnNumber?: number;\n lineNumber?: number;\n url?: string;\n}\n\nexport interface TraceFrame {\n frame: string;\n name: string;\n processId: ProcessID;\n url: string;\n parent?: string;\n}\n\n// Sample events.\n\nexport interface TraceEventSample extends TraceEventData {\n ph: Phase.SAMPLE;\n}\n\nexport interface TraceEventProfile extends TraceEventSample {\n name: 'Profile';\n id: ProfileID;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n startTime: MicroSeconds,\n },\n };\n}\n\nexport interface TraceEventProfileChunk extends TraceEventSample {\n name: 'ProfileChunk';\n id: ProfileID;\n args: TraceEventArgs&{\n // `data` is only missing in \"fake\" traces\n data?: TraceEventArgsData & {\n cpuProfile?: TraceEventPartialProfile,\n timeDeltas?: MicroSeconds[],\n lines?: MicroSeconds[],\n },\n };\n}\n\nexport interface TraceEventPartialProfile {\n nodes?: TraceEventPartialNode[];\n samples: CallFrameID[];\n}\n\nexport interface TraceEventPartialNode {\n callFrame: TraceEventCallFrame;\n id: CallFrameID;\n parent?: CallFrameID;\n}\n\n// Complete events.\n\nexport interface TraceEventComplete extends TraceEventData {\n ph: Phase.COMPLETE;\n dur: MicroSeconds;\n}\n\nexport interface TraceEventFireIdleCallback extends TraceEventComplete {\n name: 'FireIdleCallback';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n allottedMilliseconds: MilliSeconds,\n frame: string,\n id: number,\n timedOut: boolean,\n },\n };\n}\n\nexport interface TraceEventDispatch extends TraceEventComplete {\n name: 'EventDispatch';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n type: string,\n },\n };\n}\n\nexport interface TraceEventParseHTML extends TraceEventComplete {\n name: 'ParseHTML';\n args: TraceEventArgs&{\n beginData: {\n frame: string,\n startLine: number,\n url: string,\n },\n endData?: {\n endLine: number,\n },\n };\n}\n\nexport interface TraceEventBegin extends TraceEventData {\n ph: Phase.BEGIN;\n}\n\nexport interface TraceEventEnd extends TraceEventData {\n ph: Phase.END;\n}\n\n/**\n * This denotes a complete event created from a pair of begin and end\n * events. For practicality, instead of always having to look for the\n * end event corresponding to a begin event, we create a synthetic\n * complete event that comprises the data of both from the beginning in\n * the RendererHandler.\n */\nexport type TraceEventSyntheticCompleteEvent = TraceEventComplete;\n\nexport interface TraceEventEventTiming extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_START|Phase.ASYNC_NESTABLE_END;\n name: KnownEventName.EventTiming;\n id: string;\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n cancelable: boolean,\n duration: MilliSeconds,\n processingEnd: MicroSeconds,\n processingStart: MicroSeconds,\n timeStamp: MicroSeconds,\n interactionId?: number, type: string,\n },\n };\n}\n\nexport interface TraceEventEventTimingBegin extends TraceEventEventTiming {\n ph: Phase.ASYNC_NESTABLE_START;\n}\nexport interface TraceEventEventTimingEnd extends TraceEventEventTiming {\n ph: Phase.ASYNC_NESTABLE_END;\n}\n\nexport interface TraceEventGPUTask extends TraceEventComplete {\n name: 'GPUTask';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n /* eslint-disable @typescript-eslint/naming-convention */\n renderer_pid: ProcessID,\n used_bytes: number,\n /* eslint-enable @typescript-eslint/naming-convention */\n },\n };\n}\n\nexport interface TraceEventSyntheticNetworkRedirect {\n url: string;\n priority: string;\n requestMethod?: string;\n ts: MicroSeconds;\n dur: MicroSeconds;\n}\n\n// TraceEventProcessedArgsData is used to store the processed data of a network\n// request. Which is used to distinguish from the date we extract from the\n// trace event directly.\ninterface TraceEventSyntheticArgsData {\n dnsLookup: MicroSeconds;\n download: MicroSeconds;\n downloadStart: MicroSeconds;\n finishTime: MicroSeconds;\n initialConnection: MicroSeconds;\n isDiskCached: boolean;\n isHttps: boolean;\n isMemoryCached: boolean;\n isPushedResource: boolean;\n networkDuration: MicroSeconds;\n processingDuration: MicroSeconds;\n proxyNegotiation: MicroSeconds;\n queueing: MicroSeconds;\n redirectionDuration: MicroSeconds;\n requestSent: MicroSeconds;\n sendStartTime: MicroSeconds;\n ssl: MicroSeconds;\n stalled: MicroSeconds;\n totalTime: MicroSeconds;\n waiting: MicroSeconds;\n}\n\nexport interface TraceEventSyntheticNetworkRequest extends TraceEventComplete {\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n syntheticData: TraceEventSyntheticArgsData,\n // All fields below are from TraceEventsForNetworkRequest,\n // Required fields\n decodedBodyLength: number,\n encodedDataLength: number,\n frame: string,\n fromServiceWorker: boolean,\n host: string,\n mimeType: string,\n pathname: string,\n search: string,\n priority: Priority,\n initialPriority: Priority,\n protocol: string,\n redirects: TraceEventSyntheticNetworkRedirect[],\n renderBlocking: RenderBlocking,\n requestId: string,\n requestingFrameUrl: string,\n statusCode: number,\n url: string,\n // Optional fields\n requestMethod?: string,\n timing?: TraceEventResourceReceiveResponseTimingData,\n },\n };\n cat: 'loading';\n name: 'SyntheticNetworkRequest';\n ph: Phase.COMPLETE;\n dur: MicroSeconds;\n tdur: MicroSeconds;\n ts: MicroSeconds;\n tts: MicroSeconds;\n pid: ProcessID;\n tid: ThreadID;\n}\n\nexport const enum AuctionWorkletType {\n BIDDER = 'bidder',\n SELLER = 'seller',\n // Not expected to be used, but here as a fallback in case new types get\n // added and we have yet to update the trace engine.\n UNKNOWN = 'unknown',\n}\n\nexport interface SyntheticAuctionWorkletEvent extends TraceEventInstant {\n name: 'SyntheticAuctionWorkletEvent';\n // The PID that the AuctionWorklet is running in.\n pid: ProcessID;\n // URL\n host: string;\n // An ID used to pair up runningInProcessEvents with doneWithProcessEvents\n target: string;\n type: AuctionWorkletType;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n // There are two threads for a worklet that we care about, so we gather\n // the thread_name events so we can know the PID and TID for them (and\n // hence display the right events in the track for each thread)\n utilityThread: TraceEventThreadName,\n v8HelperThread: TraceEventThreadName,\n } &\n (\n // This type looks odd, but this is because these events could either have:\n // 1. Just the DoneWithProcess event\n // 2. Just the RunningInProcess event\n // 3. Both events\n // But crucially it cannot have both events missing, hence listing all the\n // allowed cases.\n // Clang is disabled as the combination of nested types and optional\n // properties cause it to weirdly indent some of the properties and make it\n // very unreadable.\n // clang-format off\n {\n runningInProcessEvent: TraceEventAuctionWorkletRunningInProcess,\n doneWithProcessEvent: TraceEventAuctionWorkletDoneWithProcess,\n } |\n {\n runningInProcessEvent?: TraceEventAuctionWorkletRunningInProcess,\n doneWithProcessEvent: TraceEventAuctionWorkletDoneWithProcess,\n } |\n {\n doneWithProcessEvent?: TraceEventAuctionWorkletDoneWithProcess,\n runningInProcessEvent: TraceEventAuctionWorkletRunningInProcess,\n\n }),\n // clang-format on\n };\n}\nexport interface TraceEventAuctionWorkletRunningInProcess extends TraceEventData {\n name: 'AuctionWorkletRunningInProcess';\n ph: Phase.INSTANT;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n host: string,\n pid: ProcessID,\n target: string,\n type: AuctionWorkletType,\n },\n };\n}\nexport interface TraceEventAuctionWorkletDoneWithProcess extends TraceEventData {\n name: 'AuctionWorkletDoneWithProcess';\n ph: Phase.INSTANT;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n host: string,\n pid: ProcessID,\n target: string,\n type: AuctionWorkletType,\n },\n };\n}\n\nexport function isTraceEventAuctionWorkletRunningInProcess(event: TraceEventData):\n event is TraceEventAuctionWorkletRunningInProcess {\n return event.name === 'AuctionWorkletRunningInProcess';\n}\nexport function isTraceEventAuctionWorkletDoneWithProcess(event: TraceEventData):\n event is TraceEventAuctionWorkletDoneWithProcess {\n return event.name === 'AuctionWorkletDoneWithProcess';\n}\n\n// Snapshot events.\n\nexport interface TraceEventSnapshot extends TraceEventData {\n args: TraceEventArgs&{\n snapshot: string,\n };\n name: 'Screenshot';\n cat: 'disabled-by-default-devtools.screenshot';\n ph: Phase.OBJECT_SNAPSHOT;\n}\n\n// Animation events.\n\nexport interface TraceEventAnimation extends TraceEventData {\n args: TraceEventArgs&{\n id?: string,\n name?: string,\n nodeId?: number,\n nodeName?: string,\n state?: string,\n compositeFailed?: number,\n unsupportedProperties?: string[],\n };\n name: 'Animation';\n id2?: {\n local?: string,\n };\n}\n\n// Metadata events.\n\nexport interface TraceEventMetadata extends TraceEventData {\n ph: Phase.METADATA;\n args: TraceEventArgs&{\n name?: string,\n uptime?: string,\n };\n}\n\nexport interface TraceEventThreadName extends TraceEventMetadata {\n name: 'thread_name';\n args: TraceEventArgs&{\n name?: string,\n };\n}\n\nexport interface TraceEventProcessName extends TraceEventMetadata {\n name: 'process_name';\n}\n\n// Mark events.\n\nexport interface TraceEventMark extends TraceEventData {\n ph: Phase.MARK;\n}\n\nexport interface TraceEventNavigationStart extends TraceEventMark {\n name: 'navigationStart';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n documentLoaderURL: string,\n isLoadingMainFrame: boolean,\n // isOutermostMainFrame was introduced in crrev.com/c/3625434 and exists\n // because of Fenced Frames\n // [github.com/WICG/fenced-frame/tree/master/explainer].\n // Fenced frames introduce a situation where isLoadingMainFrame could be\n // true for a navigation, but that navigation be within an embedded \"main\n // frame\", and therefore it wouldn't be on the top level main frame.\n // In situations where we need to distinguish that, we can rely on\n // isOutermostMainFrame, which will only be true for navigations on the\n // top level main frame.\n\n // This flag is optional as it was introduced in May 2022; so users\n // reasonably may import traces from before that date that do not have\n // this field present.\n isOutermostMainFrame?: boolean, navigationId: string,\n },\n frame: string,\n };\n}\n\nexport interface TraceEventFirstContentfulPaint extends TraceEventMark {\n name: 'firstContentfulPaint';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n navigationId: string,\n },\n };\n}\n\nexport interface TraceEventFirstPaint extends TraceEventMark {\n name: 'firstPaint';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n navigationId: string,\n },\n };\n}\n\nexport type PageLoadEvent = TraceEventFirstContentfulPaint|TraceEventMarkDOMContent|TraceEventInteractiveTime|\n TraceEventLargestContentfulPaintCandidate|TraceEventLayoutShift|TraceEventFirstPaint|TraceEventMarkLoad|\n TraceEventNavigationStart;\n\nexport interface TraceEventLargestContentfulPaintCandidate extends TraceEventMark {\n name: 'largestContentfulPaint::Candidate';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n candidateIndex: number,\n isOutermostMainFrame: boolean,\n isMainFrame: boolean,\n navigationId: string,\n nodeId: Protocol.DOM.BackendNodeId,\n type?: string,\n },\n };\n}\nexport interface TraceEventLargestImagePaintCandidate extends TraceEventMark {\n name: 'LargestImagePaint::Candidate';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n candidateIndex: number,\n imageUrl: string,\n // eslint-disable-next-line @typescript-eslint/naming-convention\n DOMNodeId: Protocol.DOM.BackendNodeId,\n },\n };\n}\nexport interface TraceEventLargestTextPaintCandidate extends TraceEventMark {\n name: 'LargestTextPaint::Candidate';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n candidateIndex: number,\n // eslint-disable-next-line @typescript-eslint/naming-convention\n DOMNodeId: Protocol.DOM.BackendNodeId,\n },\n };\n}\n\nexport interface TraceEventInteractiveTime extends TraceEventMark {\n name: 'InteractiveTime';\n args: TraceEventArgs&{\n args: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n total_blocking_time_ms: number,\n },\n frame: string,\n };\n}\n\n// Instant events.\n\nexport interface TraceEventInstant extends TraceEventData {\n ph: Phase.INSTANT;\n s: TraceEventScope;\n}\n\nexport interface TraceEventUpdateCounters extends TraceEventInstant {\n name: 'UpdateCounters';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n documents: number,\n jsEventListeners: number,\n jsHeapSizeUsed: number,\n nodes: number,\n },\n };\n}\n\nexport type TraceEventRendererEvent = TraceEventInstant|TraceEventComplete;\n\nexport interface TraceEventTracingStartedInBrowser extends TraceEventInstant {\n name: 'TracingStartedInBrowser';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n frameTreeNodeId: number,\n // Frames can only missing in \"fake\" traces\n frames?: TraceFrame[], persistentIds: boolean,\n },\n };\n}\n\nexport interface TraceEventTracingSessionIdForWorker extends TraceEventInstant {\n name: 'TracingSessionIdForWorker';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n url: string,\n workerId: WorkerId,\n workerThreadId: ThreadID,\n frame: string,\n },\n };\n}\nexport function isTraceEventTracingSessionIdForWorker(event: TraceEventData):\n event is TraceEventTracingSessionIdForWorker {\n return event.name === 'TracingSessionIdForWorker';\n}\n\nexport interface TraceEventFrameCommittedInBrowser extends TraceEventInstant {\n name: 'FrameCommittedInBrowser';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & TraceFrame,\n };\n}\n\nexport interface TraceEventMainFrameViewport extends TraceEventInstant {\n name: 'PaintTimingVisualizer::Viewport';\n args: {\n data: TraceEventArgsData&{\n // eslint-disable-next-line @typescript-eslint/naming-convention\n viewport_rect: number[],\n },\n };\n}\n\nexport interface TraceEventCommitLoad extends TraceEventInstant {\n name: 'CommitLoad';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n frame: string,\n isMainFrame: boolean,\n name: string,\n nodeId: number,\n page: string,\n parent: string,\n url: string,\n },\n };\n}\n\nexport interface TraceEventMarkDOMContent extends TraceEventInstant {\n name: 'MarkDOMContent';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n frame: string,\n isMainFrame: boolean,\n page: string,\n },\n };\n}\n\nexport interface TraceEventMarkLoad extends TraceEventInstant {\n name: 'MarkLoad';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n frame: string,\n isMainFrame: boolean,\n page: string,\n },\n };\n}\n\nexport interface TraceEventAsync extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_START|Phase.ASYNC_NESTABLE_INSTANT|Phase.ASYNC_NESTABLE_END|Phase.ASYNC_STEP_INTO|\n Phase.ASYNC_BEGIN|Phase.ASYNC_END|Phase.ASYNC_STEP_PAST;\n}\n\nexport type TraceRect = [number, number, number, number];\nexport type TraceImpactedNode = {\n // These keys come from the trace data, so we have to use underscores.\n /* eslint-disable @typescript-eslint/naming-convention */\n new_rect: TraceRect,\n node_id: Protocol.DOM.BackendNodeId,\n old_rect: TraceRect,\n /* eslint-enable @typescript-eslint/naming-convention */\n};\n\ntype LayoutShiftData = TraceEventArgsData&{\n // These keys come from the trace data, so we have to use underscores.\n /* eslint-disable @typescript-eslint/naming-convention */\n cumulative_score: number,\n frame_max_distance: number,\n had_recent_input: boolean,\n impacted_nodes: TraceImpactedNode[] | undefined,\n is_main_frame: boolean,\n overall_max_distance: number,\n region_rects: TraceRect[],\n score: number,\n weighted_score_delta: number,\n /* eslint-enable @typescript-eslint/naming-convention */\n};\n// These keys come from the trace data, so we have to use underscores.\nexport interface TraceEventLayoutShift extends TraceEventInstant {\n name: 'LayoutShift';\n normalized?: boolean;\n args: TraceEventArgs&{\n frame: string,\n data?: LayoutShiftData,\n };\n}\n\ninterface LayoutShiftSessionWindowData {\n // The sum of the weighted score of all the shifts\n // that belong to a session window.\n cumulativeWindowScore: number;\n // A consecutive generated in the frontend to\n // to identify a session window.\n id: number;\n}\nexport interface LayoutShiftParsedData {\n screenshotSource?: string;\n timeFromNavigation?: MicroSeconds;\n // The sum of the weighted scores of the shifts that\n // belong to a session window up until this shift\n // (inclusive).\n cumulativeWeightedScoreInWindow: number;\n sessionWindowData: LayoutShiftSessionWindowData;\n}\nexport interface SyntheticLayoutShift extends TraceEventLayoutShift {\n args: TraceEventArgs&{\n frame: string,\n data?: LayoutShiftData&{\n rawEvent: TraceEventLayoutShift,\n },\n };\n parsedData: LayoutShiftParsedData;\n}\n\nexport type Priority = 'Low'|'High'|'Medium'|'VeryHigh'|'Highest';\nexport type RenderBlocking = 'blocking'|'non_blocking'|'in_body_parser_blocking'|'potentially_blocking';\nexport interface TraceEventResourceSendRequest extends TraceEventInstant {\n name: 'ResourceSendRequest';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n requestId: string,\n url: string,\n priority: Priority,\n // TODO(crbug.com/1457985): change requestMethod to enum when confirm in the backend code.\n requestMethod?: string,\n renderBlocking?: RenderBlocking,\n },\n };\n}\n\nexport interface TraceEventResourceChangePriority extends TraceEventInstant {\n name: 'ResourceChangePriority';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n requestId: string,\n priority: Priority,\n },\n };\n}\n\nexport interface TraceEventResourceWillSendRequest extends TraceEventInstant {\n name: 'ResourceWillSendRequest';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n requestId: string,\n },\n };\n}\n\nexport interface TraceEventResourceFinish extends TraceEventInstant {\n name: 'ResourceFinish';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n decodedBodyLength: number,\n didFail: boolean,\n encodedDataLength: number,\n finishTime: Seconds,\n requestId: string,\n },\n };\n}\n\nexport interface TraceEventResourceReceivedData extends TraceEventInstant {\n name: 'ResourceReceivedData';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n encodedDataLength: number,\n frame: string,\n requestId: string,\n },\n };\n}\n\ninterface TraceEventResourceReceiveResponseTimingData {\n connectEnd: MilliSeconds;\n connectStart: MilliSeconds;\n dnsEnd: MilliSeconds;\n dnsStart: MilliSeconds;\n proxyEnd: MilliSeconds;\n proxyStart: MilliSeconds;\n pushEnd: MilliSeconds;\n pushStart: MilliSeconds;\n receiveHeadersEnd: MilliSeconds;\n requestTime: Seconds;\n sendEnd: MilliSeconds;\n sendStart: MilliSeconds;\n sslEnd: MilliSeconds;\n sslStart: MilliSeconds;\n workerReady: MilliSeconds;\n workerStart: MilliSeconds;\n}\n\nexport interface TraceEventResourceReceiveResponse extends TraceEventInstant {\n name: 'ResourceReceiveResponse';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n encodedDataLength: number,\n frame: string,\n fromCache: boolean,\n fromServiceWorker: boolean,\n mimeType: string,\n requestId: string,\n responseTime: MilliSeconds,\n statusCode: number,\n timing: TraceEventResourceReceiveResponseTimingData,\n },\n };\n}\n\nexport interface TraceEventResourceMarkAsCached extends TraceEventInstant {\n name: 'ResourceMarkAsCached';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n requestId: string,\n },\n };\n}\n\nexport const enum LayoutInvalidationReason {\n SIZE_CHANGED = 'Size changed',\n ATTRIBUTE = 'Attribute',\n ADDED_TO_LAYOUT = 'Added to layout',\n SCROLLBAR_CHANGED = 'Scrollbar changed',\n REMOVED_FROM_LAYOUT = 'Removed from layout',\n STYLE_CHANGED = 'Style changed',\n FONTS_CHANGED = 'Fonts changed',\n UNKNOWN = 'Unknown',\n}\n\nexport interface TraceEventLayoutInvalidation extends TraceEventInstant {\n name: 'LayoutInvalidationTracking'|'ScheduleStyleInvalidationTracking';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n nodeId: Protocol.DOM.BackendNodeId,\n reason: LayoutInvalidationReason,\n nodeName?: string,\n },\n };\n}\n\nexport const enum StyleRecalcInvalidationReason {\n ANIMATION = 'Animation',\n}\n\nexport interface TraceEventStyleRecalcInvalidation extends TraceEventInstant {\n name: 'StyleRecalcInvalidationTracking';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n nodeId: Protocol.DOM.BackendNodeId,\n reason: StyleRecalcInvalidationReason,\n subtree: boolean,\n nodeName?: string,\n extraData?: string,\n },\n };\n}\n\nexport interface TraceEventPrePaint extends TraceEventComplete {\n name: 'PrePaint';\n}\n\nexport type TraceEventNestableAsync = TraceEventNestableAsyncBegin|TraceEventNestableAsyncEnd;\nexport interface TraceEventNestableAsyncBegin extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_START;\n // The id2 field gives flexibility to explicitly specify if an event\n // id is global among processes or process local. However not all\n // events use it, so both kind of ids need to be marked as optional.\n id2?: {local?: string, global?: string};\n id?: string;\n}\n\nexport interface TraceEventNestableAsyncEnd extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_END;\n id2?: {local?: string, global?: string};\n id?: string;\n}\n\nexport type TraceEventAsyncPerformanceMeasure = TraceEventPerformanceMeasureBegin|TraceEventPerformanceMeasureEnd;\n\nexport interface TraceEventPerformanceMeasureBegin extends TraceEventNestableAsyncBegin {\n cat: 'blink.user_timing';\n id: string;\n}\n\nexport interface TraceEventPerformanceMeasureEnd extends TraceEventNestableAsyncEnd {\n cat: 'blink.user_timing';\n id: string;\n}\n\nexport interface TraceEventConsoleTimeBegin extends TraceEventNestableAsyncBegin {\n cat: 'blink.console';\n id2: {\n local: string,\n };\n}\n\nexport interface TraceEventConsoleTimeEnd extends TraceEventNestableAsyncEnd {\n cat: 'blink.console';\n id2: {\n local: string,\n };\n}\n\nexport interface TraceEventTimeStamp extends TraceEventData {\n cat: 'devtools.timeline';\n name: 'TimeStamp';\n ph: Phase.INSTANT;\n id: string;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n message: string,\n },\n };\n}\n\nexport interface TraceEventPerformanceMark extends TraceEventData {\n cat: 'blink.user_timing';\n ph: Phase.INSTANT|Phase.MARK;\n id: string;\n}\n\n// Nestable async events with a duration are made up of two distinct\n// events: the begin, and the end. We need both of them to be able to\n// display the right information, so we create these synthetic events.\nexport interface TraceEventSyntheticNestableAsyncEvent extends TraceEventData {\n id?: string;\n id2?: {local?: string, global?: string};\n dur: MicroSeconds;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n beginEvent: TraceEventNestableAsyncBegin,\n endEvent: TraceEventNestableAsyncEnd,\n },\n };\n}\n\nexport interface TraceEventSyntheticUserTiming extends TraceEventSyntheticNestableAsyncEvent {\n id: string;\n dur: MicroSeconds;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n beginEvent: TraceEventPerformanceMeasureBegin,\n endEvent: TraceEventPerformanceMeasureEnd,\n },\n };\n}\n\nexport interface TraceEventSyntheticConsoleTiming extends TraceEventSyntheticNestableAsyncEvent {\n id2: {local: string};\n dur: MicroSeconds;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n beginEvent: TraceEventConsoleTimeBegin,\n endEvent: TraceEventConsoleTimeEnd,\n },\n };\n}\n\nexport interface SyntheticInteractionEvent extends TraceEventSyntheticNestableAsyncEvent {\n // InteractionID and type are available within the beginEvent's data, but we\n // put them on the top level for ease of access.\n interactionId: number;\n type: string;\n // This is equivalent to startEvent.ts;\n ts: MicroSeconds;\n // This duration can be calculated via endEvent.ts - startEvent.ts, but we do\n // that and put it here to make it easier. This also makes these events\n // consistent with real events that have a dur field.\n dur: MicroSeconds;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n beginEvent: TraceEventEventTimingBegin,\n endEvent: TraceEventEventTimingEnd,\n },\n };\n}\n\n/**\n * An event created synthetically in the frontend that has a self time\n * (the time spent running the task itself).\n */\nexport interface SyntheticEventWithSelfTime extends TraceEventData {\n selfTime?: MicroSeconds;\n}\n\n/**\n * A profile call created in the frontend from samples disguised as a\n * trace event.\n */\nexport interface TraceEventSyntheticProfileCall extends SyntheticEventWithSelfTime {\n callFrame: Protocol.Runtime.CallFrame;\n nodeId: Protocol.integer;\n children?: TraceEventSyntheticProfileCall[];\n}\n\n/**\n * A trace event augmented synthetically in the frontend to contain\n * its self time.\n */\nexport type SyntheticRendererEvent = TraceEventRendererEvent&SyntheticEventWithSelfTime;\n\nexport type RendererEntry = SyntheticRendererEvent|TraceEventSyntheticProfileCall;\n\nexport function isSyntheticInteractionEvent(event: TraceEventData): event is SyntheticInteractionEvent {\n return Boolean(\n 'interactionId' in event && event.args?.data && 'beginEvent' in event.args.data && 'endEvent' in event.args.data);\n}\n\nexport function isRendererEvent(event: TraceEventData): event is RendererEntry {\n return isTraceEventRendererEvent(event) || isProfileCall(event);\n}\n\nclass ProfileIdTag {\n readonly #profileIdTag: (symbol|undefined);\n}\nexport type ProfileID = string&ProfileIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function ProfileID(value: string): ProfileID {\n return value as ProfileID;\n}\n\nclass CallFrameIdTag {\n readonly #callFrameIdTag: (symbol|undefined);\n}\nexport type CallFrameID = number&CallFrameIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function CallFrameID(value: number): CallFrameID {\n return value as CallFrameID;\n}\n\nclass ProcessIdTag {\n readonly #processIdTag: (symbol|undefined);\n}\nexport type ProcessID = number&ProcessIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function ProcessID(value: number): ProcessID {\n return value as ProcessID;\n}\n\nclass ThreadIdTag {\n readonly #threadIdTag: (symbol|undefined);\n}\nexport type ThreadID = number&ThreadIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function ThreadID(value: number): ThreadID {\n return value as ThreadID;\n}\n\nclass WorkerIdTag {\n readonly #workerIdTag: (symbol|undefined);\n}\nexport type WorkerId = string&WorkerIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function WorkerId(value: string): WorkerId {\n return value as WorkerId;\n}\n\nexport function isTraceEventComplete(event: TraceEventData): event is TraceEventComplete {\n return event.ph === Phase.COMPLETE;\n}\n\nexport function isTraceEventBegin(event: TraceEventData): event is TraceEventBegin {\n return event.ph === Phase.BEGIN;\n}\n\nexport function isTraceEventEnd(event: TraceEventData): event is TraceEventEnd {\n return event.ph === Phase.END;\n}\n\nexport function isTraceEventDispatch(event: TraceEventData): event is TraceEventDispatch {\n return event.name === 'EventDispatch';\n}\n\nexport function isTraceEventInstant(event: TraceEventData): event is TraceEventInstant {\n return event.ph === Phase.INSTANT;\n}\n\nexport function isTraceEventRendererEvent(event: TraceEventData): event is TraceEventRendererEvent {\n return isTraceEventInstant(event) || isTraceEventComplete(event);\n}\n\nexport function isTraceEventFireIdleCallback(event: TraceEventData): event is TraceEventFireIdleCallback {\n return event.name === 'FireIdleCallback';\n}\n\nexport function isTraceEventUpdateCounters(event: TraceEventData): event is TraceEventUpdateCounters {\n return event.name === 'UpdateCounters';\n}\n\nexport function isThreadName(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventThreadName {\n return traceEventData.name === 'thread_name';\n}\n\nexport function isProcessName(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventProcessName {\n return traceEventData.name === 'process_name';\n}\n\nexport function isTraceEventTracingStartedInBrowser(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventTracingStartedInBrowser {\n return traceEventData.name === 'TracingStartedInBrowser';\n}\n\nexport function isTraceEventFrameCommittedInBrowser(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventFrameCommittedInBrowser {\n return traceEventData.name === 'FrameCommittedInBrowser';\n}\n\nexport function isTraceEventCommitLoad(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventCommitLoad {\n return traceEventData.name === 'CommitLoad';\n}\n\nexport function isTraceEventNavigationStart(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventNavigationStart {\n return traceEventData.name === 'navigationStart';\n}\n\nexport function isTraceEventAnimation(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventAnimation {\n return traceEventData.name === 'Animation';\n}\n\nexport function isTraceEventLayoutShift(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventLayoutShift {\n return traceEventData.name === 'LayoutShift';\n}\n\nexport function isTraceEventLayoutInvalidation(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventLayoutInvalidation {\n return traceEventData.name === 'LayoutInvalidationTracking' ||\n traceEventData.name === 'ScheduleStyleInvalidationTracking';\n}\n\nexport function isTraceEventStyleRecalcInvalidation(traceEventData: TraceEventData):\n traceEventData is TraceEventStyleRecalcInvalidation {\n return traceEventData.name === 'StyleRecalcInvalidationTracking';\n}\n\nexport function isTraceEventFirstContentfulPaint(traceEventData: TraceEventData):\n traceEventData is TraceEventFirstContentfulPaint {\n return traceEventData.name === 'firstContentfulPaint';\n}\n\nexport function isTraceEventLargestContentfulPaintCandidate(traceEventData: TraceEventData):\n traceEventData is TraceEventLargestContentfulPaintCandidate {\n return traceEventData.name === 'largestContentfulPaint::Candidate';\n}\nexport function isTraceEventLargestImagePaintCandidate(traceEventData: TraceEventData):\n traceEventData is TraceEventLargestImagePaintCandidate {\n return traceEventData.name === 'LargestImagePaint::Candidate';\n}\nexport function isTraceEventLargestTextPaintCandidate(traceEventData: TraceEventData):\n traceEventData is TraceEventLargestTextPaintCandidate {\n return traceEventData.name === 'LargestTextPaint::Candidate';\n}\n\nexport function isTraceEventMarkLoad(traceEventData: TraceEventData): traceEventData is TraceEventMarkLoad {\n return traceEventData.name === 'MarkLoad';\n}\n\nexport function isTraceEventFirstPaint(traceEventData: TraceEventData): traceEventData is TraceEventFirstPaint {\n return traceEventData.name === 'firstPaint';\n}\n\nexport function isTraceEventMarkDOMContent(traceEventData: TraceEventData): traceEventData is TraceEventMarkDOMContent {\n return traceEventData.name === 'MarkDOMContent';\n}\n\nexport function isTraceEventInteractiveTime(traceEventData: TraceEventData):\n traceEventData is TraceEventInteractiveTime {\n return traceEventData.name === 'InteractiveTime';\n}\n\nexport function isTraceEventEventTiming(traceEventData: TraceEventData): traceEventData is TraceEventEventTiming {\n return traceEventData.name === KnownEventName.EventTiming;\n}\n\nexport function isTraceEventEventTimingEnd(traceEventData: TraceEventData): traceEventData is TraceEventEventTimingEnd {\n return isTraceEventEventTiming(traceEventData) && traceEventData.ph === Phase.ASYNC_NESTABLE_END;\n}\nexport function isTraceEventEventTimingStart(traceEventData: TraceEventData):\n traceEventData is TraceEventEventTimingBegin {\n return isTraceEventEventTiming(traceEventData) && traceEventData.ph === Phase.ASYNC_NESTABLE_START;\n}\n\nexport function isTraceEventGPUTask(traceEventData: TraceEventData): traceEventData is TraceEventGPUTask {\n return traceEventData.name === 'GPUTask';\n}\n\nexport function isTraceEventProfile(traceEventData: TraceEventData): traceEventData is TraceEventProfile {\n return traceEventData.name === 'Profile';\n}\n\nexport function isTraceEventProfileChunk(traceEventData: TraceEventData): traceEventData is TraceEventProfileChunk {\n return traceEventData.name === 'ProfileChunk';\n}\n\nexport function isTraceEventResourceChangePriority(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceChangePriority {\n return traceEventData.name === 'ResourceChangePriority';\n}\n\nexport function isTraceEventResourceSendRequest(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceSendRequest {\n return traceEventData.name === 'ResourceSendRequest';\n}\n\nexport function isTraceEventResourceReceiveResponse(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceReceiveResponse {\n return traceEventData.name === 'ResourceReceiveResponse';\n}\n\nexport function isTraceEventResourceMarkAsCached(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceMarkAsCached {\n return traceEventData.name === 'ResourceMarkAsCached';\n}\n\nexport function isTraceEventResourceFinish(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceFinish {\n return traceEventData.name === 'ResourceFinish';\n}\n\nexport function isTraceEventResourceWillSendRequest(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceWillSendRequest {\n return traceEventData.name === 'ResourceWillSendRequest';\n}\n\nexport function isTraceEventResourceReceivedData(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceReceivedData {\n return traceEventData.name === 'ResourceReceivedData';\n}\n\nexport function isSyntheticNetworkRequestDetailsEvent(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventSyntheticNetworkRequest {\n return traceEventData.name === 'SyntheticNetworkRequest';\n}\n\nexport function isTraceEventPrePaint(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventPrePaint {\n return traceEventData.name === 'PrePaint';\n}\n\nexport function isTraceEventNavigationStartWithURL(event: TraceEventData): event is TraceEventNavigationStart {\n return Boolean(isTraceEventNavigationStart(event) && event.args.data && event.args.data.documentLoaderURL !== '');\n}\n\nexport function isTraceEventMainFrameViewport(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventMainFrameViewport {\n return traceEventData.name === 'PaintTimingVisualizer::Viewport';\n}\n\nexport function isSyntheticUserTimingTraceEvent(traceEventData: TraceEventData):\n traceEventData is TraceEventSyntheticUserTiming {\n if (traceEventData.cat !== 'blink.user_timing') {\n return false;\n }\n const data = traceEventData.args?.data;\n if (!data) {\n return false;\n }\n return 'beginEvent' in data && 'endEvent' in data;\n}\n\nexport function isSyntheticConsoleTimingTraceEvent(traceEventData: TraceEventData):\n traceEventData is TraceEventSyntheticConsoleTiming {\n if (traceEventData.cat !== 'blink.console') {\n return false;\n }\n const data = traceEventData.args?.data;\n if (!data) {\n return false;\n }\n return 'beginEvent' in data && 'endEvent' in data;\n}\n\nexport function isTraceEventPerformanceMeasure(traceEventData: TraceEventData):\n traceEventData is TraceEventPerformanceMeasureBegin|TraceEventPerformanceMeasureEnd {\n return traceEventData.cat === 'blink.user_timing' && isTraceEventAsyncPhase(traceEventData);\n}\n\nexport function isTraceEventPerformanceMark(traceEventData: TraceEventData):\n traceEventData is TraceEventPerformanceMark {\n return traceEventData.cat === 'blink.user_timing' &&\n (traceEventData.ph === Phase.MARK || traceEventData.ph === Phase.INSTANT);\n}\n\nexport function isTraceEventConsoleTime(traceEventData: TraceEventData): traceEventData is TraceEventConsoleTimeBegin|\n TraceEventConsoleTimeEnd {\n return traceEventData.cat === 'blink.console' && isTraceEventAsyncPhase(traceEventData);\n}\n\nexport function isTraceEventTimeStamp(traceEventData: TraceEventData): traceEventData is TraceEventTimeStamp {\n return traceEventData.ph === Phase.INSTANT && traceEventData.name === 'TimeStamp';\n}\n\nexport function isTraceEventParseHTML(traceEventData: TraceEventData): traceEventData is TraceEventParseHTML {\n return traceEventData.name === 'ParseHTML';\n}\n\nexport interface TraceEventAsync extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_START|Phase.ASYNC_NESTABLE_INSTANT|Phase.ASYNC_NESTABLE_END|Phase.ASYNC_STEP_INTO|\n Phase.ASYNC_BEGIN|Phase.ASYNC_END|Phase.ASYNC_STEP_PAST;\n}\n\nexport function isTraceEventAsyncPhase(traceEventData: TraceEventData): boolean {\n const asyncPhases = new Set([\n Phase.ASYNC_NESTABLE_START,\n Phase.ASYNC_NESTABLE_INSTANT,\n Phase.ASYNC_NESTABLE_END,\n Phase.ASYNC_STEP_INTO,\n Phase.ASYNC_BEGIN,\n Phase.ASYNC_END,\n Phase.ASYNC_STEP_PAST,\n ]);\n return asyncPhases.has(traceEventData.ph);\n}\n\nexport function isSyntheticLayoutShift(traceEventData: TraceEventData): traceEventData is SyntheticLayoutShift {\n if (!isTraceEventLayoutShift(traceEventData) || !traceEventData.args.data) {\n return false;\n }\n return 'rawEvent' in traceEventData.args.data;\n}\n\nexport function isProfileCall(event: TraceEventData): event is TraceEventSyntheticProfileCall {\n return 'callFrame' in event;\n}\n\n/**\n * This is an exhaustive list of events we track in the Performance\n * panel. Note not all of them are necessarliry shown in the flame\n * chart, some of them we only use for parsing.\n * TODO(crbug.com/1428024): Complete this enum.\n */\nexport const enum KnownEventName {\n /* Task */\n Program = 'Program',\n RunTask = 'RunTask',\n AsyncTask = 'AsyncTask',\n RunMicrotasks = 'RunMicrotasks',\n\n /* Load */\n XHRLoad = 'XHRLoad',\n XHRReadyStateChange = 'XHRReadyStateChange',\n /* Parse */\n ParseHTML = 'ParseHTML',\n ParseCSS = 'ParseAuthorStyleSheet',\n /* V8 */\n CompileScript = 'V8.CompileScript',\n CompileCode = 'V8.CompileCode',\n CompileModule = 'V8.CompileModule',\n Optimize = 'V8.OptimizeCode',\n WasmStreamFromResponseCallback = 'v8.wasm.streamFromResponseCallback',\n WasmCompiledModule = 'v8.wasm.compiledModule',\n WasmCachedModule = 'v8.wasm.cachedModule',\n WasmModuleCacheHit = 'v8.wasm.moduleCacheHit',\n WasmModuleCacheInvalid = 'v8.wasm.moduleCacheInvalid',\n /* Js */\n ProfileCall = 'ProfileCall',\n EvaluateScript = 'EvaluateScript',\n FunctionCall = 'FunctionCall',\n EventDispatch = 'EventDispatch',\n EvaluateModule = 'v8.evaluateModule',\n RequestMainThreadFrame = 'RequestMainThreadFrame',\n RequestAnimationFrame = 'RequestAnimationFrame',\n CancelAnimationFrame = 'CancelAnimationFrame',\n FireAnimationFrame = 'FireAnimationFrame',\n RequestIdleCallback = 'RequestIdleCallback',\n CancelIdleCallback = 'CancelIdleCallback',\n FireIdleCallback = 'FireIdleCallback',\n TimerInstall = 'TimerInstall',\n TimerRemove = 'TimerRemove',\n TimerFire = 'TimerFire',\n WebSocketCreate = 'WebSocketCreate',\n WebSocketSendHandshake = 'WebSocketSendHandshakeRequest',\n WebSocketReceiveHandshake = 'WebSocketReceiveHandshakeResponse',\n WebSocketDestroy = 'WebSocketDestroy',\n CryptoDoEncrypt = 'DoEncrypt',\n CryptoDoEncryptReply = 'DoEncryptReply',\n CryptoDoDecrypt = 'DoDecrypt',\n CryptoDoDecryptReply = 'DoDecryptReply',\n CryptoDoDigest = 'DoDigest',\n CryptoDoDigestReply = 'DoDigestReply',\n CryptoDoSign = 'DoSign',\n CryptoDoSignReply = 'DoSignReply',\n CryptoDoVerify = 'DoVerify',\n CryptoDoVerifyReply = 'DoVerifyReply',\n V8Execute = 'V8.Execute',\n\n /* Gc */\n GC = 'GCEvent',\n DOMGC = 'BlinkGC.AtomicPhase',\n IncrementalGCMarking = 'V8.GCIncrementalMarking',\n MajorGC = 'MajorGC',\n MinorGC = 'MinorGC',\n GCCollectGarbage = 'BlinkGC.AtomicPhase',\n\n /* Layout */\n ScheduleStyleRecalculation = 'ScheduleStyleRecalculation',\n RecalculateStyles = 'RecalculateStyles',\n Layout = 'Layout',\n UpdateLayoutTree = 'UpdateLayoutTree',\n InvalidateLayout = 'InvalidateLayout',\n LayoutInvalidationTracking = 'LayoutInvalidationTracking',\n ComputeIntersections = 'ComputeIntersections',\n HitTest = 'HitTest',\n PrePaint = 'PrePaint',\n Layerize = 'Layerize',\n LayoutShift = 'LayoutShift',\n UpdateLayerTree = 'UpdateLayerTree',\n ScheduleStyleInvalidationTracking = 'ScheduleStyleInvalidationTracking',\n StyleRecalcInvalidationTracking = 'StyleRecalcInvalidationTracking',\n StyleInvalidatorInvalidationTracking = 'StyleInvalidatorInvalidationTracking',\n\n /* Paint */\n ScrollLayer = 'ScrollLayer',\n UpdateLayer = 'UpdateLayer',\n PaintSetup = 'PaintSetup',\n Paint = 'Paint',\n PaintImage = 'PaintImage',\n Commit = 'Commit',\n CompositeLayers = 'CompositeLayers',\n RasterTask = 'RasterTask',\n ImageDecodeTask = 'ImageDecodeTask',\n ImageUploadTask = 'ImageUploadTask',\n DecodeImage = 'Decode Image',\n ResizeImage = 'Resize Image',\n DrawLazyPixelRef = 'Draw LazyPixelRef',\n DecodeLazyPixelRef = 'Decode LazyPixelRef',\n GPUTask = 'GPUTask',\n Rasterize = 'Rasterize',\n EventTiming = 'EventTiming',\n\n /* Compile */\n OptimizeCode = 'V8.OptimizeCode',\n CacheScript = 'v8.produceCache',\n CacheModule = 'v8.produceModuleCache',\n // V8Sample events are coming from tracing and contain raw stacks with function addresses.\n // After being processed with help of JitCodeAdded and JitCodeMoved events they\n // get translated into function infos and stored as stacks in JSSample events.\n V8Sample = 'V8Sample',\n JitCodeAdded = 'JitCodeAdded',\n JitCodeMoved = 'JitCodeMoved',\n StreamingCompileScript = 'v8.parseOnBackground',\n StreamingCompileScriptWaiting = 'v8.parseOnBackgroundWaiting',\n StreamingCompileScriptParsing = 'v8.parseOnBackgroundParsing',\n BackgroundDeserialize = 'v8.deserializeOnBackground',\n FinalizeDeserialization = 'V8.FinalizeDeserialization',\n\n /* Markers */\n CommitLoad = 'CommitLoad',\n MarkLoad = 'MarkLoad',\n MarkDOMContent = 'MarkDOMContent',\n MarkFirstPaint = 'firstPaint',\n MarkFCP = 'firstContentfulPaint',\n MarkLCPCandidate = 'largestContentfulPaint::Candidate',\n MarkLCPInvalidate = 'largestContentfulPaint::Invalidate',\n NavigationStart = 'navigationStart',\n TimeStamp = 'TimeStamp',\n ConsoleTime = 'ConsoleTime',\n UserTiming = 'UserTiming',\n InteractiveTime = 'InteractiveTime',\n\n /* Frames */\n BeginFrame = 'BeginFrame',\n NeedsBeginFrameChanged = 'NeedsBeginFrameChanged',\n BeginMainThreadFrame = 'BeginMainThreadFrame',\n ActivateLayerTree = 'ActivateLayerTree',\n DrawFrame = 'DrawFrame',\n DroppedFrame = 'DroppedFrame',\n FrameStartedLoading = 'FrameStartedLoading',\n\n /* Network request events */\n ResourceWillSendRequest = 'ResourceWillSendRequest',\n ResourceSendRequest = 'ResourceSendRequest',\n ResourceReceiveResponse = 'ResourceReceiveResponse',\n ResourceReceivedData = 'ResourceReceivedData',\n ResourceFinish = 'ResourceFinish',\n ResourceMarkAsCached = 'ResourceMarkAsCached',\n\n /* Web sockets */\n WebSocketSendHandshakeRequest = 'WebSocketSendHandshakeRequest',\n WebSocketReceiveHandshakeResponse = 'WebSocketReceiveHandshakeResponse',\n\n /* CPU Profiling */\n Profile = 'Profile',\n StartProfiling = 'CpuProfiler::StartProfiling',\n ProfileChunk = 'ProfileChunk',\n UpdateCounters = 'UpdateCounters',\n\n /* Other */\n Animation = 'Animation',\n ParseAuthorStyleSheet = 'ParseAuthorStyleSheet',\n EmbedderCallback = 'EmbedderCallback',\n SetLayerTreeId = 'SetLayerTreeId',\n TracingStartedInPage = 'TracingStartedInPage',\n TracingSessionIdForWorker = 'TracingSessionIdForWorker',\n LazyPixelRef = 'LazyPixelRef',\n LayerTreeHostImplSnapshot = 'cc::LayerTreeHostImpl',\n PictureSnapshot = 'cc::Picture',\n DisplayItemListSnapshot = 'cc::DisplayItemList',\n InputLatencyMouseMove = 'InputLatency::MouseMove',\n InputLatencyMouseWheel = 'InputLatency::MouseWheel',\n ImplSideFling = 'InputHandlerProxy::HandleGestureFling::started',\n}\n", "\n// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\nimport type * as Types from './../types/types.js';\nimport type * as ModelHandlers from './ModelHandlers.js';\n\nexport interface TraceEventHandler {\n reset(): void;\n initialize?(freshRecording?: boolean): void;\n handleEvent(data: {}): void;\n finalize?(): Promise<void>;\n data(): unknown;\n deps?(): TraceEventHandlerName[];\n handleUserConfig?(config: Types.Configuration.Configuration): void;\n}\nexport type TraceEventHandlerName = keyof typeof ModelHandlers;\n\n// This type maps TraceEventHandler names to the return type of their data\n// function. So, for example, if we are given an object with a key of 'foo'\n// and a value which is a TraceHandler containing a data() function that\n// returns a string, this type will be { foo: string }.\n//\n// This allows us to model the behavior of the TraceProcessor in the model,\n// which takes an object with TraceEventHandlers as part of its config, and\n// which ultimately returns an object keyed off the names of the\n// TraceEventHandlers, and with values that are derived from each\n// TraceEventHandler's data function.\n//\n// So, concretely, we provide a TraceEventHandler for calculating the #time\n// bounds of a trace called TraceBounds, whose data() function returns a\n// TraceWindow. The HandlerData, therefore, would determine that the\n// TraceProcessor would contain a key called 'TraceBounds' whose value is\n// a TraceWindow.\nexport type EnabledHandlerDataWithMeta<T extends {[key: string]: TraceEventHandler}> = {\n // We allow the user to configure which handlers are created by passing them\n // in when constructing a model instance. However, we then ensure that the\n // Meta handler is added to that, as the Model relies on some of the data\n // from the Meta handler when creating the file. Therefore, this type\n // explicitly defines that the Meta data is present, before then extending it\n // with the index type to represent all the other handlers.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Meta: Readonly<ReturnType<typeof ModelHandlers['Meta']['data']>>,\n}&{\n // For every key in the object, look up the TraceEventHandler's data function\n // and use its return type as the value for the object.\n [K in keyof T]: Readonly<ReturnType<T[K]['data']>>;\n};\n\nexport type HandlersWithMeta<T extends {[key: string]: TraceEventHandler}> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Meta: typeof ModelHandlers.Meta,\n}&{\n [K in keyof T]: T[K];\n};\n\n// Represents the final parsed data from all of the handlers. Note that because\n// we are currently in the middle of the migration of data engines, not all the\n// handlers are enabled. Therefore for now you should use the type defined in\n// models/trace/handlers/Migration.ts, `PartialTraceData`, which\n// represents the final parsed data for only the enabled handlers.\nexport type TraceParseData = Readonly<EnabledHandlerDataWithMeta<typeof ModelHandlers>>;\n\nexport type Handlers = typeof ModelHandlers;\n\nexport const enum HandlerState {\n UNINITIALIZED = 1,\n INITIALIZED = 2,\n FINALIZED = 3,\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport {data as metaHandlerData} from './MetaHandler.js';\n\nimport {type TraceEventHandlerName, HandlerState} from './types.js';\n\nimport * as Types from '../types/types.js';\nimport * as Helpers from '../helpers/helpers.js';\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\n// Each thread contains events. Events indicate the thread and process IDs, which are\n// used to store the event in the correct process thread entry below.\nconst eventsInProcessThread =\n new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventGPUTask[]>>();\n\nlet mainGPUThreadTasks: Types.TraceEvents.TraceEventGPUTask[] = [];\n\nexport function reset(): void {\n eventsInProcessThread.clear();\n mainGPUThreadTasks = [];\n\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('GPU Handler was not reset before being initialized');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('GPU Handler is not initialized');\n }\n\n if (!Types.TraceEvents.isTraceEventGPUTask(event)) {\n return;\n }\n\n Helpers.Trace.addEventToProcessThread(event, eventsInProcessThread);\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('GPU Handler is not initialized');\n }\n\n const {gpuProcessId, gpuThreadId} = metaHandlerData();\n const gpuThreadsForProcess = eventsInProcessThread.get(gpuProcessId);\n if (gpuThreadsForProcess && gpuThreadId) {\n mainGPUThreadTasks = gpuThreadsForProcess.get(gpuThreadId) || [];\n }\n handlerState = HandlerState.FINALIZED;\n}\n\nexport interface GPUHandlerReturnData {\n mainGPUThreadTasks: readonly Types.TraceEvents.TraceEventGPUTask[];\n}\n\nexport function data(): GPUHandlerReturnData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('GPU Handler is not finalized');\n }\n return {\n mainGPUThreadTasks: [...mainGPUThreadTasks],\n };\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta'];\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\n// We track the renderer processes we see in each frame on the way through the trace.\nconst rendererProcessesByFrameId = new Map<\n string,\n Map<Types.TraceEvents.ProcessID, {window: Types.Timing.TraceWindow, frame: Types.TraceEvents.TraceFrame}[]>>();\n\n// We will often want to key data by Frame IDs, and commonly we'll care most\n// about the main frame's ID, so we store and expose that.\nlet mainFrameId: string = '';\nlet mainFrameURL: string = '';\n\nconst framesByProcessId = new Map<Types.TraceEvents.ProcessID, Map<string, Types.TraceEvents.TraceFrame>>();\n\n// We will often want to key data by the browser process, GPU process and top\n// level renderer IDs, so keep a track on those.\nlet browserProcessId: Types.TraceEvents.ProcessID = Types.TraceEvents.ProcessID(-1);\nlet browserThreadId: Types.TraceEvents.ThreadID = Types.TraceEvents.ThreadID(-1);\nlet gpuProcessId: Types.TraceEvents.ProcessID = Types.TraceEvents.ProcessID(-1);\nlet gpuThreadId: Types.TraceEvents.ThreadID = Types.TraceEvents.ThreadID(-1);\nlet viewportRect: DOMRect|null = null;\n\nconst topLevelRendererIds = new Set<Types.TraceEvents.ProcessID>();\nconst traceBounds: Types.Timing.TraceWindow = {\n min: Types.Timing.MicroSeconds(Number.POSITIVE_INFINITY),\n max: Types.Timing.MicroSeconds(Number.NEGATIVE_INFINITY),\n range: Types.Timing.MicroSeconds(Number.POSITIVE_INFINITY),\n};\n\n/**\n * These represent the user navigating. Values such as First Contentful Paint,\n * etc, are relative to the navigation.\n *\n * We store navigation events both by the frame and navigation ID. This means\n * when we need to look them up, we can use whichever ID we have.\n *\n * Note that these Maps will have the same values in them; these are just keyed\n * differently to make look-ups easier.\n *\n * We also additionally maintain an array of only navigations that occured on\n * the main frame. In many places in the UI we only care about highlighting\n * main frame navigations, so calculating this list here is better than\n * filtering either of the below maps over and over again at the UI layer.\n */\nconst navigationsByFrameId = new Map<string, Types.TraceEvents.TraceEventNavigationStart[]>();\nconst navigationsByNavigationId = new Map<string, Types.TraceEvents.TraceEventNavigationStart>();\nconst mainFrameNavigations: Types.TraceEvents.TraceEventNavigationStart[] = [];\n\n// Represents all the threads in the trace, organized by process. This is mostly for internal\n// bookkeeping so that during the finalize pass we can obtain the main and browser thread IDs.\nconst threadsInProcess =\n new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventThreadName>>();\n\nlet traceStartedTimeFromTracingStartedEvent = Types.Timing.MicroSeconds(-1);\nconst eventPhasesOfInterestForTraceBounds = new Set([\n Types.TraceEvents.Phase.BEGIN,\n Types.TraceEvents.Phase.END,\n Types.TraceEvents.Phase.COMPLETE,\n Types.TraceEvents.Phase.INSTANT,\n]);\n\nlet handlerState = HandlerState.UNINITIALIZED;\nexport function reset(): void {\n navigationsByFrameId.clear();\n navigationsByNavigationId.clear();\n mainFrameNavigations.length = 0;\n\n browserProcessId = Types.TraceEvents.ProcessID(-1);\n browserThreadId = Types.TraceEvents.ThreadID(-1);\n gpuProcessId = Types.TraceEvents.ProcessID(-1);\n gpuThreadId = Types.TraceEvents.ThreadID(-1);\n viewportRect = null;\n topLevelRendererIds.clear();\n threadsInProcess.clear();\n rendererProcessesByFrameId.clear();\n framesByProcessId.clear();\n\n traceBounds.min = Types.Timing.MicroSeconds(Number.POSITIVE_INFINITY);\n traceBounds.max = Types.Timing.MicroSeconds(Number.NEGATIVE_INFINITY);\n traceBounds.range = Types.Timing.MicroSeconds(Number.POSITIVE_INFINITY);\n traceStartedTimeFromTracingStartedEvent = Types.Timing.MicroSeconds(-1);\n\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('Meta Handler was not reset');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nfunction updateRendererProcessByFrame(\n event: Types.TraceEvents.TraceEventData, frame: Types.TraceEvents.TraceFrame): void {\n const framesInProcessById = Platform.MapUtilities.getWithDefault(framesByProcessId, frame.processId, () => new Map());\n framesInProcessById.set(frame.frame, frame);\n\n const rendererProcessInFrame = Platform.MapUtilities.getWithDefault(\n rendererProcessesByFrameId, frame.frame,\n () => new Map<\n Types.TraceEvents.ProcessID, {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindow}[]>());\n const rendererProcessInfo = Platform.MapUtilities.getWithDefault(rendererProcessInFrame, frame.processId, () => {\n return [];\n });\n const lastProcessData = rendererProcessInfo.at(-1);\n\n // Only store a new entry if the URL changed, otherwise it's just\n // redundant information.\n if (lastProcessData && lastProcessData.frame.url === frame.url) {\n return;\n }\n // For now we store the time of the event as the min. In the finalize we step\n // through each of these windows and update their max and range values.\n rendererProcessInfo.push({\n frame,\n window: {\n min: event.ts,\n max: Types.Timing.MicroSeconds(0),\n range: Types.Timing.MicroSeconds(0),\n },\n });\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Meta Handler is not initialized');\n }\n\n // If there is a timestamp (which meta events do not have), and the event does\n // not end with ::UMA then it, and the event is in the set of valid phases,\n // then it should be included for the purposes of calculating the trace bounds.\n // The UMA events in particular seem to be reported on page unloading, which\n // often extends the bounds of the trace unhelpfully.\n if (event.ts !== 0 && !event.name.endsWith('::UMA') && eventPhasesOfInterestForTraceBounds.has(event.ph)) {\n traceBounds.min = Types.Timing.MicroSeconds(Math.min(event.ts, traceBounds.min));\n const eventDuration = event.dur || Types.Timing.MicroSeconds(0);\n traceBounds.max = Types.Timing.MicroSeconds(Math.max(event.ts + eventDuration, traceBounds.max));\n }\n\n if (Types.TraceEvents.isProcessName(event) &&\n (event.args.name === 'Browser' || event.args.name === 'HeadlessBrowser')) {\n browserProcessId = event.pid;\n return;\n }\n\n if (Types.TraceEvents.isProcessName(event) && (event.args.name === 'Gpu' || event.args.name === 'GPU Process')) {\n gpuProcessId = event.pid;\n return;\n }\n\n if (Types.TraceEvents.isThreadName(event) && event.args.name === 'CrGpuMain') {\n gpuThreadId = event.tid;\n return;\n }\n\n if (Types.TraceEvents.isThreadName(event) && event.args.name === 'CrBrowserMain') {\n browserThreadId = event.tid;\n }\n\n if (Types.TraceEvents.isTraceEventMainFrameViewport(event) && viewportRect === null) {\n const rectAsArray = event.args.data.viewport_rect;\n const viewportX = rectAsArray[0];\n const viewportY = rectAsArray[1];\n const viewportWidth = rectAsArray[2];\n const viewportHeight = rectAsArray[5];\n viewportRect = new DOMRect(viewportX, viewportY, viewportWidth, viewportHeight);\n }\n\n // The TracingStartedInBrowser event includes the data on which frames are\n // in scope at the start of the trace. We use this to identify the frame with\n // no parent, i.e. the top level frame.\n if (Types.TraceEvents.isTraceEventTracingStartedInBrowser(event)) {\n traceStartedTimeFromTracingStartedEvent = event.ts;\n\n if (!event.args.data) {\n throw new Error('No frames found in trace data');\n }\n\n for (const frame of (event.args.data.frames ?? [])) {\n updateRendererProcessByFrame(event, frame);\n\n if (frame.parent) {\n continue;\n }\n\n mainFrameId = frame.frame;\n mainFrameURL = frame.url;\n topLevelRendererIds.add(frame.processId);\n }\n return;\n }\n\n // FrameCommittedInBrowser events tell us information about each frame\n // and we use these to track how long each individual renderer is active\n // for. We track all renderers here (top level and those in frames), but\n // for convenience we also populate a set of top level renderer IDs.\n if (Types.TraceEvents.isTraceEventFrameCommittedInBrowser(event)) {\n const frame = event.args.data;\n if (!frame) {\n return;\n }\n\n updateRendererProcessByFrame(event, frame);\n\n if (frame.parent) {\n return;\n }\n\n topLevelRendererIds.add(frame.processId);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventCommitLoad(event)) {\n const frameData = event.args.data;\n if (!frameData) {\n return;\n }\n\n const {frame, name, url} = frameData;\n updateRendererProcessByFrame(event, {processId: event.pid, frame, name, url});\n return;\n }\n\n // Track all threads based on the process & thread IDs.\n if (Types.TraceEvents.isThreadName(event)) {\n const threads = Platform.MapUtilities.getWithDefault(threadsInProcess, event.pid, () => new Map());\n threads.set(event.tid, event);\n return;\n }\n\n // Track all navigation events. Note that there can be navigation start events\n // but where the documentLoaderURL is empty. As far as the trace rendering is\n // concerned, these events are noise so we filter them out here.\n if (Types.TraceEvents.isTraceEventNavigationStartWithURL(event) && event.args.data) {\n const navigationId = event.args.data.navigationId;\n if (navigationsByNavigationId.has(navigationId)) {\n throw new Error('Found multiple navigation start events with the same navigation ID.');\n }\n navigationsByNavigationId.set(navigationId, event);\n\n const frameId = event.args.frame;\n const existingFrameNavigations = navigationsByFrameId.get(frameId) || [];\n existingFrameNavigations.push(event);\n navigationsByFrameId.set(frameId, existingFrameNavigations);\n if (frameId === mainFrameId) {\n mainFrameNavigations.push(event);\n }\n return;\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Handler is not initialized');\n }\n\n // We try to set the minimum time by finding the event with the smallest\n // timestamp. However, if we also got a timestamp from the\n // TracingStartedInBrowser event, we should always use that.\n // But in some traces (for example, CPU profiles) we do not get that event,\n // hence why we need to check we got a timestamp from it before setting it.\n if (traceStartedTimeFromTracingStartedEvent >= 0) {\n traceBounds.min = traceStartedTimeFromTracingStartedEvent;\n }\n traceBounds.range = Types.Timing.MicroSeconds(traceBounds.max - traceBounds.min);\n\n // If we go from foo.com to example.com we will get a new renderer, and\n // therefore the \"top level renderer\" will have a different PID as it has\n // changed. Here we step through each renderer process and updated its window\n // bounds, such that we end up with the time ranges in the trace for when\n // each particular renderer started and stopped being the main renderer\n // process.\n for (const [, processWindows] of rendererProcessesByFrameId) {\n const processWindowValues = [...processWindows.values()].flat();\n for (let i = 0; i < processWindowValues.length; i++) {\n const currentWindow = processWindowValues[i];\n const nextWindow = processWindowValues[i + 1];\n\n // For the last window we set its max to be positive infinity.\n // TODO: Move the trace bounds handler into meta so we can clamp first and last windows.\n if (!nextWindow) {\n currentWindow.window.max = Types.Timing.MicroSeconds(traceBounds.max);\n currentWindow.window.range = Types.Timing.MicroSeconds(traceBounds.max - currentWindow.window.min);\n } else {\n currentWindow.window.max = Types.Timing.MicroSeconds(nextWindow.window.min - 1);\n currentWindow.window.range = Types.Timing.MicroSeconds(currentWindow.window.max - currentWindow.window.min);\n }\n }\n }\n\n // Frame ids which we didn't register using either the TracingStartedInBrowser or\n // the FrameCommittedInBrowser events are considered noise, so we filter them out, as well\n // as the navigations that belong to such frames.\n for (const [frameId, navigations] of navigationsByFrameId) {\n // The frames in the rendererProcessesByFrameId map come only from the\n // TracingStartedInBrowser and FrameCommittedInBrowser events, so we can use it as point\n // of comparison to determine if a frameId should be discarded.\n if (rendererProcessesByFrameId.has(frameId)) {\n continue;\n }\n navigationsByFrameId.delete(frameId);\n for (const navigation of navigations) {\n if (!navigation.args.data) {\n continue;\n }\n navigationsByNavigationId.delete(navigation.args.data.navigationId);\n }\n }\n\n handlerState = HandlerState.FINALIZED;\n}\n\ntype MetaHandlerData = {\n traceBounds: Types.Timing.TraceWindow,\n browserProcessId: Types.TraceEvents.ProcessID,\n browserThreadId: Types.TraceEvents.ThreadID,\n gpuProcessId: Types.TraceEvents.ProcessID,\n gpuThreadId?: Types.TraceEvents.ThreadID,\n viewportRect?: DOMRect,\n navigationsByFrameId: Map<string, Types.TraceEvents.TraceEventNavigationStart[]>,\n navigationsByNavigationId: Map<string, Types.TraceEvents.TraceEventNavigationStart>,\n threadsInProcess:\n Map<Types.TraceEvents.ProcessID,\n Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventThreadName>>,\n mainFrameId: string,\n mainFrameURL: string,\n /**\n * A frame can have multiple renderer processes, at the same time,\n * a renderer process can have multiple URLs. This map tracks the\n * processes active on a given frame, with the time window in which\n * they were active. Because a renderer process might have multiple\n * URLs, each process in each frame has an array of windows, with an\n * entry for each URL it had.\n */\n rendererProcessesByFrame: FrameProcessData,\n topLevelRendererIds: Set<Types.TraceEvents.ProcessID>,\n frameByProcessId: Map<Types.TraceEvents.ProcessID, Map<string, Types.TraceEvents.TraceFrame>>,\n mainFrameNavigations: Types.TraceEvents.TraceEventNavigationStart[],\n};\n\nexport type FrameProcessData =\n Map<string,\n Map<Types.TraceEvents.ProcessID, {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindow}[]>>;\n\nexport function data(): MetaHandlerData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Meta Handler is not finalized');\n }\n\n return {\n traceBounds: {...traceBounds},\n browserProcessId,\n browserThreadId,\n gpuProcessId,\n gpuThreadId: gpuThreadId === Types.TraceEvents.ThreadID(-1) ? undefined : gpuThreadId,\n viewportRect: viewportRect || undefined,\n mainFrameId,\n mainFrameURL,\n navigationsByFrameId: new Map(navigationsByFrameId),\n navigationsByNavigationId: new Map(navigationsByNavigationId),\n threadsInProcess: new Map(threadsInProcess),\n rendererProcessesByFrame: new Map(rendererProcessesByFrameId),\n topLevelRendererIds: new Set(topLevelRendererIds),\n frameByProcessId: new Map(framesByProcessId),\n mainFrameNavigations: [...mainFrameNavigations],\n };\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as SamplesIntegrator from './SamplesIntegrator.js';\nexport * as Timing from './Timing.js';\nexport * as Trace from './Trace.js';\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport type * as CPUProfile from '../../cpu_profile/cpu_profile.js';\nimport * as Types from '../types/types.js';\n\nimport {millisecondsToMicroseconds} from './Timing.js';\nimport {mergeEventsInOrder} from './Trace.js';\n\n/**\n * This is a helper that integrates CPU profiling data coming in the\n * shape of samples, with trace events. Samples indicate what the JS\n * stack trace looked at a given point in time, but they don't have\n * duration. The SamplesIntegrator task is to make an approximation\n * of what the duration of each JS call was, given the sample data and\n * given the trace events profiled during that time. At the end of its\n * execution, the SamplesIntegrator returns an array of ProfileCalls\n * (under SamplesIntegrator::buildProfileCalls()), which\n * represent JS calls, with a call frame and duration. These calls have\n * the shape of a complete trace events and can be treated as flame\n * chart entries in the timeline.\n *\n * The approach to build the profile calls consists in tracking the\n * current stack as the following events happen (in order):\n * 1. A sample was done.\n * 2. A trace event started.\n * 3. A trace event ended.\n * Depending on the event and on the data that's coming with it the\n * stack is updated by adding or removing JS calls to it and updating\n * the duration of the calls in the tracking stack.\n *\n * note: Although this approach has been implemented since long ago, and\n * is relatively efficent (adds a complexity over the trace parsing of\n * O(n) where n is the number of samples) it has proven to be faulty.\n * It might be worthwhile experimenting with improvements or with a\n * completely different approach. Improving the approach is tracked in\n * crbug.com/1417439\n */\nexport class SamplesIntegrator {\n /**\n * The result of runing the samples integrator. Holds the JS calls\n * with their approximated duration after integrating samples into the\n * trace event tree.\n */\n #constructedProfileCalls: Types.TraceEvents.TraceEventSyntheticProfileCall[] = [];\n /**\n * tracks the state of the JS stack at each point in time to update\n * the profile call durations as new events arrive. This doesn't only\n * happen with new profile calls (in which case we would compare the\n * stack in them) but also with trace events (in which case we would\n * update the duration of the events we are tracking at the moment).\n */\n #currentJSStack: Types.TraceEvents.TraceEventSyntheticProfileCall[] = [];\n /**\n * Process holding the CPU profile and trace events.\n */\n #processId: Types.TraceEvents.ProcessID;\n /**\n * Thread holding the CPU profile and trace events.\n */\n #threadId: Types.TraceEvents.ThreadID;\n /**\n * Tracks the depth of the JS stack at the moment a trace event starts\n * or ends. It is assumed that for the duration of a trace event, the\n * JS stack's depth cannot decrease, since JS calls that started\n * before a trace event cannot end during the trace event. So as trace\n * events arrive, we store the \"locked\" amount of JS frames that were\n * in the stack before the event came.\n */\n #lockedJsStackDepth: number[] = [];\n /**\n * Used to keep track when samples should be integrated even if they\n * are not children of invocation trace events. This is useful in\n * cases where we can be missing the start of JS invocation events if\n * we start tracing half-way through.\n */\n #fakeJSInvocation = false;\n /**\n * The parsed CPU profile, holding the tree hierarchy of JS frames and\n * the sample data.\n */\n #profileModel: CPUProfile.CPUProfileDataModel.CPUProfileDataModel;\n\n #engineConfig: Types.Configuration.Configuration;\n\n constructor(\n profileModel: CPUProfile.CPUProfileDataModel.CPUProfileDataModel, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID, configuration?: Types.Configuration.Configuration) {\n this.#profileModel = profileModel;\n this.#threadId = tid;\n this.#processId = pid;\n this.#engineConfig = configuration || Types.Configuration.DEFAULT;\n }\n\n buildProfileCalls(traceEvents: Types.TraceEvents.TraceEventData[]):\n Types.TraceEvents.TraceEventSyntheticProfileCall[] {\n const mergedEvents = mergeEventsInOrder(traceEvents, this.callsFromProfileSamples());\n const stack = [];\n for (let i = 0; i < mergedEvents.length; i++) {\n const event = mergedEvents[i];\n // Because instant trace events have no duration, they don't provide\n // useful information for possible changes in the duration of calls\n // in the JS stack.\n if (event.ph === Types.TraceEvents.Phase.INSTANT) {\n continue;\n }\n if (stack.length === 0) {\n if (Types.TraceEvents.isProfileCall(event)) {\n this.#onProfileCall(event);\n continue;\n }\n stack.push(event);\n this.#onTraceEventStart(event);\n continue;\n }\n\n const parentEvent = stack.at(-1);\n if (parentEvent === undefined) {\n continue;\n }\n const begin = event.ts;\n const parentBegin = parentEvent.ts;\n const parentDuration = parentEvent.dur || 0;\n const parentEnd = parentBegin + parentDuration;\n\n const startsAfterParent = begin >= parentEnd;\n if (startsAfterParent) {\n this.#onTraceEventEnd(parentEvent);\n stack.pop();\n i--;\n continue;\n }\n if (Types.TraceEvents.isProfileCall(event)) {\n this.#onProfileCall(event, parentEvent);\n continue;\n }\n this.#onTraceEventStart(event);\n stack.push(event);\n }\n while (stack.length) {\n const last = stack.pop();\n if (last) {\n this.#onTraceEventEnd(last);\n }\n }\n return this.#constructedProfileCalls;\n }\n\n #onTraceEventStart(event: Types.TraceEvents.TraceEventData): void {\n // Top level events cannot be nested into JS frames so we reset\n // the stack when we find one.\n if (event.name === Types.TraceEvents.KnownEventName.RunMicrotasks ||\n event.name === Types.TraceEvents.KnownEventName.RunTask) {\n this.#lockedJsStackDepth = [];\n this.#truncateJSStack(0, event.ts);\n this.#fakeJSInvocation = false;\n }\n\n if (this.#fakeJSInvocation) {\n this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, event.ts);\n this.#fakeJSInvocation = false;\n }\n this.#extractStackTrace(event);\n // Keep track of the call frames in the stack before the event\n // happened. For the duration of this event, these frames cannot\n // change (none can be terminated before this event finishes).\n //\n // Also, every frame that is opened after this event, is considered\n // to be a descendant of the event. So once the event finishes, the\n // frames that were opened after it, need to be closed (see\n // onEndEvent).\n //\n // TODO(crbug.com/1417439):\n // The assumption that every frame opened after an event is a\n // descendant of the event is incorrect. For example, a JS call that\n // parents a trace event might have been sampled after the event was\n // dispatched. In this case the JS call would be discarded if this\n // event isn't an invocation event, otherwise the call will be\n // considered a child of the event. In both cases, the result would\n // be incorrect.\n this.#lockedJsStackDepth.push(this.#currentJSStack.length);\n }\n\n #onProfileCall(event: Types.TraceEvents.TraceEventSyntheticProfileCall, parent?: Types.TraceEvents.TraceEventData):\n void {\n if ((parent && SamplesIntegrator.isJSInvocationEvent(parent)) || this.#fakeJSInvocation) {\n this.#extractStackTrace(event);\n } else if (Types.TraceEvents.isProfileCall(event) && this.#currentJSStack.length === 0) {\n // Force JS Samples to show up even if we are not inside a JS\n // invocation event, because we can be missing the start of JS\n // invocation events if we start tracing half-way through. Pretend\n // we have a top-level JS invocation event.\n this.#fakeJSInvocation = true;\n const stackDepthBefore = this.#currentJSStack.length;\n this.#extractStackTrace(event);\n this.#lockedJsStackDepth.push(stackDepthBefore);\n }\n }\n\n #onTraceEventEnd(event: Types.TraceEvents.TraceEventData): void {\n // Because the event has ended, any frames that happened after\n // this event are terminated. Frames that are ancestors to this\n // event are extended to cover its ending.\n const endTime = Types.Timing.MicroSeconds(event.ts + (event.dur || 0));\n this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, endTime);\n }\n\n /**\n * Builds the initial calls with no duration from samples. Their\n * purpose is to be merged with the trace event array being parsed so\n * that they can be traversed in order with them and their duration\n * can be updated as the SampleIntegrator callbacks are invoked.\n */\n callsFromProfileSamples(): Types.TraceEvents.TraceEventSyntheticProfileCall[] {\n const samples = this.#profileModel.samples;\n const timestamps = this.#profileModel.timestamps;\n if (!samples) {\n return [];\n }\n const calls: Types.TraceEvents.TraceEventSyntheticProfileCall[] = [];\n for (let i = 0; i < samples.length; i++) {\n const node = this.#profileModel.nodeByIndex(i);\n const timestamp = millisecondsToMicroseconds(Types.Timing.MilliSeconds(timestamps[i]));\n if (!node) {\n continue;\n }\n const call = SamplesIntegrator.makeProfileCall(node, timestamp, this.#processId, this.#threadId);\n calls.push(call);\n }\n return calls;\n }\n\n #getStackTraceFromProfileCall(profileCall: Types.TraceEvents.TraceEventSyntheticProfileCall):\n Types.TraceEvents.TraceEventSyntheticProfileCall[] {\n let node = this.#profileModel.nodeById(profileCall.nodeId);\n if (!node) {\n return [];\n }\n // `node.depth` is 0 based, so to set the size of the array we need\n // to add 1 to its value.\n const callFrames = new Array<Types.TraceEvents.TraceEventSyntheticProfileCall>(node.depth + 1);\n // Add the stack trace in reverse order (bottom first).\n let i = callFrames.length - 1;\n while (node) {\n callFrames[i--] = SamplesIntegrator.makeProfileCall(node, profileCall.ts, this.#processId, this.#threadId);\n node = node.parent;\n }\n return callFrames;\n }\n\n /**\n * Update tracked stack using this event's call stack.\n */\n #extractStackTrace(event: Types.TraceEvents.TraceEventData): void {\n const stackTrace =\n Types.TraceEvents.isProfileCall(event) ? this.#getStackTraceFromProfileCall(event) : this.#currentJSStack;\n SamplesIntegrator.filterStackFrames(stackTrace, this.#engineConfig);\n\n const endTime = event.ts + (event.dur || 0);\n const minFrames = Math.min(stackTrace.length, this.#currentJSStack.length);\n let i;\n // Merge a sample's stack frames with the stack frames we have\n // so far if we detect they are equivalent.\n // Graphically\n // This:\n // Current stack trace Sample\n // [-------A------] [A]\n // [-------B------] [B]\n // [-------C------] [C]\n // ^ t = x1 ^ t = x2\n\n // Becomes this:\n // New stack trace after merge\n // [--------A-------]\n // [--------B-------]\n // [--------C-------]\n // ^ t = x2\n for (i = this.#lockedJsStackDepth.at(-1) || 0; i < minFrames; ++i) {\n const newFrame = stackTrace[i].callFrame;\n const oldFrame = this.#currentJSStack[i].callFrame;\n if (!SamplesIntegrator.framesAreEqual(newFrame, oldFrame)) {\n break;\n }\n // Scoot the right edge of this callFrame to the right\n this.#currentJSStack[i].dur =\n Types.Timing.MicroSeconds(Math.max(this.#currentJSStack[i].dur || 0, endTime - this.#currentJSStack[i].ts));\n }\n\n // If there are call frames in the sample that differ with the stack\n // we have, update the stack, but keeping the common frames in place\n // Graphically\n // This:\n // Current stack trace Sample\n // [-------A------] [A]\n // [-------B------] [B]\n // [-------C------] [C]\n // [-------D------] [E]\n // ^ t = x1 ^ t = x2\n // Becomes this:\n // New stack trace after merge\n // [--------A-------]\n // [--------B-------]\n // [--------C-------]\n // [E]\n // ^ t = x2\n this.#truncateJSStack(i, event.ts);\n\n for (; i < stackTrace.length; ++i) {\n const call = stackTrace[i];\n this.#currentJSStack.push(call);\n if (call.nodeId === this.#profileModel.programNode?.id || call.nodeId === this.#profileModel.root?.id ||\n call.nodeId === this.#profileModel.idleNode?.id || call.nodeId === this.#profileModel.gcNode?.id) {\n // Skip (root), (program) and (idle) frames, since this are not\n // relevant for web profiling and we don't want to show them in\n // the timeline.\n continue;\n }\n this.#constructedProfileCalls.push(call);\n }\n }\n\n /**\n * When a call stack that differs from the one we are tracking has\n * been detected in the samples, the latter is \"truncated\" by\n * setting the ending time of its call frames and removing the top\n * call frames that aren't shared with the new call stack. This way,\n * we can update the tracked stack with the new call frames on top.\n * @param depth the amount of call frames from bottom to top that\n * should be kept in the tracking stack trace. AKA amount of shared\n * call frames between two stacks.\n * @param time the new end of the call frames in the stack.\n */\n #truncateJSStack(depth: number, time: Types.Timing.MicroSeconds): void {\n if (this.#lockedJsStackDepth.length) {\n const lockedDepth = this.#lockedJsStackDepth.at(-1);\n if (lockedDepth && depth < lockedDepth) {\n console.error(`Child stack is shallower (${depth}) than the parent stack (${lockedDepth}) at ${time}`);\n depth = lockedDepth;\n }\n }\n if (this.#currentJSStack.length < depth) {\n console.error(`Trying to truncate higher than the current stack size at ${time}`);\n depth = this.#currentJSStack.length;\n }\n for (let k = 0; k < this.#currentJSStack.length; ++k) {\n this.#currentJSStack[k].dur = Types.Timing.MicroSeconds(Math.max(time - this.#currentJSStack[k].ts, 0));\n }\n this.#currentJSStack.length = depth;\n }\n\n /**\n * Generally, before JS is executed, a trace event is dispatched that\n * parents the JS calls. These we call \"invocation\" events. This\n * function determines if an event is one of such.\n */\n static isJSInvocationEvent(event: Types.TraceEvents.TraceEventData): boolean {\n switch (event.name) {\n case Types.TraceEvents.KnownEventName.RunMicrotasks:\n case Types.TraceEvents.KnownEventName.FunctionCall:\n case Types.TraceEvents.KnownEventName.EvaluateScript:\n case Types.TraceEvents.KnownEventName.EvaluateModule:\n case Types.TraceEvents.KnownEventName.EventDispatch:\n case Types.TraceEvents.KnownEventName.V8Execute:\n return true;\n }\n // Also consider any new v8 trace events. (eg 'V8.RunMicrotasks' and 'v8.run')\n if (event.name.startsWith('v8') || event.name.startsWith('V8')) {\n return true;\n }\n return false;\n }\n\n static framesAreEqual(frame1: Protocol.Runtime.CallFrame, frame2: Protocol.Runtime.CallFrame): boolean {\n return frame1.scriptId === frame2.scriptId && frame1.functionName === frame2.functionName &&\n frame1.lineNumber === frame2.lineNumber;\n }\n\n static showNativeName(name: string, runtimeCallStatsEnabled: boolean): boolean {\n return runtimeCallStatsEnabled && Boolean(SamplesIntegrator.nativeGroup(name));\n }\n\n static nativeGroup(nativeName: string): 'Parse'|'Compile'|null {\n if (nativeName.startsWith('Parse')) {\n return 'Parse';\n }\n if (nativeName.startsWith('Compile') || nativeName.startsWith('Recompile')) {\n return 'Compile';\n }\n return null;\n }\n\n static isNativeRuntimeFrame(frame: Protocol.Runtime.CallFrame): boolean {\n return frame.url === 'native V8Runtime';\n }\n\n static filterStackFrames(\n stack: Types.TraceEvents.TraceEventSyntheticProfileCall[],\n engineConfig: Types.Configuration.Configuration): void {\n const showAllEvents = engineConfig.experiments.timelineShowAllEvents;\n if (showAllEvents) {\n return;\n }\n let previousNativeFrameName: string|null = null;\n let j = 0;\n for (let i = 0; i < stack.length; ++i) {\n const frame = stack[i].callFrame;\n const nativeRuntimeFrame = SamplesIntegrator.isNativeRuntimeFrame(frame);\n if (nativeRuntimeFrame &&\n !SamplesIntegrator.showNativeName(frame.functionName, engineConfig.experiments.timelineV8RuntimeCallStats)) {\n continue;\n }\n const nativeFrameName = nativeRuntimeFrame ? SamplesIntegrator.nativeGroup(frame.functionName) : null;\n if (previousNativeFrameName && previousNativeFrameName === nativeFrameName) {\n continue;\n }\n previousNativeFrameName = nativeFrameName;\n stack[j++] = stack[i];\n }\n stack.length = j;\n }\n\n static makeProfileCall(\n node: CPUProfile.ProfileTreeModel.ProfileNode, ts: Types.Timing.MicroSeconds, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID): Types.TraceEvents.TraceEventSyntheticProfileCall {\n return {\n cat: '',\n name: 'ProfileCall',\n nodeId: node.id,\n args: {},\n ph: Types.TraceEvents.Phase.COMPLETE,\n pid,\n tid,\n ts,\n dur: Types.Timing.MicroSeconds(0),\n selfTime: Types.Timing.MicroSeconds(0),\n callFrame: node.callFrame,\n };\n }\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Types from '../types/types.js';\n\nimport {getNavigationForTraceEvent} from './Trace.js';\n\nexport const millisecondsToMicroseconds = (value: Types.Timing.MilliSeconds): Types.Timing.MicroSeconds =>\n Types.Timing.MicroSeconds(value * 1000);\n\nexport const secondsToMilliseconds = (value: Types.Timing.Seconds): Types.Timing.MilliSeconds =>\n Types.Timing.MilliSeconds(value * 1000);\n\nexport const secondsToMicroseconds = (value: Types.Timing.Seconds): Types.Timing.MicroSeconds =>\n millisecondsToMicroseconds(secondsToMilliseconds(value));\n\nexport const microSecondsToMilliseconds = (value: Types.Timing.MicroSeconds): Types.Timing.MilliSeconds =>\n Types.Timing.MilliSeconds(value / 1000);\n\nexport const microSecondsToSeconds = (value: Types.Timing.MicroSeconds): Types.Timing.Seconds =>\n Types.Timing.Seconds(value / 1000 / 1000);\n\nexport function detectBestTimeUnit(timeInMicroseconds: Types.Timing.MicroSeconds): Types.Timing.TimeUnit {\n if (timeInMicroseconds < 1000) {\n return Types.Timing.TimeUnit.MICROSECONDS;\n }\n\n const timeInMilliseconds = timeInMicroseconds / 1000;\n if (timeInMilliseconds < 1000) {\n return Types.Timing.TimeUnit.MILLISECONDS;\n }\n\n const timeInSeconds = timeInMilliseconds / 1000;\n if (timeInSeconds < 60) {\n return Types.Timing.TimeUnit.SECONDS;\n }\n\n return Types.Timing.TimeUnit.MINUTES;\n}\n\ninterface FormatOptions extends Intl.NumberFormatOptions {\n format?: Types.Timing.TimeUnit;\n}\n\nconst defaultFormatOptions = {\n style: 'unit',\n unit: 'millisecond',\n unitDisplay: 'narrow',\n};\n\n// Create a bunch of common formatters up front, so that we're not creating\n// them repeatedly during rendering.\nconst serialize = (value: {}): string => JSON.stringify(value);\nconst formatterFactory = (key: string|undefined): Intl.NumberFormat => {\n // If we pass undefined as the locale, that achieves two things:\n // 1. Avoids us referencing window.navigatior to fetch the locale, which is\n // useful given long term we would like this engine to run in NodeJS\n // environments.\n // 2. Will cause the formatter to fallback to the locale of the system, which\n // is likely going to be the most accurate one to use anyway.\n return new Intl.NumberFormat(undefined, key ? JSON.parse(key) : {});\n};\nconst formatters = new Map<string, Intl.NumberFormat>();\n\n// Microsecond Formatter.\nPlatform.MapUtilities.getWithDefault(formatters, serialize({style: 'decimal'}), formatterFactory);\n\n// Millisecond Formatter\nPlatform.MapUtilities.getWithDefault(formatters, serialize(defaultFormatOptions), formatterFactory);\n\n// Second Formatter\nPlatform.MapUtilities.getWithDefault(\n formatters, serialize({...defaultFormatOptions, unit: 'second'}), formatterFactory);\n\n// Minute Formatter\nPlatform.MapUtilities.getWithDefault(\n formatters, serialize({...defaultFormatOptions, unit: 'minute'}), formatterFactory);\n\nexport function formatMicrosecondsTime(\n timeInMicroseconds: Types.Timing.MicroSeconds, opts: FormatOptions = {}): string {\n if (!opts.format) {\n opts.format = detectBestTimeUnit(timeInMicroseconds);\n }\n\n const timeInMilliseconds = timeInMicroseconds / 1000;\n const timeInSeconds = timeInMilliseconds / 1000;\n const formatterOpts = {...defaultFormatOptions, ...opts};\n\n switch (opts.format) {\n case Types.Timing.TimeUnit.MICROSECONDS: {\n const formatter =\n Platform.MapUtilities.getWithDefault(formatters, serialize({style: 'decimal'}), formatterFactory);\n return `${formatter.format(timeInMicroseconds)}\u03BCs`;\n }\n\n case Types.Timing.TimeUnit.MILLISECONDS: {\n const formatter = Platform.MapUtilities.getWithDefault(formatters, serialize(formatterOpts), formatterFactory);\n return formatter.format(timeInMilliseconds);\n }\n\n case Types.Timing.TimeUnit.SECONDS: {\n const formatter = Platform.MapUtilities.getWithDefault(\n formatters, serialize({...formatterOpts, unit: 'second'}), formatterFactory);\n return formatter.format(timeInSeconds);\n }\n\n default: {\n // Switch to mins & seconds.\n const minuteFormatter = Platform.MapUtilities.getWithDefault(\n formatters, serialize({...formatterOpts, unit: 'minute'}), formatterFactory);\n const secondFormatter = Platform.MapUtilities.getWithDefault(\n formatters, serialize({...formatterOpts, unit: 'second'}), formatterFactory);\n const timeInMinutes = timeInSeconds / 60;\n const [mins, divider, fraction] = minuteFormatter.formatToParts(timeInMinutes);\n\n let seconds = 0;\n if (divider && fraction) {\n // Convert the fraction value (a string) to the nearest second.\n seconds = Math.round(Number(`0.${fraction.value}`) * 60);\n }\n return `${minuteFormatter.format(Number(mins.value))} ${secondFormatter.format(seconds)}`;\n }\n }\n}\n\nexport function timeStampForEventAdjustedByClosestNavigation(\n event: Types.TraceEvents.TraceEventData,\n traceBounds: Types.Timing.TraceWindow,\n navigationsByNavigationId: Map<string, Types.TraceEvents.TraceEventNavigationStart>,\n navigationsByFrameId: Map<string, Types.TraceEvents.TraceEventNavigationStart[]>,\n ): Types.Timing.MicroSeconds {\n let eventTimeStamp = event.ts - traceBounds.min;\n if (event.args?.data?.navigationId) {\n const navigationForEvent = navigationsByNavigationId.get(event.args.data.navigationId);\n if (navigationForEvent) {\n eventTimeStamp = event.ts - navigationForEvent.ts;\n }\n } else if (event.args?.data?.frame) {\n const navigationForEvent = getNavigationForTraceEvent(event, event.args.data.frame, navigationsByFrameId);\n if (navigationForEvent) {\n eventTimeStamp = event.ts - navigationForEvent.ts;\n }\n }\n return Types.Timing.MicroSeconds(eventTimeStamp);\n}\n\nexport interface EventTimingsData<\n ValueType extends Types.Timing.MicroSeconds|Types.Timing.MilliSeconds|Types.Timing.Seconds,\n> {\n startTime: ValueType;\n endTime: ValueType;\n duration: ValueType;\n selfTime: ValueType;\n}\n\nexport function eventTimingsMicroSeconds(event: Types.TraceEvents.TraceEventData):\n EventTimingsData<Types.Timing.MicroSeconds> {\n return {\n startTime: event.ts,\n endTime: Types.Timing.MicroSeconds(event.ts + (event.dur || Types.Timing.MicroSeconds(0))),\n duration: Types.Timing.MicroSeconds(event.dur || 0),\n // TODO(crbug.com/1434599): Implement selfTime calculation for events\n // from the new engine.\n selfTime: Types.TraceEvents.isRendererEvent(event) ? Types.Timing.MicroSeconds(event.selfTime || 0) :\n Types.Timing.MicroSeconds(event.dur || 0),\n };\n}\nexport function eventTimingsMilliSeconds(event: Types.TraceEvents.TraceEventData):\n EventTimingsData<Types.Timing.MilliSeconds> {\n const microTimes = eventTimingsMicroSeconds(event);\n return {\n startTime: microSecondsToMilliseconds(microTimes.startTime),\n endTime: microSecondsToMilliseconds(microTimes.endTime),\n duration: microSecondsToMilliseconds(microTimes.duration),\n selfTime: microSecondsToMilliseconds(microTimes.selfTime),\n };\n}\nexport function eventTimingsSeconds(event: Types.TraceEvents.TraceEventData): EventTimingsData<Types.Timing.Seconds> {\n const microTimes = eventTimingsMicroSeconds(event);\n return {\n startTime: microSecondsToSeconds(microTimes.startTime),\n endTime: microSecondsToSeconds(microTimes.endTime),\n duration: microSecondsToSeconds(microTimes.duration),\n selfTime: microSecondsToSeconds(microTimes.selfTime),\n };\n}\n\nexport function traceBoundsMilliseconds(bounds: Types.Timing.TraceWindow): {\n min: Types.Timing.MilliSeconds,\n max: Types.Timing.MilliSeconds,\n range: Types.Timing.MilliSeconds,\n} {\n return {\n min: microSecondsToMilliseconds(bounds.min),\n max: microSecondsToMilliseconds(bounds.max),\n range: microSecondsToMilliseconds(bounds.range),\n };\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Types from '../types/types.js';\nimport * as Platform from '../../../core/platform/platform.js';\n\nexport function extractOriginFromTrace(firstNavigationURL: string): string|null {\n const url = new URL(firstNavigationURL);\n if (url) {\n // We do this to save some space in the toolbar - seeing the `www` is less\n // useful than seeing `foo.com` if it's truncated at narrow widths\n if (url.host.startsWith('www.')) {\n return url.host.slice(4);\n }\n return url.host;\n }\n return null;\n}\n\nexport type EventsInThread<T extends Types.TraceEvents.TraceEventData> = Map<Types.TraceEvents.ThreadID, T[]>;\n// Each thread contains events. Events indicate the thread and process IDs, which are\n// used to store the event in the correct process thread entry below.\nexport function addEventToProcessThread<T extends Types.TraceEvents.TraceEventData>(\n event: T,\n eventsInProcessThread: Map<Types.TraceEvents.ProcessID, EventsInThread<T>>,\n ): void {\n const {tid, pid} = event;\n let eventsInThread = eventsInProcessThread.get(pid);\n if (!eventsInThread) {\n eventsInThread = new Map<Types.TraceEvents.ThreadID, T[]>();\n }\n\n let events = eventsInThread.get(tid);\n if (!events) {\n events = [];\n }\n\n events.push(event);\n eventsInThread.set(event.tid, events);\n eventsInProcessThread.set(event.pid, eventsInThread);\n}\n\ntype TimeSpan = {\n ts: Types.Timing.MicroSeconds,\n dur?: Types.Timing.MicroSeconds,\n};\nfunction eventTimeComparator(a: TimeSpan, b: TimeSpan): -1|0|1 {\n const aBeginTime = a.ts;\n const bBeginTime = b.ts;\n if (aBeginTime < bBeginTime) {\n return -1;\n }\n if (aBeginTime > bBeginTime) {\n return 1;\n }\n const aDuration = a.dur ?? 0;\n const bDuration = b.dur ?? 0;\n const aEndTime = aBeginTime + aDuration;\n const bEndTime = bBeginTime + bDuration;\n if (aEndTime > bEndTime) {\n return -1;\n }\n if (aEndTime < bEndTime) {\n return 1;\n }\n return 0;\n}\n/**\n * Sorts all the events in place, in order, by their start time. If they have\n * the same start time, orders them by longest first.\n */\nexport function sortTraceEventsInPlace(events: {ts: Types.Timing.MicroSeconds, dur?: Types.Timing.MicroSeconds}[]):\n void {\n events.sort(eventTimeComparator);\n}\n\n/**\n * Returns an array of ordered events that results after merging the two\n * ordered input arrays.\n */\nexport function\nmergeEventsInOrder<T1 extends Types.TraceEvents.TraceEventData, T2 extends Types.TraceEvents.TraceEventData>(\n eventsArray1: T1[], eventsArray2: T2[]): (T1|T2)[] {\n const result = [];\n let i = 0;\n let j = 0;\n while (i < eventsArray1.length && j < eventsArray2.length) {\n const event1 = eventsArray1[i];\n const event2 = eventsArray2[j];\n const compareValue = eventTimeComparator(event1, event2);\n if (compareValue <= 0) {\n result.push(event1);\n i++;\n }\n if (compareValue === 1) {\n result.push(event2);\n j++;\n }\n }\n while (i < eventsArray1.length) {\n result.push(eventsArray1[i++]);\n }\n while (j < eventsArray2.length) {\n result.push(eventsArray2[j++]);\n }\n return result;\n}\n\nexport function getNavigationForTraceEvent(\n event: Types.TraceEvents.TraceEventData,\n eventFrameId: string,\n navigationsByFrameId: Map<string, Types.TraceEvents.TraceEventNavigationStart[]>,\n ): Types.TraceEvents.TraceEventNavigationStart|null {\n const navigations = navigationsByFrameId.get(eventFrameId);\n if (!navigations || eventFrameId === '') {\n // This event's navigation has been filtered out by the meta handler as a noise event\n // or contains an empty frameId.\n return null;\n }\n\n const eventNavigationIndex =\n Platform.ArrayUtilities.nearestIndexFromEnd(navigations, navigation => navigation.ts <= event.ts);\n\n if (eventNavigationIndex === null) {\n // This event's navigation has been filtered out by the meta handler as a noise event.\n return null;\n }\n return navigations[eventNavigationIndex];\n}\n\nexport function extractId(event: Types.TraceEvents.TraceEventNestableAsync): string|undefined {\n return event.id || event.id2?.global || event.id2?.local;\n}\n\nexport function activeURLForFrameAtTime(\n frameId: string, time: Types.Timing.MicroSeconds,\n rendererProcessesByFrame: Map<\n string,\n Map<Types.TraceEvents.ProcessID, {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindow}[]>>):\n string|null {\n const processData = rendererProcessesByFrame.get(frameId);\n if (!processData) {\n return null;\n }\n for (const processes of processData.values()) {\n for (const processInfo of processes) {\n if (processInfo.window.min > time || processInfo.window.max < time) {\n continue;\n }\n return processInfo.frame.url;\n }\n }\n return null;\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\n\nimport {type TraceEventHandlerName, HandlerState} from './types.js';\n\nimport {ScoreClassification} from './PageLoadMetricsHandler.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport {data as screenshotsHandlerData} from './ScreenshotsHandler.js';\nimport * as Platform from '../../../core/platform/platform.js';\n\nimport * as Types from '../types/types.js';\n\n// We start with a score of zero and step through all Layout Shift records from\n// all renderers. Each record not only tells us which renderer it is, but also\n// the unweighted and weighted scores. The unweighted score is the score we would\n// get if the renderer were the only one in the viewport. The weighted score, on\n// the other hand, accounts for how much of the viewport that particular render\n// takes up when the shift happened. An ad frame in the corner of the viewport\n// that shifts is considered less disruptive, therefore, than if it were taking\n// up the whole viewport.\n//\n// Next, we step through all the records from all renderers and add the weighted\n// score to a running total across all of the renderers. We create a new \"cluster\"\n// and reset the running total when:\n//\n// 1. We observe a outermost frame navigation, or\n// 2. When there's a gap between records of > 1s, or\n// 3. When there's more than 5 seconds of continuous layout shifting.\n//\n// Note that for it to be Cumulative Layout Shift in the sense described in the\n// documentation we would need to guarantee that we are tracking from navigation\n// to unload. However, we don't make any such guarantees here (since a developer\n// can record and stop when they please), so we support the cluster approach,\n// and we can give them a score, but it is effectively a \"session\" score, a\n// score for the given recording, and almost certainly not the\n// navigation-to-unload CLS score.\n\ninterface LayoutShifts {\n clusters: LayoutShiftCluster[];\n sessionMaxScore: number;\n // The session window which contains the SessionMaxScore\n clsWindowID: number;\n // We use these to calculate root causes for a given LayoutShift\n prePaintEvents: Types.TraceEvents.TraceEventPrePaint[];\n layoutInvalidationEvents: Types.TraceEvents.TraceEventLayoutInvalidation[];\n styleRecalcInvalidationEvents: Types.TraceEvents.TraceEventStyleRecalcInvalidation[];\n scoreRecords: ScoreRecord[];\n}\n\n// This represents the maximum #time we will allow a cluster to go before we\n// reset it.\nexport const MAX_CLUSTER_DURATION = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(5000));\n\n// This represents the maximum #time we will allow between layout shift events\n// before considering it to be the start of a new cluster.\nexport const MAX_SHIFT_TIME_DELTA = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(1000));\n\n// Layout shifts are reported globally to the developer, irrespective of which\n// frame they originated in. However, each process does have its own individual\n// CLS score, so we need to segment by process. This means Layout Shifts from\n// sites with one process (no subframes, or subframes from the same origin)\n// will be reported together. In the case of multiple renderers (frames across\n// different origins), we offer the developer the ability to switch renderer in\n// the UI.\nconst layoutShiftEvents: Types.TraceEvents.TraceEventLayoutShift[] = [];\n\n// These events denote potential node resizings. We store them to link captured\n// layout shifts to the resizing of unsized elements.\nconst layoutInvalidationEvents: Types.TraceEvents.TraceEventLayoutInvalidation[] = [];\nconst styleRecalcInvalidationEvents: Types.TraceEvents.TraceEventStyleRecalcInvalidation[] = [];\n\n// Layout shifts happen during PrePaint as part of the rendering lifecycle.\n// We determine if a LayoutInvalidation event is a potential root cause of a layout\n// shift if the next PrePaint after the LayoutInvalidation is the parent\n// node of such shift.\nconst prePaintEvents: Types.TraceEvents.TraceEventPrePaint[] = [];\n\nlet sessionMaxScore = 0;\n\nlet clsWindowID = -1;\n\nconst clusters: LayoutShiftCluster[] = [];\n\n// Represents a point in time in which a LS score change\n// was recorded.\ntype ScoreRecord = {\n ts: number,\n score: number,\n};\n\n// The complete timeline of LS score changes in a trace.\n// Includes drops to 0 when session windows end.\nconst scoreRecords: ScoreRecord[] = [];\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('LayoutShifts Handler was not reset');\n }\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function reset(): void {\n handlerState = HandlerState.UNINITIALIZED;\n layoutShiftEvents.length = 0;\n layoutInvalidationEvents.length = 0;\n prePaintEvents.length = 0;\n clusters.length = 0;\n sessionMaxScore = 0;\n scoreRecords.length = 0;\n clsWindowID = -1;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Handler is not initialized');\n }\n\n if (Types.TraceEvents.isTraceEventLayoutShift(event) && !event.args.data?.had_recent_input) {\n layoutShiftEvents.push(event);\n return;\n }\n if (Types.TraceEvents.isTraceEventLayoutInvalidation(event)) {\n layoutInvalidationEvents.push(event);\n return;\n }\n if (Types.TraceEvents.isTraceEventStyleRecalcInvalidation(event)) {\n styleRecalcInvalidationEvents.push(event);\n }\n if (Types.TraceEvents.isTraceEventPrePaint(event)) {\n prePaintEvents.push(event);\n return;\n }\n}\n\nfunction traceWindowFromTime(time: Types.Timing.MicroSeconds): Types.Timing.TraceWindow {\n return {\n min: time,\n max: time,\n range: Types.Timing.MicroSeconds(0),\n };\n}\n\nfunction updateTraceWindowMax(traceWindow: Types.Timing.TraceWindow, newMax: Types.Timing.MicroSeconds): void {\n traceWindow.max = newMax;\n traceWindow.range = Types.Timing.MicroSeconds(traceWindow.max - traceWindow.min);\n}\n\nfunction findNextScreenshotSource(timestamp: Types.Timing.MicroSeconds): string|undefined {\n const screenshots = screenshotsHandlerData();\n const screenshotIndex = findNextScreenshotEventIndex(screenshots, timestamp);\n if (!screenshotIndex) {\n return undefined;\n }\n return `data:img/png;base64,${screenshots[screenshotIndex].args.snapshot}`;\n}\n\nexport function findNextScreenshotEventIndex(\n screenshots: Types.TraceEvents.TraceEventSnapshot[], timestamp: Types.Timing.MicroSeconds): number|null {\n return Platform.ArrayUtilities.nearestIndexFromBeginning(screenshots, frame => frame.ts > timestamp);\n}\n\nfunction buildScoreRecords(): void {\n const {traceBounds} = metaHandlerData();\n scoreRecords.push({ts: traceBounds.min, score: 0});\n\n for (const cluster of clusters) {\n let clusterScore = 0;\n if (cluster.events[0].args.data) {\n scoreRecords.push({ts: cluster.clusterWindow.min, score: cluster.events[0].args.data.weighted_score_delta});\n }\n for (let i = 0; i < cluster.events.length; i++) {\n const event = cluster.events[i];\n if (!event.args.data) {\n continue;\n }\n clusterScore += event.args.data.weighted_score_delta;\n scoreRecords.push({ts: event.ts, score: clusterScore});\n }\n scoreRecords.push({ts: cluster.clusterWindow.max, score: 0});\n }\n}\n\nexport async function finalize(): Promise<void> {\n // Ensure the events are sorted by #time ascending.\n layoutShiftEvents.sort((a, b) => a.ts - b.ts);\n prePaintEvents.sort((a, b) => a.ts - b.ts);\n layoutInvalidationEvents.sort((a, b) => a.ts - b.ts);\n\n // Each function transforms the data used by the next, as such the invoke order\n // is important.\n await buildLayoutShiftsClusters();\n buildScoreRecords();\n handlerState = HandlerState.FINALIZED;\n}\nasync function buildLayoutShiftsClusters(): Promise<void> {\n const {navigationsByFrameId, mainFrameId, traceBounds} = metaHandlerData();\n const navigations = navigationsByFrameId.get(mainFrameId) || [];\n if (layoutShiftEvents.length === 0) {\n return;\n }\n let firstShiftTime = layoutShiftEvents[0].ts;\n let lastShiftTime = layoutShiftEvents[0].ts;\n let lastShiftNavigation = null;\n // Now step through each and create clusters.\n // A cluster is equivalent to a session window (see https://web.dev/cls/#what-is-cls).\n // To make the line chart clear, we explicitly demark the limits of each session window\n // by starting the cumulative score of the window at the time of the first layout shift\n // and ending it (dropping the line back to 0) when the window ends according to the\n // thresholds (MAX_CLUSTER_DURATION, MAX_SHIFT_TIME_DELTA).\n for (const event of layoutShiftEvents) {\n // First detect if either the cluster duration or the #time between this and\n // the last shift has been exceeded.\n const clusterDurationExceeded = event.ts - firstShiftTime > MAX_CLUSTER_DURATION;\n const maxTimeDeltaSinceLastShiftExceeded = event.ts - lastShiftTime > MAX_SHIFT_TIME_DELTA;\n\n // Next take a look at navigations. If between this and the last shift we have navigated,\n // note it.\n const currentShiftNavigation = Platform.ArrayUtilities.nearestIndexFromEnd(navigations, nav => nav.ts < event.ts);\n const hasNavigated = lastShiftNavigation !== currentShiftNavigation && currentShiftNavigation !== null;\n\n // If any of the above criteria are met or if we don't have any cluster yet we should\n // start a new one.\n if (clusterDurationExceeded || maxTimeDeltaSinceLastShiftExceeded || hasNavigated || !clusters.length) {\n // The cluster starts #time should be the timestamp of the first layout shift in it.\n const clusterStartTime = event.ts;\n\n // If the last session window ended because the max delta time between shifts\n // was exceeded set the endtime to MAX_SHIFT_TIME_DELTA microseconds after the\n // last shift in the session.\n const endTimeByMaxSessionDuration = clusterDurationExceeded ? firstShiftTime + MAX_CLUSTER_DURATION : Infinity;\n\n // If the last session window ended because the max session duration was\n // surpassed, set the endtime so that the window length = MAX_CLUSTER_DURATION;\n const endTimeByMaxShiftGap = maxTimeDeltaSinceLastShiftExceeded ? lastShiftTime + MAX_SHIFT_TIME_DELTA : Infinity;\n\n // If there was a navigation during the last window, close it at the time\n // of the navigation.\n const endTimeByNavigation = hasNavigated ? navigations[currentShiftNavigation].ts : Infinity;\n\n // End the previous cluster at the time of the first of the criteria above that was met.\n const previousClusterEndTime = Math.min(endTimeByMaxSessionDuration, endTimeByMaxShiftGap, endTimeByNavigation);\n\n // If there is an existing cluster update its closing time.\n if (clusters.length > 0) {\n const currentCluster = clusters[clusters.length - 1];\n updateTraceWindowMax(currentCluster.clusterWindow, Types.Timing.MicroSeconds(previousClusterEndTime));\n }\n\n clusters.push({\n events: [],\n clusterWindow: traceWindowFromTime(clusterStartTime),\n clusterCumulativeScore: 0,\n scoreWindows: {\n good: traceWindowFromTime(clusterStartTime),\n needsImprovement: null,\n bad: null,\n },\n });\n\n firstShiftTime = clusterStartTime;\n }\n\n // Given the above we should have a cluster available, so pick the most\n // recent one and append the shift, bump its score and window values accordingly.\n const currentCluster = clusters[clusters.length - 1];\n const timeFromNavigation = currentShiftNavigation !== null ?\n Types.Timing.MicroSeconds(event.ts - navigations[currentShiftNavigation].ts) :\n undefined;\n\n currentCluster.clusterCumulativeScore += event.args.data ? event.args.data.weighted_score_delta : 0;\n if (!event.args.data) {\n continue;\n }\n const shift: Types.TraceEvents.SyntheticLayoutShift = {\n ...event,\n args: {\n frame: event.args.frame,\n data: {\n ...event.args.data,\n rawEvent: event,\n },\n },\n parsedData: {\n screenshotSource: findNextScreenshotSource(event.ts),\n timeFromNavigation,\n cumulativeWeightedScoreInWindow: currentCluster.clusterCumulativeScore,\n // The score of the session window is temporarily set to 0 just\n // to initialize it. Since we need to get the score of all shifts\n // in the session window to determine its value, its definite\n // value is set when stepping through the built clusters.\n sessionWindowData: {cumulativeWindowScore: 0, id: clusters.length},\n },\n };\n currentCluster.events.push(shift);\n updateTraceWindowMax(currentCluster.clusterWindow, event.ts);\n\n lastShiftTime = event.ts;\n lastShiftNavigation = currentShiftNavigation;\n }\n\n // Now step through each cluster and set up the times at which the value\n // goes from Good, to needs improvement, to Bad. Note that if there is a\n // large jump we may go from Good to Bad without ever creating a Needs\n // Improvement window at all.\n for (const cluster of clusters) {\n let weightedScore = 0;\n let windowID = -1;\n // If this is the last cluster update its window. The cluster duration is determined\n // by the minimum between: time to next navigation, trace end time, time to maximum\n // cluster duration and time to maximum gap between layout shifts.\n if (cluster === clusters[clusters.length - 1]) {\n const clusterEndByMaxDuration = MAX_CLUSTER_DURATION + cluster.clusterWindow.min;\n const clusterEndByMaxGap = cluster.clusterWindow.max + MAX_SHIFT_TIME_DELTA;\n const nextNavigationIndex =\n Platform.ArrayUtilities.nearestIndexFromBeginning(navigations, nav => nav.ts > cluster.clusterWindow.max);\n const nextNavigationTime = nextNavigationIndex ? navigations[nextNavigationIndex].ts : Infinity;\n const clusterEnd = Math.min(clusterEndByMaxDuration, clusterEndByMaxGap, traceBounds.max, nextNavigationTime);\n updateTraceWindowMax(cluster.clusterWindow, Types.Timing.MicroSeconds(clusterEnd));\n }\n for (const shift of cluster.events) {\n weightedScore += shift.args.data ? shift.args.data.weighted_score_delta : 0;\n windowID = shift.parsedData.sessionWindowData.id;\n const ts = shift.ts;\n // Update the the CLS score of this shift's session window now that\n // we have it.\n shift.parsedData.sessionWindowData.cumulativeWindowScore = cluster.clusterCumulativeScore;\n if (weightedScore < LayoutShiftsThreshold.NEEDS_IMPROVEMENT) {\n // Expand the Good window.\n updateTraceWindowMax(cluster.scoreWindows.good, ts);\n } else if (\n weightedScore >= LayoutShiftsThreshold.NEEDS_IMPROVEMENT && weightedScore < LayoutShiftsThreshold.BAD) {\n if (!cluster.scoreWindows.needsImprovement) {\n // Close the Good window, and open the needs improvement window.\n updateTraceWindowMax(cluster.scoreWindows.good, Types.Timing.MicroSeconds(ts - 1));\n cluster.scoreWindows.needsImprovement = traceWindowFromTime(ts);\n }\n\n // Expand the needs improvement window.\n updateTraceWindowMax(cluster.scoreWindows.needsImprovement, ts);\n } else if (weightedScore >= LayoutShiftsThreshold.BAD) {\n if (!cluster.scoreWindows.bad) {\n // We may jump from Good to Bad here, so update whichever window is open.\n if (cluster.scoreWindows.needsImprovement) {\n updateTraceWindowMax(cluster.scoreWindows.needsImprovement, Types.Timing.MicroSeconds(ts - 1));\n } else {\n updateTraceWindowMax(cluster.scoreWindows.good, Types.Timing.MicroSeconds(ts - 1));\n }\n\n cluster.scoreWindows.bad = traceWindowFromTime(shift.ts);\n }\n\n // Expand the Bad window.\n updateTraceWindowMax(cluster.scoreWindows.bad, ts);\n }\n\n // At this point the windows are set by the timestamps of the events, but the\n // next cluster begins at the timestamp of its first event. As such we now\n // need to expand the score window to the end of the cluster, and we do so\n // by using the Bad widow if it's there, or the NI window, or finally the\n // Good window.\n if (cluster.scoreWindows.bad) {\n updateTraceWindowMax(cluster.scoreWindows.bad, cluster.clusterWindow.max);\n } else if (cluster.scoreWindows.needsImprovement) {\n updateTraceWindowMax(cluster.scoreWindows.needsImprovement, cluster.clusterWindow.max);\n } else {\n updateTraceWindowMax(cluster.scoreWindows.good, cluster.clusterWindow.max);\n }\n }\n if (weightedScore > sessionMaxScore) {\n clsWindowID = windowID;\n sessionMaxScore = weightedScore;\n }\n }\n}\n\nexport function data(): LayoutShifts {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Layout Shifts Handler is not finalized');\n }\n\n return {\n clusters: [...clusters],\n sessionMaxScore: sessionMaxScore,\n clsWindowID,\n prePaintEvents: [...prePaintEvents],\n layoutInvalidationEvents: [...layoutInvalidationEvents],\n styleRecalcInvalidationEvents: [],\n scoreRecords: [...scoreRecords],\n };\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Screenshots', 'Meta'];\n}\n\nexport function stateForLayoutShiftScore(score: number): ScoreClassification {\n let state = ScoreClassification.GOOD;\n if (score >= LayoutShiftsThreshold.NEEDS_IMPROVEMENT) {\n state = ScoreClassification.OK;\n }\n\n if (score >= LayoutShiftsThreshold.BAD) {\n state = ScoreClassification.BAD;\n }\n\n return state;\n}\n\nexport interface LayoutShiftCluster {\n clusterWindow: Types.Timing.TraceWindow;\n clusterCumulativeScore: number;\n events: Types.TraceEvents.SyntheticLayoutShift[];\n // For convenience we split apart the cluster into good, NI, and bad windows.\n // Since a cluster may remain in the good window, we mark NI and bad as being\n // possibly null.\n scoreWindows: {\n good: Types.Timing.TraceWindow,\n needsImprovement: Types.Timing.TraceWindow|null,\n bad: Types.Timing.TraceWindow|null,\n };\n}\n\n// Based on https://web.dev/cls/\nexport const enum LayoutShiftsThreshold {\n GOOD = 0,\n NEEDS_IMPROVEMENT = 0.1,\n BAD = 0.25,\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * This handler stores page load metrics, including web vitals,\n * and exports them in the shape of a map with the following shape:\n * Map(FrameId -> Map(navigationID -> metrics) )\n *\n * It also exports all markers in a trace in an array.\n *\n * Some metrics are taken directly from a page load events (AKA markers) like DCL.\n * Others require processing multiple events to be determined, like CLS and TBT.\n */\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\n\nimport {type TraceEventHandlerName} from './types.js';\n\nimport * as Types from '../types/types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\n\n/**\n * This represents the metric scores for all navigations, for all frames in a trace.\n * Given a frame id, the map points to another map from navigation id to metric scores.\n * The metric scores include the event related to the metric as well as the data regarding\n * the score itself.\n */\nconst metricScoresByFrameId =\n new Map</* Frame id */ string, Map</* navigation id */ string, Map<MetricName, MetricScore>>>();\n\n/**\n * Page load events with no associated duration that happened in the\n * main frame.\n */\nlet allMarkerEvents: Types.TraceEvents.PageLoadEvent[] = [];\n\nexport function reset(): void {\n metricScoresByFrameId.clear();\n pageLoadEventsArray = [];\n allMarkerEvents = [];\n selectedLCPCandidateEvents.clear();\n}\n\nlet pageLoadEventsArray: Types.TraceEvents.PageLoadEvent[] = [];\n\n// Once we've found the LCP events in the trace we want to fetch their DOM Node\n// from the backend. We could do this by parsing through our Map of frame =>\n// navigation => metric, but it's easier to keep a set of LCP events. As we\n// parse the trace, any time we store an LCP candidate as the potential LCP\n// event, we store the event here. If we later find a new candidate in the\n// trace, we store that and delete the prior event. When we've parsed the\n// entire trace this set will contain all the LCP events that were used - e.g.\n// the candidates that were the actual LCP events.\nconst selectedLCPCandidateEvents = new Set<Types.TraceEvents.TraceEventLargestContentfulPaintCandidate>();\n\nexport const MarkerName =\n ['MarkDOMContent', 'MarkLoad', 'firstPaint', 'firstContentfulPaint', 'largestContentfulPaint::Candidate'] as const;\n\nconst markerTypeGuards = [\n Types.TraceEvents.isTraceEventMarkDOMContent,\n Types.TraceEvents.isTraceEventMarkLoad,\n Types.TraceEvents.isTraceEventFirstPaint,\n Types.TraceEvents.isTraceEventFirstContentfulPaint,\n Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate,\n Types.TraceEvents.isTraceEventNavigationStart,\n];\n\ninterface MakerEvent extends Types.TraceEvents.TraceEventData {\n name: typeof MarkerName[number];\n}\n\nexport function isTraceEventMarkerEvent(event: Types.TraceEvents.TraceEventData): event is MakerEvent {\n return markerTypeGuards.some(fn => fn(event));\n}\n\nconst pageLoadEventTypeGuards = [\n ...markerTypeGuards,\n Types.TraceEvents.isTraceEventInteractiveTime,\n];\n\nexport function eventIsPageLoadEvent(event: Types.TraceEvents.TraceEventData):\n event is Types.TraceEvents.PageLoadEvent {\n return pageLoadEventTypeGuards.some(fn => fn(event));\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (!eventIsPageLoadEvent(event)) {\n return;\n }\n pageLoadEventsArray.push(event);\n}\n\nfunction storePageLoadMetricAgainstNavigationId(\n navigation: Types.TraceEvents.TraceEventNavigationStart, event: Types.TraceEvents.PageLoadEvent): void {\n const navigationId = navigation.args.data?.navigationId;\n if (!navigationId) {\n throw new Error('Navigation event unexpectedly had no navigation ID.');\n }\n const frameId = getFrameIdForPageLoadEvent(event);\n const {rendererProcessesByFrame} = metaHandlerData();\n\n // If either of these pieces of data do not exist, the most likely\n // explanation is that the page load metric we found is for a frame/process\n // combo that the MetaHandler discarded. This typically happens if we get a\n // navigation event with an empty URL. Therefore, we will silently return and\n // drop this metric. If we didn't care about the navigation, we certainly do\n // not need to care about metrics for that navigation.\n const rendererProcessesInFrame = rendererProcessesByFrame.get(frameId);\n if (!rendererProcessesInFrame) {\n return;\n }\n const processData = rendererProcessesInFrame.get(event.pid);\n if (!processData) {\n return;\n }\n\n if (Types.TraceEvents.isTraceEventNavigationStart(event)) {\n return;\n }\n\n // We compare the timestamp of the event to determine if it happened during the\n // time window in which its process was considered active.\n const minTime = processData[0].window.min;\n const maxTime = processData.at(-1)?.window.max || 0;\n const eventBelongsToProcess = event.ts >= minTime && event.ts <= maxTime;\n\n if (!eventBelongsToProcess) {\n // If the event occurred outside its process' active time window we ignore it.\n return;\n }\n\n if (Types.TraceEvents.isTraceEventFirstContentfulPaint(event)) {\n const fcpTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const score = Helpers.Timing.formatMicrosecondsTime(fcpTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const classification = scoreClassificationForFirstContentfulPaint(fcpTime);\n const metricScore = {event, score, metricName: MetricName.FCP, classification, navigation};\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventFirstPaint(event)) {\n const paintTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const score = Helpers.Timing.formatMicrosecondsTime(paintTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const classification = ScoreClassification.UNCLASSIFIED;\n const metricScore = {event, score, metricName: MetricName.FP, classification, navigation};\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventMarkDOMContent(event)) {\n const dclTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const score = Helpers.Timing.formatMicrosecondsTime(dclTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const metricScore = {\n event,\n score,\n metricName: MetricName.DCL,\n classification: scoreClassificationForDOMContentLoaded(dclTime),\n navigation,\n };\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventInteractiveTime(event)) {\n const ttiValue = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const ttiScore = Helpers.Timing.formatMicrosecondsTime(ttiValue, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const tti = {\n event,\n score: ttiScore,\n metricName: MetricName.TTI,\n classification: scoreClassificationForTimeToInteractive(ttiValue),\n navigation,\n };\n storeMetricScore(frameId, navigationId, tti);\n\n const tbtValue =\n Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(event.args.args.total_blocking_time_ms));\n const tbtScore = Helpers.Timing.formatMicrosecondsTime(tbtValue, {\n format: Types.Timing.TimeUnit.MILLISECONDS,\n maximumFractionDigits: 2,\n });\n const tbt = {\n event,\n score: tbtScore,\n metricName: MetricName.TBT,\n classification: scoreClassificationForTotalBlockingTime(tbtValue),\n navigation,\n };\n storeMetricScore(frameId, navigationId, tbt);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventMarkLoad(event)) {\n const loadTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const score = Helpers.Timing.formatMicrosecondsTime(loadTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const metricScore = {\n event,\n score,\n metricName: MetricName.L,\n classification: ScoreClassification.UNCLASSIFIED,\n navigation,\n };\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(event)) {\n const candidateIndex = event.args.data?.candidateIndex;\n if (!candidateIndex) {\n throw new Error('Largest Contenful Paint unexpectedly had no candidateIndex.');\n }\n const lcpTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const lcpScore = Helpers.Timing.formatMicrosecondsTime(lcpTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const lcp = {\n event,\n score: lcpScore,\n metricName: MetricName.LCP,\n classification: scoreClassificationForLargestContentfulPaint(lcpTime),\n navigation,\n };\n const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());\n const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());\n const lastLCPCandidate = metrics.get(MetricName.LCP);\n if (lastLCPCandidate === undefined) {\n selectedLCPCandidateEvents.add(lcp.event);\n storeMetricScore(frameId, navigationId, lcp);\n return;\n }\n const lastLCPCandidateEvent = lastLCPCandidate.event;\n\n if (!Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {\n return;\n }\n const lastCandidateIndex = lastLCPCandidateEvent.args.data?.candidateIndex;\n if (!lastCandidateIndex) {\n // lastCandidateIndex cannot be undefined because we don't store candidates with\n // with an undefined candidateIndex value. This check is only to make TypeScript\n // treat the field as not undefined below.\n return;\n }\n if (lastCandidateIndex < candidateIndex) {\n selectedLCPCandidateEvents.delete(lastLCPCandidateEvent);\n selectedLCPCandidateEvents.add(lcp.event);\n storeMetricScore(frameId, navigationId, lcp);\n }\n return;\n }\n if (Types.TraceEvents.isTraceEventLayoutShift(event)) {\n return;\n }\n return Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\nfunction storeMetricScore(frameId: string, navigationId: string, metricScore: MetricScore): void {\n const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());\n const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());\n // If an entry with that metric name is present, delete it so that the new entry that\n // will replace it is added at the end of the map. This way we guarantee the map entries\n // are ordered in ASC manner by timestamp.\n metrics.delete(metricScore.metricName);\n metrics.set(metricScore.metricName, metricScore);\n}\n\nexport function getFrameIdForPageLoadEvent(event: Types.TraceEvents.PageLoadEvent): string {\n if (Types.TraceEvents.isTraceEventFirstContentfulPaint(event) ||\n Types.TraceEvents.isTraceEventInteractiveTime(event) ||\n Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(event) ||\n Types.TraceEvents.isTraceEventNavigationStart(event) || Types.TraceEvents.isTraceEventLayoutShift(event) ||\n Types.TraceEvents.isTraceEventFirstPaint(event)) {\n return event.args.frame;\n }\n if (Types.TraceEvents.isTraceEventMarkDOMContent(event) || Types.TraceEvents.isTraceEventMarkLoad(event)) {\n const frameId = event.args.data?.frame;\n if (!frameId) {\n throw new Error('MarkDOMContent unexpectedly had no frame ID.');\n }\n return frameId;\n }\n Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\nfunction getNavigationForPageLoadEvent(event: Types.TraceEvents.PageLoadEvent):\n Types.TraceEvents.TraceEventNavigationStart|null {\n if (Types.TraceEvents.isTraceEventFirstContentfulPaint(event) ||\n Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(event) ||\n Types.TraceEvents.isTraceEventFirstPaint(event)) {\n const navigationId = event.args.data?.navigationId;\n if (!navigationId) {\n throw new Error('Trace event unexpectedly had no navigation ID.');\n }\n const {navigationsByNavigationId} = metaHandlerData();\n const navigation = navigationsByNavigationId.get(navigationId);\n\n if (!navigation) {\n // This event's navigation has been filtered out by the meta handler as a noise event.\n return null;\n }\n return navigation;\n }\n\n if (Types.TraceEvents.isTraceEventMarkDOMContent(event) || Types.TraceEvents.isTraceEventInteractiveTime(event) ||\n Types.TraceEvents.isTraceEventLayoutShift(event) || Types.TraceEvents.isTraceEventMarkLoad(event)) {\n const frameId = getFrameIdForPageLoadEvent(event);\n const {navigationsByFrameId} = metaHandlerData();\n return Helpers.Trace.getNavigationForTraceEvent(event, frameId, navigationsByFrameId);\n }\n\n if (Types.TraceEvents.isTraceEventNavigationStart(event)) {\n // We don't want to compute metrics of the navigation relative to itself, so we'll avoid avoid all that.\n return null;\n }\n\n return Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/fcp/\n */\nexport function scoreClassificationForFirstContentfulPaint(fcpScoreInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n const FCP_GOOD_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(1.8));\n const FCP_MEDIUM_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(3.0));\n let scoreClassification = ScoreClassification.BAD;\n if (fcpScoreInMicroseconds <= FCP_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (fcpScoreInMicroseconds <= FCP_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/interactive/#how-lighthouse-determines-your-tti-score\n */\n\nexport function scoreClassificationForTimeToInteractive(ttiTimeInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n const TTI_GOOD_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(3.8));\n const TTI_MEDIUM_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(7.3));\n let scoreClassification = ScoreClassification.BAD;\n if (ttiTimeInMicroseconds <= TTI_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (ttiTimeInMicroseconds <= TTI_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/lcp/#what-is-lcp\n */\n\nexport function scoreClassificationForLargestContentfulPaint(lcpTimeInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n const LCP_GOOD_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(2.5));\n const LCP_MEDIUM_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(4));\n let scoreClassification = ScoreClassification.BAD;\n if (lcpTimeInMicroseconds <= LCP_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (lcpTimeInMicroseconds <= LCP_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * DCL does not have a classification.\n */\nexport function scoreClassificationForDOMContentLoaded(_dclTimeInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n return ScoreClassification.UNCLASSIFIED;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/lighthouse-total-blocking-#time/\n */\n\nexport function scoreClassificationForTotalBlockingTime(tbtTimeInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n const TBT_GOOD_TIMING = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(200));\n const TBT_MEDIUM_TIMING = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(600));\n let scoreClassification = ScoreClassification.BAD;\n if (tbtTimeInMicroseconds <= TBT_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (tbtTimeInMicroseconds <= TBT_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Gets all the Largest Contentful Paint scores of all the frames in the\n * trace.\n */\nfunction gatherFinalLCPEvents(): Types.TraceEvents.PageLoadEvent[] {\n const allFinalLCPEvents: Types.TraceEvents.PageLoadEvent[] = [];\n const dataForAllFrames = [...metricScoresByFrameId.values()];\n const dataForAllNavigations = dataForAllFrames.flatMap(frameData => [...frameData.values()]);\n for (let i = 0; i < dataForAllNavigations.length; i++) {\n const navigationData = dataForAllNavigations[i];\n const lcpInNavigation = navigationData.get(MetricName.LCP);\n if (!lcpInNavigation || !lcpInNavigation.event) {\n continue;\n }\n\n allFinalLCPEvents.push(lcpInNavigation.event);\n }\n return allFinalLCPEvents;\n}\n\nexport async function finalize(): Promise<void> {\n pageLoadEventsArray.sort((a, b) => a.ts - b.ts);\n\n for (const pageLoadEvent of pageLoadEventsArray) {\n const navigation = getNavigationForPageLoadEvent(pageLoadEvent);\n if (navigation) {\n // Event's navigation was not filtered out as noise.\n storePageLoadMetricAgainstNavigationId(navigation, pageLoadEvent);\n }\n }\n // NOTE: if you are looking for the TBT calculation, it has temporarily been\n // removed. See crbug.com/1424335 for details.\n const allFinalLCPEvents = gatherFinalLCPEvents();\n const mainFrame = metaHandlerData().mainFrameId;\n // Filter out LCP candidates to use only definitive LCP values\n const allEventsButLCP =\n pageLoadEventsArray.filter(event => !Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(event));\n const markerEvents = [...allFinalLCPEvents, ...allEventsButLCP].filter(isTraceEventMarkerEvent);\n // Filter by main frame and sort.\n allMarkerEvents =\n markerEvents.filter(event => getFrameIdForPageLoadEvent(event) === mainFrame).sort((a, b) => a.ts - b.ts);\n}\n\nexport type PageLoadMetricsData = {\n metricScoresByFrameId: Map<string, Map<string, Map<MetricName, MetricScore>>>,\n allMarkerEvents: Types.TraceEvents.PageLoadEvent[],\n};\n\nexport function data(): PageLoadMetricsData {\n return {\n /**\n * This represents the metric scores for all navigations, for all frames in a trace.\n * Given a frame id, the map points to another map from navigation id to metric scores.\n * The metric scores include the event related to the metric as well as the data regarding\n * the score itself.\n */\n metricScoresByFrameId: new Map(metricScoresByFrameId),\n\n /**\n * Page load events with no associated duration that happened in the\n * main frame.\n */\n allMarkerEvents: [...allMarkerEvents],\n };\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta'];\n}\n\nexport const enum ScoreClassification {\n GOOD = 'good',\n OK = 'ok',\n BAD = 'bad',\n // Some metrics (such as DOMContentLoaded) don't have a Good/OK/Bad classification, hence this additional entry.\n UNCLASSIFIED = 'unclassified',\n}\n\nexport const enum MetricName {\n // First Contentful Paint\n FCP = 'FCP',\n // First Paint\n FP = 'FP',\n // MarkLoad\n L = 'L',\n LCP = 'LCP',\n // Mark DOM Content\n DCL = 'DCL',\n // Time To Interactive\n TTI = 'TTI',\n // Total Blocking Time\n TBT = 'TBT',\n // Cumulative Layout Shift\n CLS = 'CLS',\n}\n\nexport interface MetricScore {\n score: string;\n metricName: MetricName;\n classification: ScoreClassification;\n event?: Types.TraceEvents.PageLoadEvent;\n // The last navigation that occured before this metric score.\n navigation?: Types.TraceEvents.TraceEventNavigationStart;\n estimated?: boolean;\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport {type TraceEventHandlerName} from './types.js';\n\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\n// Each thread contains events. Events indicate the thread and process IDs, which are\n// used to store the event in the correct process thread entry below.\nconst eventsInProcessThread =\n new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventSnapshot[]>>();\n\nlet snapshots: Types.TraceEvents.TraceEventSnapshot[] = [];\nexport function reset(): void {\n eventsInProcessThread.clear();\n snapshots.length = 0;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (event.ph !== Types.TraceEvents.Phase.OBJECT_SNAPSHOT || event.name !== 'Screenshot') {\n return;\n }\n\n Helpers.Trace.addEventToProcessThread(event, eventsInProcessThread);\n}\n\nexport async function finalize(): Promise<void> {\n const {browserProcessId, browserThreadId} = metaHandlerData();\n const browserThreads = eventsInProcessThread.get(browserProcessId);\n if (browserThreads) {\n snapshots = browserThreads.get(browserThreadId) || [];\n }\n}\n\nexport function data(): Types.TraceEvents.TraceEventSnapshot[] {\n return [...snapshots];\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta'];\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Types from '../types/types.js';\n\nexport interface MemoryData {\n updateCountersByProcess: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventUpdateCounters[]>;\n}\n\nconst updateCountersByProcess: MemoryData['updateCountersByProcess'] = new Map();\n\nexport function reset(): void {\n updateCountersByProcess.clear();\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (Types.TraceEvents.isTraceEventUpdateCounters(event)) {\n const countersForProcess = Platform.MapUtilities.getWithDefault(updateCountersByProcess, event.pid, () => []);\n countersForProcess.push(event);\n updateCountersByProcess.set(event.pid, countersForProcess);\n }\n}\n\nexport function data(): MemoryData {\n return {updateCountersByProcess: new Map(updateCountersByProcess)};\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport {type TraceEventHandlerName, HandlerState} from './types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport * as Helpers from '../helpers/helpers.js';\n\nimport * as Types from '../types/types.js';\n\nconst MILLISECONDS_TO_MICROSECONDS = 1000;\nconst SECONDS_TO_MICROSECONDS = 1000000;\n\n// Network requests from traces are actually formed of 5 trace records.\n// This handler tracks all trace records based on the request ID, and\n// then creates a new synthetic trace event for those network requests.\n//\n// This interface, then, defines the shape of the object we intend to\n// keep for each request in the trace. In the finalize we will convert\n// these 5 types of trace records to a synthetic complete event that\n// represents a composite of these trace records.\ninterface TraceEventsForNetworkRequest {\n changePriority?: Types.TraceEvents.TraceEventResourceChangePriority;\n willSendRequests?: Types.TraceEvents.TraceEventResourceWillSendRequest[];\n sendRequests?: Types.TraceEvents.TraceEventResourceSendRequest[];\n receiveResponse?: Types.TraceEvents.TraceEventResourceReceiveResponse;\n resourceFinish?: Types.TraceEvents.TraceEventResourceFinish;\n receivedData?: Types.TraceEvents.TraceEventResourceReceivedData[];\n resourceMarkAsCached?: Types.TraceEvents.TraceEventResourceMarkAsCached;\n}\n\ninterface NetworkRequestData {\n byOrigin: Map<string, {\n renderBlocking: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n nonRenderBlocking: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n all: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n }>;\n byTime: Types.TraceEvents.TraceEventSyntheticNetworkRequest[];\n}\n\nconst requestMap = new Map<string, TraceEventsForNetworkRequest>();\nconst requestsByOrigin = new Map<string, {\n renderBlocking: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n nonRenderBlocking: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n all: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n}>();\nconst requestsByTime: Types.TraceEvents.TraceEventSyntheticNetworkRequest[] = [];\n\nfunction storeTraceEventWithRequestId<K extends keyof TraceEventsForNetworkRequest>(\n requestId: string, key: K, value: TraceEventsForNetworkRequest[K]): void {\n if (!requestMap.has(requestId)) {\n requestMap.set(requestId, {});\n }\n\n const traceEvents = requestMap.get(requestId);\n if (!traceEvents) {\n throw new Error(`Unable to locate trace events for request ID ${requestId}`);\n }\n\n if (Array.isArray(traceEvents[key])) {\n const target = traceEvents[key] as Types.TraceEvents.TraceEventData[];\n const values = value as Types.TraceEvents.TraceEventData[];\n target.push(...values);\n } else {\n traceEvents[key] = value;\n }\n}\n\nfunction firstPositiveValueInList(entries: number[]): number {\n for (const entry of entries) {\n if (entry > 0) {\n return entry;\n }\n }\n\n // In the event we don't find a positive value, we return 0 so as to\n // be a mathematical noop. It's typically not correct to return \u2013 say \u2013\n // a -1 here because it would affect the calculation of stats below.\n return 0;\n}\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function reset(): void {\n requestsByOrigin.clear();\n requestMap.clear();\n requestsByTime.length = 0;\n\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Network Request handler is not initialized');\n }\n\n if (Types.TraceEvents.isTraceEventResourceChangePriority(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'changePriority', event);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceWillSendRequest(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'willSendRequests', [event]);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceSendRequest(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'sendRequests', [event]);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceReceiveResponse(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'receiveResponse', event);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceReceivedData(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'receivedData', [event]);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceFinish(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'resourceFinish', event);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceMarkAsCached(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'resourceMarkAsCached', event);\n return;\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Network Request handler is not initialized');\n }\n\n const {rendererProcessesByFrame} = metaHandlerData();\n for (const [requestId, request] of requestMap.entries()) {\n // If we have an incomplete set of events here, we choose to drop the network\n // request rather than attempt to synthesize the missing data.\n if (!request.sendRequests || !request.receiveResponse) {\n continue;\n }\n\n // In the data we may get multiple willSendRequests and sendRequests, which\n // will indicate that there are redirects for a given (sub)resource. In the\n // case of a navigation, e.g., example.com/ we will get willSendRequests,\n // and we should use these to calculate time spent in redirects.\n // In the case of sub-resources, however, e.g., example.com/foo.js we will\n // *only* get sendRequests, and we use these instead of willSendRequests\n // to detect the time in redirects. We always use the sendRequest for the\n // url, priority etc since it contains those values, but we use the\n // willSendRequest (if it exists) to calculate the timestamp and durations\n // of redirects.\n const redirects: Types.TraceEvents.TraceEventSyntheticNetworkRedirect[] = [];\n for (let i = 0; i < request.sendRequests.length - 1; i++) {\n const sendRequest = request.sendRequests[i];\n const nextSendRequest = request.sendRequests[i + 1];\n\n // Use the willSendRequests as the source for redirects if possible.\n // We default to those of the sendRequests, however, since willSendRequest\n // is not guaranteed to be present in the data for every request.\n let ts = sendRequest.ts;\n let dur = Types.Timing.MicroSeconds(nextSendRequest.ts - sendRequest.ts);\n if (request.willSendRequests && request.willSendRequests[i] && request.willSendRequests[i + 1]) {\n const willSendRequest = request.willSendRequests[i];\n const nextWillSendRequest = request.willSendRequests[i + 1];\n ts = willSendRequest.ts;\n dur = Types.Timing.MicroSeconds(nextWillSendRequest.ts - willSendRequest.ts);\n }\n\n redirects.push({\n url: sendRequest.args.data.url,\n priority: sendRequest.args.data.priority,\n requestMethod: sendRequest.args.data.requestMethod,\n ts,\n dur,\n });\n }\n\n // If a ResourceFinish event with an encoded data length is received,\n // then the resource was not cached; it was fetched before it was\n // requested, e.g. because it was pushed in this navigation.\n const isPushedResource = request.resourceFinish?.args.data.encodedDataLength !== 0;\n // This works around crbug.com/998397, which reports pushed resources, and resources served by a service worker as disk cached.\n const isDiskCached = request.receiveResponse.args.data.fromCache &&\n !request.receiveResponse.args.data.fromServiceWorker && !isPushedResource;\n // If the request contains a resourceMarkAsCached event, it was served from memory cache.\n const isMemoryCached = request.resourceMarkAsCached !== undefined;\n\n // The timing data returned is from the original (uncached) request, which\n // means that if we leave the above network record data as-is when the\n // request came from either the disk cache or memory cache, our calculations\n // will be incorrect.\n //\n // Here we add a flag so when we calculate the timestamps of the various\n // events, we can overwrite them.\n // These timestamps may not be perfect (indeed they don't always match\n // the Network CDP domain exactly, which is likely an artifact of the way\n // the data is routed on the backend), but they're the closest we have.\n const isCached = isMemoryCached || isDiskCached;\n\n const timing = request.receiveResponse.args.data.timing;\n // If a non-cached request has no |timing| indicates data URLs, we ignore it.\n if (!timing && !isCached) {\n continue;\n }\n\n const firstSendRequest = request.sendRequests[0];\n const finalSendRequest = request.sendRequests[request.sendRequests.length - 1];\n\n const initialPriority = finalSendRequest.args.data.priority;\n let finalPriority = initialPriority;\n if (request.changePriority) {\n finalPriority = request.changePriority.args.data.priority;\n }\n\n // Start time\n // =======================\n // The time where the request started, which is either the first willSendRequest\n // event if there is one, or, if there is not, the sendRequest.\n const startTime = (request.willSendRequests && request.willSendRequests.length) ?\n Types.Timing.MicroSeconds(request.willSendRequests[0].ts) :\n Types.Timing.MicroSeconds(firstSendRequest.ts);\n\n // End redirect time\n // =======================\n // It's possible that when we start requesting data we will receive redirections.\n // Here we note the time of the *last* willSendRequest / sendRequest event,\n // which is used later on in the calculations for time queueing etc.\n const endRedirectTime = (request.willSendRequests && request.willSendRequests.length) ?\n Types.Timing.MicroSeconds(request.willSendRequests[request.willSendRequests.length - 1].ts) :\n Types.Timing.MicroSeconds(finalSendRequest.ts);\n\n // Finish time and end time\n // =======================\n // The finish time and the end time are subtly different.\n // - Finish time: records the point at which the network stack stopped receiving the data\n // - End time: the timestamp of the finish event itself (if one exists)\n //\n // The end time, then, will be slightly after the finish time.\n const endTime = request.resourceFinish ? request.resourceFinish.ts : endRedirectTime;\n const finishTime = request.resourceFinish?.args.data.finishTime ?\n Types.Timing.MicroSeconds(request.resourceFinish.args.data.finishTime * SECONDS_TO_MICROSECONDS) :\n Types.Timing.MicroSeconds(endTime);\n\n // Network duration\n // =======================\n // Time spent on the network.\n const networkDuration = isCached ? Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((finishTime || endRedirectTime) - endRedirectTime);\n\n // Processing duration\n // =======================\n // Time spent from start to end.\n const processingDuration = Types.Timing.MicroSeconds(endTime - (finishTime || endTime));\n\n // Redirection duration\n // =======================\n // Time between the first willSendRequest / sendRequest and last. This we place in *front* of the\n // queueing, since the queueing time that we know about from the trace data is only the last request,\n // i.e., the one that occurs after all the redirects.\n const redirectionDuration = Types.Timing.MicroSeconds(endRedirectTime - startTime);\n\n // Queueing\n // =======================\n // The amount of time queueing is the time between the request's start time to the requestTime\n // arg recorded in the receiveResponse event. In the cases where the recorded start time is larger\n // that the requestTime we set queueing time to zero.\n const queueing = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds(Platform.NumberUtilities.clamp(\n (timing.requestTime * SECONDS_TO_MICROSECONDS - endRedirectTime), 0, Number.MAX_VALUE));\n\n // Stalled\n // =======================\n // If the request is cached, the amount of time stalled is the time between the start time and\n // receiving a response.\n // Otherwise it is whichever positive number comes first from the following timing info:\n // DNS start, Connection start, Send Start, or the time duration between our start time and\n // receiving a response.\n const stalled = isCached ? Types.Timing.MicroSeconds(request.receiveResponse.ts - startTime) :\n Types.Timing.MicroSeconds(firstPositiveValueInList([\n timing.dnsStart * MILLISECONDS_TO_MICROSECONDS,\n timing.connectStart * MILLISECONDS_TO_MICROSECONDS,\n timing.sendStart * MILLISECONDS_TO_MICROSECONDS,\n (request.receiveResponse.ts - endRedirectTime),\n ]));\n\n // Sending HTTP request\n // =======================\n // Time when the HTTP request is sent.\n const sendStartTime = isCached ?\n startTime :\n Types.Timing.MicroSeconds(\n timing.requestTime * SECONDS_TO_MICROSECONDS + timing.sendStart * MILLISECONDS_TO_MICROSECONDS);\n\n // Waiting\n // =======================\n // Time from when the send finished going to when the headers were received.\n const waiting = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.receiveHeadersEnd - timing.sendEnd) * MILLISECONDS_TO_MICROSECONDS);\n\n // Download\n // =======================\n // Time from receipt of headers to the finish time.\n const downloadStart = isCached ?\n startTime :\n Types.Timing.MicroSeconds(\n timing.requestTime * SECONDS_TO_MICROSECONDS + timing.receiveHeadersEnd * MILLISECONDS_TO_MICROSECONDS);\n const download = isCached ? Types.Timing.MicroSeconds(endTime - request.receiveResponse.ts) :\n Types.Timing.MicroSeconds(((finishTime || downloadStart) - downloadStart));\n\n const totalTime = Types.Timing.MicroSeconds(networkDuration + processingDuration);\n\n // Collect a few values from the timing info.\n // If the Network request is cached, we zero out them.\n const dnsLookup = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.dnsEnd - timing.dnsStart) * MILLISECONDS_TO_MICROSECONDS);\n const ssl = isCached ? Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.sslEnd - timing.sslStart) * MILLISECONDS_TO_MICROSECONDS);\n const proxyNegotiation = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.proxyEnd - timing.proxyStart) * MILLISECONDS_TO_MICROSECONDS);\n const requestSent = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.sendEnd - timing.sendStart) * MILLISECONDS_TO_MICROSECONDS);\n const initialConnection = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.connectEnd - timing.connectStart) * MILLISECONDS_TO_MICROSECONDS);\n\n // Finally get some of the general data from the trace events.\n const {frame, url, renderBlocking} = finalSendRequest.args.data;\n const {encodedDataLength, decodedBodyLength} =\n request.resourceFinish ? request.resourceFinish.args.data : {encodedDataLength: 0, decodedBodyLength: 0};\n const {host, protocol, pathname, search} = new URL(url);\n const isHttps = protocol === 'https:';\n const requestingFrameUrl =\n Helpers.Trace.activeURLForFrameAtTime(frame, finalSendRequest.ts, rendererProcessesByFrame) || '';\n\n // Construct a synthetic trace event for this network request.\n const networkEvent: Types.TraceEvents.TraceEventSyntheticNetworkRequest = {\n args: {\n data: {\n // All data we create from trace events should be added to |syntheticData|.\n syntheticData: {\n dnsLookup,\n download,\n downloadStart,\n finishTime,\n initialConnection,\n isDiskCached,\n isHttps,\n isMemoryCached,\n isPushedResource,\n networkDuration,\n processingDuration,\n proxyNegotiation,\n queueing,\n redirectionDuration,\n requestSent,\n sendStartTime,\n ssl,\n stalled,\n totalTime,\n waiting,\n },\n // All fields below are from TraceEventsForNetworkRequest.\n decodedBodyLength,\n encodedDataLength,\n frame,\n fromServiceWorker: request.receiveResponse.args.data.fromServiceWorker,\n host,\n mimeType: request.receiveResponse.args.data.mimeType,\n pathname,\n priority: finalPriority,\n initialPriority,\n protocol,\n redirects,\n // In the event the property isn't set, assume non-blocking.\n renderBlocking: renderBlocking ? renderBlocking : 'non_blocking',\n requestId,\n requestingFrameUrl,\n requestMethod: finalSendRequest.args.data.requestMethod,\n search,\n statusCode: request.receiveResponse.args.data.statusCode,\n stackTrace: finalSendRequest.args.data.stackTrace,\n timing,\n url,\n },\n },\n cat: 'loading',\n name: 'SyntheticNetworkRequest',\n ph: Types.TraceEvents.Phase.COMPLETE,\n dur: Types.Timing.MicroSeconds(endTime - startTime),\n tdur: Types.Timing.MicroSeconds(endTime - startTime),\n ts: Types.Timing.MicroSeconds(startTime),\n tts: Types.Timing.MicroSeconds(startTime),\n pid: finalSendRequest.pid,\n tid: finalSendRequest.tid,\n };\n\n const requests = Platform.MapUtilities.getWithDefault(requestsByOrigin, host, () => {\n return {\n renderBlocking: [],\n nonRenderBlocking: [],\n all: [],\n };\n });\n\n // For ease of rendering we sometimes want to differentiate between\n // render-blocking and non-render-blocking, so we divide the data here.\n if (networkEvent.args.data.renderBlocking === 'non_blocking') {\n requests.nonRenderBlocking.push(networkEvent);\n } else {\n requests.renderBlocking.push(networkEvent);\n }\n\n // However, there are also times where we just want to loop through all\n // the captured requests, so here we store all of them together.\n requests.all.push(networkEvent);\n requestsByTime.push(networkEvent);\n }\n\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): NetworkRequestData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Network Request handler is not finalized');\n }\n\n return {\n byOrigin: new Map(requestsByOrigin),\n byTime: [...requestsByTime],\n };\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta'];\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\n// This handler serves two purposes. It generates a list of events that are\n// used to show user clicks in the timeline. It is also used to gather\n// EventTimings into Interactions, which we use to show interactions and\n// highlight long interactions to the user, along with INP.\n\n// We don't need to know which process / thread these events occurred in,\n// because they are effectively global, so we just track all that we find.\nconst allEvents: Types.TraceEvents.TraceEventEventTiming[] = [];\n\nexport const LONG_INTERACTION_THRESHOLD = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(200));\n\nexport interface UserInteractionsData {\n /** All the user events we found in the trace */\n allEvents: readonly Types.TraceEvents.TraceEventEventTiming[];\n /** All the interaction events we found in the trace that had an\n * interactionId and a duration > 0\n **/\n interactionEvents: readonly Types.TraceEvents.SyntheticInteractionEvent[];\n /** If the user rapidly generates interaction events (think typing into a\n * text box), in the UI we only really want to show the user the longest\n * interaction in that set.\n * For example picture interactions like this:\n * ===[interaction A]==========\n * =[interaction B]======\n * =[interaction C]=\n *\n * These events all end at the same time, and so in this instance we only want\n * to show the first interaction A on the timeline, as that is the longest one\n * and the one the developer should be focusing on. So this array of events is\n * all the interaction events filtered down, removing any nested interactions\n * entirely.\n **/\n interactionEventsWithNoNesting: readonly Types.TraceEvents.SyntheticInteractionEvent[];\n // The longest duration interaction event. Can be null if the trace has no interaction events.\n longestInteractionEvent: Readonly<Types.TraceEvents.SyntheticInteractionEvent>|null;\n // All interactions that went over the interaction threshold (200ms, see https://web.dev/inp/)\n interactionsOverThreshold: Readonly<Set<Types.TraceEvents.SyntheticInteractionEvent>>;\n}\n\nlet longestInteractionEvent: Types.TraceEvents.SyntheticInteractionEvent|null = null;\n\nconst interactionEvents: Types.TraceEvents.SyntheticInteractionEvent[] = [];\nconst interactionEventsWithNoNesting: Types.TraceEvents.SyntheticInteractionEvent[] = [];\nconst eventTimingEndEventsById = new Map<string, Types.TraceEvents.TraceEventEventTimingEnd>();\nconst eventTimingStartEventsForInteractions: Types.TraceEvents.TraceEventEventTimingBegin[] = [];\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function reset(): void {\n allEvents.length = 0;\n interactionEvents.length = 0;\n eventTimingStartEventsForInteractions.length = 0;\n eventTimingEndEventsById.clear();\n interactionEventsWithNoNesting.length = 0;\n longestInteractionEvent = null;\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Handler is not initialized');\n }\n\n if (!Types.TraceEvents.isTraceEventEventTiming(event)) {\n return;\n }\n\n if (Types.TraceEvents.isTraceEventEventTimingEnd(event)) {\n // Store the end event; for each start event that is an interaction, we need the matching end event to calculate the duration correctly.\n eventTimingEndEventsById.set(event.id, event);\n }\n\n allEvents.push(event);\n\n // From this point on we want to find events that represent interactions.\n // These events are always start events - those are the ones that contain all\n // the metadata about the interaction.\n if (!event.args.data || !Types.TraceEvents.isTraceEventEventTimingStart(event)) {\n return;\n }\n const {duration, interactionId} = event.args.data;\n // We exclude events for the sake of interactions if:\n // 1. They have no duration.\n // 2. They have no interactionId\n // 3. They have an interactionId of 0: this indicates that it's not an\n // interaction that we care about because it hasn't had its own interactionId\n // set (0 is the default on the backend).\n // See: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/timing/responsiveness_metrics.cc;l=133;drc=40c209a9c365ebb9f16fb99dfe78c7fe768b9594\n\n if (duration < 1 || interactionId === undefined || interactionId === 0) {\n return;\n }\n\n // Store the start event. In the finalize() function we will pair this with\n // its end event and create the synthetic interaction event.\n eventTimingStartEventsForInteractions.push(event);\n}\n\n/**\n * See https://web.dev/better-responsiveness-metric/#interaction-types for the\n * table that defines these sets.\n **/\nconst pointerEventTypes = new Set([\n 'pointerdown',\n 'touchstart',\n 'pointerup',\n 'touchend',\n 'mousedown',\n 'mouseup',\n 'click',\n]);\n\nconst keyboardEventTypes = new Set([\n 'keydown',\n 'keypress',\n 'keyup',\n]);\n\nexport type InteractionCategory = 'KEYBOARD'|'POINTER'|'OTHER';\nexport function categoryOfInteraction(interaction: Types.TraceEvents.SyntheticInteractionEvent): InteractionCategory {\n if (pointerEventTypes.has(interaction.type)) {\n return 'POINTER';\n }\n if (keyboardEventTypes.has(interaction.type)) {\n return 'KEYBOARD';\n }\n\n return 'OTHER';\n}\n\n/**\n * We define a set of interactions as nested where:\n * 1. Their end times align.\n * 2. The longest interaction's start time is earlier than all other\n * interactions with the same end time.\n * 3. The interactions are of the same category [each interaction is either\n * categorised as keyboard, or pointer.]\n *\n * =============A=[pointerup]=\n * ====B=[pointerdown]=\n * ===C=[pointerdown]==\n * ===D=[pointerup]===\n *\n * In this example, B, C and D are all nested and therefore should not be\n * returned from this function.\n *\n * However, in this example we would only consider B nested (under A) and D\n * nested (under C). A and C both stay because they are of different types.\n * ========A=[keydown]====\n * =======B=[keyup]=====\n * ====C=[pointerdown]=\n * =D=[pointerup]=\n **/\nexport function removeNestedInteractions(interactions: readonly Types.TraceEvents.SyntheticInteractionEvent[]):\n readonly Types.TraceEvents.SyntheticInteractionEvent[] {\n /**\n * Because we nest events only that are in the same category, we store the\n * longest event for a given end time by category.\n **/\n const earliestEventForEndTimePerCategory:\n Record<InteractionCategory, Map<Types.Timing.MicroSeconds, Types.TraceEvents.SyntheticInteractionEvent>> = {\n POINTER: new Map(),\n KEYBOARD: new Map(),\n OTHER: new Map(),\n };\n\n function storeEventIfEarliestForCategoryAndEndTime(interaction: Types.TraceEvents.SyntheticInteractionEvent): void {\n const category = categoryOfInteraction(interaction);\n const mapToUse = earliestEventForEndTimePerCategory[category];\n const endTime = Types.Timing.MicroSeconds(interaction.ts + interaction.dur);\n\n const earliestCurrentEvent = mapToUse.get(endTime);\n if (!earliestCurrentEvent) {\n mapToUse.set(endTime, interaction);\n return;\n }\n if (interaction.ts < earliestCurrentEvent.ts) {\n mapToUse.set(endTime, interaction);\n }\n }\n\n for (const interaction of interactions) {\n storeEventIfEarliestForCategoryAndEndTime(interaction);\n }\n\n // Combine all the events that we have kept from all the per-category event\n // maps back into an array and sort them by timestamp.\n const keptEvents = Object.values(earliestEventForEndTimePerCategory)\n .flatMap(eventsByEndTime => Array.from(eventsByEndTime.values()));\n keptEvents.sort((eventA, eventB) => {\n return eventA.ts - eventB.ts;\n });\n return keptEvents;\n}\n\nexport async function finalize(): Promise<void> {\n // For each interaction start event, find the async end event by the ID, and then create the Synthetic Interaction event.\n for (const interactionStartEvent of eventTimingStartEventsForInteractions) {\n const endEvent = eventTimingEndEventsById.get(interactionStartEvent.id);\n if (!endEvent) {\n // If we cannot find an end event, bail and drop this event.\n continue;\n }\n if (!interactionStartEvent.args.data?.type || !interactionStartEvent.args.data?.interactionId) {\n // A valid interaction event that we care about has to have a type (e.g.\n // pointerdown, keyup).\n //\n // We also need to ensure it has an interactionId. We already checked\n // this in the handleEvent() function, but we do it here also to satisfy\n // TypeScript.\n continue;\n }\n\n const interactionEvent: Types.TraceEvents.SyntheticInteractionEvent = {\n // Use the start event to define the common fields.\n cat: interactionStartEvent.cat,\n name: interactionStartEvent.name,\n pid: interactionStartEvent.pid,\n tid: interactionStartEvent.tid,\n ph: interactionStartEvent.ph,\n args: {\n data: {\n beginEvent: interactionStartEvent,\n endEvent: endEvent,\n },\n },\n ts: interactionStartEvent.ts,\n dur: Types.Timing.MicroSeconds(endEvent.ts - interactionStartEvent.ts),\n type: interactionStartEvent.args.data.type,\n interactionId: interactionStartEvent.args.data.interactionId,\n };\n if (!longestInteractionEvent || longestInteractionEvent.dur < interactionEvent.dur) {\n longestInteractionEvent = interactionEvent;\n }\n interactionEvents.push(interactionEvent);\n }\n\n handlerState = HandlerState.FINALIZED;\n interactionEventsWithNoNesting.push(...removeNestedInteractions(interactionEvents));\n}\n\nexport function data(): UserInteractionsData {\n return {\n allEvents: [...allEvents],\n interactionEvents: [...interactionEvents],\n interactionEventsWithNoNesting: [...interactionEventsWithNoNesting],\n longestInteractionEvent,\n interactionsOverThreshold: new Set(interactionEvents.filter(event => {\n return event.dur > LONG_INTERACTION_THRESHOLD;\n })),\n };\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\n/**\n * IMPORTANT!\n * See UserTimings.md in this directory for some handy documentation on\n * UserTimings and the trace events we parse currently.\n **/\nconst syntheticEvents: Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[] = [];\nconst performanceMeasureEvents: (Types.TraceEvents.TraceEventPerformanceMeasureBegin|\n Types.TraceEvents.TraceEventPerformanceMeasureEnd)[] = [];\nconst performanceMarkEvents: Types.TraceEvents.TraceEventPerformanceMark[] = [];\n\nconst consoleTimings: (Types.TraceEvents.TraceEventConsoleTimeBegin|Types.TraceEvents.TraceEventConsoleTimeEnd)[] = [];\n\nconst timestampEvents: Types.TraceEvents.TraceEventTimeStamp[] = [];\n\nexport interface UserTimingsData {\n /**\n * Events triggered with the performance.measure() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure\n */\n performanceMeasures: readonly Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[];\n /**\n * Events triggered with the performance.mark() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark\n */\n performanceMarks: readonly Types.TraceEvents.TraceEventPerformanceMark[];\n /**\n * Events triggered with the console.time(), console.timeEnd() and\n * console.timeLog() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/console/time\n */\n consoleTimings: readonly Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[];\n /**\n * Events triggered with the console.timeStamp() API\n * https://developer.mozilla.org/en-US/docs/Web/API/console/timeStamp\n */\n timestampEvents: readonly Types.TraceEvents.TraceEventTimeStamp[];\n}\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function reset(): void {\n syntheticEvents.length = 0;\n performanceMeasureEvents.length = 0;\n performanceMarkEvents.length = 0;\n consoleTimings.length = 0;\n timestampEvents.length = 0;\n handlerState = HandlerState.INITIALIZED;\n}\n\nconst resourceTimingNames = [\n 'workerStart',\n 'redirectStart',\n 'redirectEnd',\n 'fetchStart',\n 'domainLookupStart',\n 'domainLookupEnd',\n 'connectStart',\n 'connectEnd',\n 'secureConnectionStart',\n 'requestStart',\n 'responseStart',\n 'responseEnd',\n];\nconst navTimingNames = [\n 'navigationStart',\n 'unloadEventStart',\n 'unloadEventEnd',\n 'redirectStart',\n 'redirectEnd',\n 'fetchStart',\n 'commitNavigationEnd',\n 'domainLookupStart',\n 'domainLookupEnd',\n 'connectStart',\n 'connectEnd',\n 'secureConnectionStart',\n 'requestStart',\n 'responseStart',\n 'responseEnd',\n 'domLoading',\n 'domInteractive',\n 'domContentLoadedEventStart',\n 'domContentLoadedEventEnd',\n 'domComplete',\n 'loadEventStart',\n 'loadEventEnd',\n];\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('UserTimings handler is not initialized');\n }\n\n // These are events dispatched under the blink.user_timing category\n // but that the user didn't add. Filter them out so that they do not\n // Appear in the timings track (they still appear in the main thread\n // flame chart).\n const ignoredNames = [...resourceTimingNames, ...navTimingNames];\n if (ignoredNames.includes(event.name)) {\n return;\n }\n\n if (Types.TraceEvents.isTraceEventPerformanceMeasure(event)) {\n performanceMeasureEvents.push(event);\n return;\n }\n if (Types.TraceEvents.isTraceEventPerformanceMark(event)) {\n performanceMarkEvents.push(event);\n }\n if (Types.TraceEvents.isTraceEventConsoleTime(event)) {\n consoleTimings.push(event);\n }\n if (Types.TraceEvents.isTraceEventTimeStamp(event)) {\n timestampEvents.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('UserTimings handler is not initialized');\n }\n\n const matchedEvents: Map<string, {\n begin: Types.TraceEvents.TraceEventNestableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventNestableAsyncEnd | null,\n }> = new Map();\n\n for (const event of [...performanceMeasureEvents, ...consoleTimings]) {\n const id = Helpers.Trace.extractId(event);\n if (id === undefined) {\n continue;\n }\n // Create a synthetic id to prevent collisions across categories.\n // Console timings can be dispatched with the same id, so use the\n // event name as well to generate unique ids.\n const syntheticId = `${event.cat}:${id}:${event.name}`;\n const otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedEvents, syntheticId, () => {\n return {begin: null, end: null};\n });\n const isStartEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_START;\n const isEndEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_END;\n\n if (isStartEvent) {\n otherEventsWithID.begin = event;\n } else if (isEndEvent) {\n otherEventsWithID.end = event;\n }\n }\n\n for (const [id, eventsPair] of matchedEvents.entries()) {\n if (!eventsPair.begin || !eventsPair.end) {\n // This should never happen, the backend only creates the events once it\n // has them both, so we should never get into this state.\n // If we do, something is very wrong, so let's just drop that problematic event.\n continue;\n }\n\n const event: Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent = {\n cat: eventsPair.end.cat,\n ph: eventsPair.end.ph,\n pid: eventsPair.end.pid,\n tid: eventsPair.end.tid,\n id,\n // Both events have the same name, so it doesn't matter which we pick to\n // use as the description\n name: eventsPair.begin.name,\n dur: Types.Timing.MicroSeconds(eventsPair.end.ts - eventsPair.begin.ts),\n ts: eventsPair.begin.ts,\n args: {\n data: {\n beginEvent: eventsPair.begin,\n endEvent: eventsPair.end,\n },\n },\n };\n\n if (event.dur < 0) {\n // Avoid any pairs that have created a negative duration; this is bad\n // trace data and we should just ignore them.\n continue;\n }\n syntheticEvents.push(event);\n }\n syntheticEvents.sort((a, b) => a.ts - b.ts);\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): UserTimingsData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('UserTimings handler is not finalized');\n }\n\n return {\n performanceMeasures: syntheticEvents.filter(Types.TraceEvents.isTraceEventPerformanceMeasure),\n consoleTimings: syntheticEvents.filter(Types.TraceEvents.isTraceEventConsoleTime),\n performanceMarks: [...performanceMarkEvents],\n timestampEvents: [...timestampEvents],\n };\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nexport interface WarningsData {\n // Tracks warnings keyed by the event.\n perEvent: Map<Types.TraceEvents.TraceEventData, Warning[]>;\n // The same data in reverse: for each type of warning, track the events.\n // Useful if we need to enumerate issues by type of issue\n perWarning: Map<Warning, Types.TraceEvents.TraceEventData[]>;\n}\n\nexport type Warning = 'LONG_TASK'|'IDLE_CALLBACK_OVER_TIME'|'FORCED_LAYOUT'|'FORCED_STYLE';\n\nconst warningsPerEvent: WarningsData['perEvent'] = new Map();\nconst eventsPerWarning: WarningsData['perWarning'] = new Map();\n\nexport const FORCED_LAYOUT_AND_STYLES_THRESHOLD =\n Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(10));\n\nexport const LONG_MAIN_THREAD_TASK_THRESHOLD = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(50));\n\nexport function reset(): void {\n warningsPerEvent.clear();\n eventsPerWarning.clear();\n}\n\nfunction storeWarning(event: Types.TraceEvents.TraceEventData, warning: Warning): void {\n const existingWarnings = Platform.MapUtilities.getWithDefault(warningsPerEvent, event, () => []);\n existingWarnings.push(warning);\n warningsPerEvent.set(event, existingWarnings);\n\n const existingEvents = Platform.MapUtilities.getWithDefault(eventsPerWarning, warning, () => []);\n existingEvents.push(event);\n eventsPerWarning.set(warning, existingEvents);\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (event.name === Types.TraceEvents.KnownEventName.RunTask) {\n const {duration} = Helpers.Timing.eventTimingsMicroSeconds(event);\n if (duration > LONG_MAIN_THREAD_TASK_THRESHOLD) {\n storeWarning(event, 'LONG_TASK');\n }\n return;\n }\n\n if (Types.TraceEvents.isTraceEventFireIdleCallback(event)) {\n const {duration} = Helpers.Timing.eventTimingsMilliSeconds(event);\n if (duration > event.args.data.allottedMilliseconds) {\n storeWarning(event, 'IDLE_CALLBACK_OVER_TIME');\n }\n return;\n }\n\n if (event.name === Types.TraceEvents.KnownEventName.Layout) {\n if (event.dur && event.dur >= FORCED_LAYOUT_AND_STYLES_THRESHOLD) {\n storeWarning(event, 'FORCED_LAYOUT');\n }\n return;\n }\n\n if (event.name === Types.TraceEvents.KnownEventName.RecalculateStyles ||\n event.name === Types.TraceEvents.KnownEventName.UpdateLayoutTree) {\n if (event.dur && event.dur >= FORCED_LAYOUT_AND_STYLES_THRESHOLD) {\n storeWarning(event, 'FORCED_STYLE');\n }\n return;\n }\n}\n\nexport function data(): WarningsData {\n return {\n perEvent: new Map(warningsPerEvent),\n perWarning: new Map(eventsPerWarning),\n };\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\nexport interface WorkersData {\n workerSessionIdEvents: readonly Types.TraceEvents.TraceEventTracingSessionIdForWorker[];\n workerIdByThread: Map<Types.TraceEvents.ThreadID, Types.TraceEvents.WorkerId>;\n workerURLById: Map<Types.TraceEvents.WorkerId, string>;\n}\nlet handlerState = HandlerState.UNINITIALIZED;\n\nconst sessionIdEvents: Types.TraceEvents.TraceEventTracingSessionIdForWorker[] = [];\nconst workerIdByThread: Map<Types.TraceEvents.ThreadID, Types.TraceEvents.WorkerId> = new Map();\nconst workerURLById: Map<Types.TraceEvents.WorkerId, string> = new Map();\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('Workers Handler was not reset');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function reset(): void {\n sessionIdEvents.length = 0;\n workerIdByThread.clear();\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Workers Handler is not initialized');\n }\n if (Types.TraceEvents.isTraceEventTracingSessionIdForWorker(event)) {\n sessionIdEvents.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Handler is not initialized');\n }\n for (const sessionIdEvent of sessionIdEvents) {\n if (!sessionIdEvent.args.data) {\n continue;\n }\n workerIdByThread.set(sessionIdEvent.args.data.workerThreadId, sessionIdEvent.args.data.workerId);\n workerURLById.set(sessionIdEvent.args.data.workerId, sessionIdEvent.args.data.url);\n }\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): WorkersData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Workers Handler is not finalized');\n }\n\n return {\n workerSessionIdEvents: [...sessionIdEvents],\n workerIdByThread: new Map(workerIdByThread),\n workerURLById: new Map(workerURLById),\n };\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as Animations from './AnimationHandler.js';\nexport * as AuctionWorklets from './AuctionWorkletsHandler.js';\nexport * as GPU from './GPUHandler.js';\nexport * as LargestImagePaint from './LargestImagePaintHandler.js';\nexport * as LargestTextPaint from './LargestTextPaintHandler.js';\nexport * as LayoutShifts from './LayoutShiftsHandler.js';\nexport * as Memory from './MemoryHandler.js';\nexport * as Meta from './MetaHandler.js';\nexport * as NetworkRequests from './NetworkRequestsHandler.js';\nexport * as PageLoadMetrics from './PageLoadMetricsHandler.js';\nexport * as Renderer from './RendererHandler.js';\nexport * as Samples from './SamplesHandler.js';\nexport * as Screenshots from './ScreenshotsHandler.js';\nexport * as UserInteractions from './UserInteractionsHandler.js';\nexport * as UserTimings from './UserTimingsHandler.js';\nexport * as Warnings from './WarningsHandler.js';\nexport * as Workers from './WorkersHandler.js';\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Types from '../types/types.js';\n\n/**\n * There are two metadata events that we care about.\n * => AuctionWorkletRunningInProcess tells us which process the Auction Worklet\n * has taken to run in.\n * => AuctionWorkletDoneWithProcess tells us when the worklet is done with that\n * process. This is less useful - but in the future we might want to surface\n * this information so we still parse and return the event.\n *\n * It is important to note that the top level PID on these events is NOT the\n * PID that the worklet is running on; instead we have to look at its\n * args.data.pid property, which is the PID of the process that it is running\n * on.\n *\n * For any given RunningInProcess event, we would typically expect to see a\n * DoneWithProcess event, however this is not guaranteed, especially as users\n * can record any chunk of time in DevTools.\n *\n * Similarly, it is also possible to see a DoneWithProcess event without a\n * RunningInProcess event, if the user started recording after the auction\n * worklets started. Therefore we are happy to create\n * SyntheticAuctionWorkletEvents as long as we see just one of these events.\n *\n * If we do get two events and need to pair them, we can use the\n * args.data.target property, which is a string ID shared by both\n * events.\n */\nconst runningInProcessEvents:\n Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventAuctionWorkletRunningInProcess> = new Map();\nconst doneWithProcessEvents:\n Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventAuctionWorkletDoneWithProcess> = new Map();\n\n// Keyed by the PID defined in `args.data.pid` on AuctionWorklet trace events..\nconst createdSyntheticEvents: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.SyntheticAuctionWorkletEvent> =\n new Map();\n\n// Each AuctonWorklet takes over a process and has 2 threads (that we care\n// about and want to show as tracks):\n// 1. A CrUtilityMain thread which is known as the \"control process\".\n// 2. A AuctionV8HelperThread which is the actual auction worklet and will be\n// either a \"Seller\" or a \"Bidder\"\n// To detect these we look for the metadata thread_name events. We key these by\n// PID so that we can easily look them up later without having to loop through.\nconst utilityThreads: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventThreadName> = new Map();\nconst v8HelperThreads: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventThreadName> = new Map();\n\nexport function reset(): void {\n runningInProcessEvents.clear();\n doneWithProcessEvents.clear();\n createdSyntheticEvents.clear();\n utilityThreads.clear();\n v8HelperThreads.clear();\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (Types.TraceEvents.isTraceEventAuctionWorkletRunningInProcess(event)) {\n runningInProcessEvents.set(event.args.data.pid, event);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventAuctionWorkletDoneWithProcess(event)) {\n doneWithProcessEvents.set(event.args.data.pid, event);\n return;\n }\n\n if (Types.TraceEvents.isThreadName(event)) {\n if (event.args.name === 'auction_worklet.CrUtilityMain') {\n utilityThreads.set(event.pid, event);\n return;\n }\n if (event.args.name === 'AuctionV8HelperThread') {\n v8HelperThreads.set(event.pid, event);\n }\n }\n}\n\nfunction workletType(input: string): Types.TraceEvents.AuctionWorkletType {\n switch (input) {\n case 'seller':\n return Types.TraceEvents.AuctionWorkletType.SELLER;\n case 'bidder':\n return Types.TraceEvents.AuctionWorkletType.BIDDER;\n default:\n return Types.TraceEvents.AuctionWorkletType.UNKNOWN;\n }\n}\n\n/**\n * We cannot make the full event without knowing the type of event, but we can\n * create everything other than the `args` field, as those are identical\n * regardless of the type of event.\n */\nfunction makeSyntheticEventBase(event: Types.TraceEvents.TraceEventAuctionWorkletDoneWithProcess|\n Types.TraceEvents.TraceEventAuctionWorkletRunningInProcess):\n Omit<Types.TraceEvents.SyntheticAuctionWorkletEvent, 'args'> {\n return {\n name: 'SyntheticAuctionWorkletEvent',\n s: Types.TraceEvents.TraceEventScope.THREAD,\n cat: event.cat,\n tid: event.tid,\n ts: event.ts,\n ph: Types.TraceEvents.Phase.INSTANT,\n pid: event.args.data.pid,\n host: event.args.data.host,\n target: event.args.data.target,\n type: workletType(event.args.data.type),\n };\n}\n\nexport async function finalize(): Promise<void> {\n // Loop through the utility threads we found to create the worklet events. We\n // expect each worklet to have a utility thread, so we can use them as the\n // root of our list of worklets.\n for (const [pid, utilityThreadNameEvent] of utilityThreads) {\n const v8HelperEvent = v8HelperThreads.get(pid);\n if (!v8HelperEvent) {\n // Bad trace data - AuctionWorklets are expected to always have both threads.\n continue;\n }\n\n const runningEvent = runningInProcessEvents.get(pid);\n const doneWithEvent = doneWithProcessEvents.get(pid);\n\n // We can create a worklet from either the runningEvent or doneWithEvent -\n // we do not need both. We cannot express that to TypeScript with an early\n // return here, so instead we set the event initially to null, and then\n // create it from either the running event or the doneWith event. If it is\n // still null after this, that means neither event was found, and we drop\n // the worklet as we do not have enough information to create the synthetic\n // event.\n\n let syntheticEvent: Types.TraceEvents.SyntheticAuctionWorkletEvent|null = null;\n\n if (runningEvent) {\n syntheticEvent = {\n ...makeSyntheticEventBase(runningEvent),\n args: {\n data: {\n runningInProcessEvent: runningEvent,\n utilityThread: utilityThreadNameEvent,\n v8HelperThread: v8HelperEvent,\n },\n },\n };\n if (doneWithEvent) {\n syntheticEvent.args.data.doneWithProcessEvent = doneWithEvent;\n }\n } else if (doneWithEvent) {\n syntheticEvent = {\n ...makeSyntheticEventBase(doneWithEvent),\n args: {\n data: {\n doneWithProcessEvent: doneWithEvent,\n utilityThread: utilityThreadNameEvent,\n v8HelperThread: v8HelperEvent,\n },\n },\n };\n if (runningEvent) {\n syntheticEvent.args.data.runningInProcessEvent = runningEvent;\n }\n }\n if (syntheticEvent === null) {\n continue;\n }\n createdSyntheticEvents.set(pid, syntheticEvent);\n }\n}\n\nexport interface AuctionWorkletsData {\n worklets: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.SyntheticAuctionWorkletEvent>;\n}\n\nexport function data(): AuctionWorkletsData {\n return {\n worklets: new Map(createdSyntheticEvents),\n };\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Types from '../types/types.js';\nimport type * as Protocol from '../../../generated/protocol.js';\n/**\n * If the LCP resource was an image, and that image was fetched over the\n * network, we want to be able to find the network request in order to construct\n * the critical path for an LCP image.\n * Within the trace file there are `LargestImagePaint::Candidate` events.\n * Within their data object, they contain a `DOMNodeId` property, which maps to\n * the DOM Node ID for that image.\n *\n * This id maps exactly to the `data.nodeId` property that a\n * `LargestContentfulPaint::Candidate` will have. So, when we find an image\n * paint candidate, we can store it, keying it on the node ID.\n * Then, when it comes to finding the network request for an LCP image, we can\n *\n * use the nodeId from the LCP candidate to find the image candidate. That image\n * candidate also contains a `imageUrl` property, which will have the full URL\n * to the image.\n **/\nconst imageByDOMNodeId = new Map<Protocol.DOM.BackendNodeId, Types.TraceEvents.TraceEventLargestImagePaintCandidate>();\n\nexport function reset(): void {\n imageByDOMNodeId.clear();\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (!Types.TraceEvents.isTraceEventLargestImagePaintCandidate(event)) {\n return;\n }\n\n if (!event.args.data) {\n return;\n }\n\n imageByDOMNodeId.set(event.args.data.DOMNodeId, event);\n}\n\nexport function data(): Map<Protocol.DOM.BackendNodeId, Types.TraceEvents.TraceEventLargestImagePaintCandidate> {\n return new Map(imageByDOMNodeId);\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as Types from '../types/types.js';\n/**\n * A trace file will contain all the text paints that were candidates for the\n * LargestTextPaint. If an LCP event is text, it will point to one of these\n * candidates, so we store them by their DOM Node ID.\n **/\nconst textPaintByDOMNodeId =\n new Map<Protocol.DOM.BackendNodeId, Types.TraceEvents.TraceEventLargestTextPaintCandidate>();\n\nexport function reset(): void {\n textPaintByDOMNodeId.clear();\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (!Types.TraceEvents.isTraceEventLargestTextPaintCandidate(event)) {\n return;\n }\n\n if (!event.args.data) {\n return;\n }\n\n textPaintByDOMNodeId.set(event.args.data.DOMNodeId, event);\n}\n\nexport function data(): Map<Protocol.DOM.BackendNodeId, Types.TraceEvents.TraceEventLargestTextPaintCandidate> {\n return new Map(textPaintByDOMNodeId);\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as metaHandlerData, type FrameProcessData} from './MetaHandler.js';\nimport {data as samplesHandlerData} from './SamplesHandler.js';\nimport {HandlerState, type TraceEventHandlerName} from './types.js';\n\n/**\n * This handler builds the hierarchy of trace events and profile calls\n * on each thread on each process.\n *\n * Throughout the code, trace events and profile calls are referred to\n * as \"entries\", but note they are different types of data. Trace events\n * come directly from the backend and it's the type the engine commonly\n * refers to. Profile calls on the other hand are built in the frontend,\n * and, for compatibility purposes, typed as an extension to the trace\n * event type.\n */\n\nconst processes = new Map<Types.TraceEvents.ProcessID, RendererProcess>();\n\n// We track the compositor tile worker thread name events so that at the end we\n// can return these keyed by the process ID. These are used in the frontend to\n// show the user the rasterization thread(s) on the main frame as tracks.\nconst compositorTileWorkers = Array<{\n pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID,\n}>();\nconst entryToNode = new Map<Types.TraceEvents.RendererEntry, RendererEntryNode>();\nconst allRendererEvents: Types.TraceEvents.TraceEventRendererEvent[] = [];\nlet nodeIdCount = 0;\nconst makeRendererEntrytNodeId = (): RendererEntryNodeId => (++nodeIdCount) as RendererEntryNodeId;\nconst completeEventStack: (Types.TraceEvents.TraceEventSyntheticCompleteEvent)[] = [];\n\nlet handlerState = HandlerState.UNINITIALIZED;\nlet config: Types.Configuration.Configuration = Types.Configuration.DEFAULT;\n\nconst makeRendererProcess = (): RendererProcess => ({\n url: null,\n isOnMainFrame: false,\n threads: new Map(),\n});\n\nconst makeRendererThread = (): RendererThread => ({\n name: null,\n entries: [],\n});\n\nconst makeEmptyRendererTree = (): RendererTree => ({\n nodes: new Map(),\n roots: new Set(),\n maxDepth: 0,\n});\n\nconst makeEmptyRendererEventNode =\n (entry: Types.TraceEvents.RendererEntry, id: RendererEntryNodeId): RendererEntryNode => ({\n entry,\n id,\n parentId: null,\n children: new Set(),\n depth: 0,\n });\n\nconst getOrCreateRendererProcess =\n (processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, pid: Types.TraceEvents.ProcessID):\n RendererProcess => {\n return Platform.MapUtilities.getWithDefault(processes, pid, makeRendererProcess);\n };\n\nconst getOrCreateRendererThread = (process: RendererProcess, tid: Types.TraceEvents.ThreadID): RendererThread => {\n return Platform.MapUtilities.getWithDefault(process.threads, tid, makeRendererThread);\n};\n\nexport function handleUserConfig(userConfig: Types.Configuration.Configuration): void {\n config = userConfig;\n}\n\nexport function reset(): void {\n processes.clear();\n entryToNode.clear();\n allRendererEvents.length = 0;\n completeEventStack.length = 0;\n compositorTileWorkers.length = 0;\n nodeIdCount = -1;\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('Renderer Handler was not reset');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Renderer Handler is not initialized');\n }\n\n if (Types.TraceEvents.isThreadName(event) && event.args.name?.startsWith('CompositorTileWorker')) {\n compositorTileWorkers.push({\n pid: event.pid,\n tid: event.tid,\n });\n }\n\n if (Types.TraceEvents.isTraceEventBegin(event) || Types.TraceEvents.isTraceEventEnd(event)) {\n const process = getOrCreateRendererProcess(processes, event.pid);\n const thread = getOrCreateRendererThread(process, event.tid);\n const completeEvent = makeCompleteEvent(event);\n if (!completeEvent) {\n return;\n }\n thread.entries.push(completeEvent);\n allRendererEvents.push(completeEvent);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventInstant(event) || Types.TraceEvents.isTraceEventComplete(event)) {\n const process = getOrCreateRendererProcess(processes, event.pid);\n const thread = getOrCreateRendererThread(process, event.tid);\n thread.entries.push(event);\n allRendererEvents.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Renderer Handler is not initialized');\n }\n\n const {mainFrameId, rendererProcessesByFrame, threadsInProcess} = metaHandlerData();\n assignMeta(processes, mainFrameId, rendererProcessesByFrame, threadsInProcess);\n sanitizeProcesses(processes);\n buildHierarchy(processes);\n sanitizeThreads(processes);\n\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): RendererHandlerData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Renderer Handler is not finalized');\n }\n\n return {\n processes: new Map(processes),\n compositorTileWorkers: new Map(gatherCompositorThreads()),\n entryToNode: new Map(entryToNode),\n allRendererEvents: [...allRendererEvents],\n };\n}\n\nfunction gatherCompositorThreads(): Map<Types.TraceEvents.ProcessID, Types.TraceEvents.ThreadID[]> {\n const threadsByProcess = new Map<Types.TraceEvents.ProcessID, Types.TraceEvents.ThreadID[]>();\n for (const worker of compositorTileWorkers) {\n const byProcess = threadsByProcess.get(worker.pid) || [];\n byProcess.push(worker.tid);\n threadsByProcess.set(worker.pid, byProcess);\n }\n return threadsByProcess;\n}\n\n/**\n * Steps through all the renderer processes we've located so far in the meta\n * handler, obtaining their URL, checking whether they are the main frame, and\n * collecting each one of their threads' name. This meta handler's data is\n * assigned to the renderer handler's data.\n */\nexport function assignMeta(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, mainFrameId: string,\n rendererProcessesByFrame: FrameProcessData,\n threadsInProcess:\n Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventThreadName>>):\n void {\n assignOrigin(processes, rendererProcessesByFrame);\n assignIsMainFrame(processes, mainFrameId, rendererProcessesByFrame);\n assignThreadName(processes, rendererProcessesByFrame, threadsInProcess);\n}\n\n/**\n * Assigns origins to all threads in all processes.\n * @see assignMeta\n */\nexport function assignOrigin(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, rendererProcessesByFrame: FrameProcessData): void {\n for (const renderProcessesByPid of rendererProcessesByFrame.values()) {\n for (const [pid, processWindows] of renderProcessesByPid) {\n for (const processInfo of processWindows.flat()) {\n const process = getOrCreateRendererProcess(processes, pid);\n // Sometimes a single process is responsible with rendering multiple\n // frames at the same time. For example, see https://crbug.com/1334563.\n // When this happens, we'd still like to assign a single url per process\n // so: 1) use the first frame rendered by this process as the url source\n // and 2) if the last url is \"about:blank\", use the next frame's url,\n // data from about:blank is irrelevant.\n if (process.url === null || process.url === 'about:blank') {\n // If we are here, it's because we care about this process and the URL. But before we store\n // it, we check if it is a valid URL by trying to create a URL object. If it isn't, we won't\n // set it, and this process will be filtered out later.\n try {\n new URL(processInfo.frame.url);\n process.url = processInfo.frame.url;\n } catch (e) {\n process.url = null;\n }\n }\n }\n }\n }\n}\n\n/**\n * Assigns whether or not a thread is the main frame to all threads in all processes.\n * @see assignMeta\n */\nexport function assignIsMainFrame(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, mainFrameId: string,\n rendererProcessesByFrame: FrameProcessData): void {\n for (const [frameId, renderProcessesByPid] of rendererProcessesByFrame) {\n for (const [pid] of renderProcessesByPid) {\n const process = getOrCreateRendererProcess(processes, pid);\n // We have this go in one direction; once a renderer has been flagged as\n // being on the main frame, we don't unset it to false if were to show up\n // in a subframe. Equally, if we already saw this renderer in a subframe,\n // but it becomes the main frame, the flag would get updated.\n if (frameId === mainFrameId) {\n process.isOnMainFrame = true;\n }\n }\n }\n}\n\n/**\n * Assigns the thread name to all threads in all processes.\n * @see assignMeta\n */\nexport function assignThreadName(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, rendererProcessesByFrame: FrameProcessData,\n threadsInProcess:\n Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventThreadName>>):\n void {\n for (const [, renderProcessesByPid] of rendererProcessesByFrame) {\n for (const [pid] of renderProcessesByPid) {\n const process = getOrCreateRendererProcess(processes, pid);\n for (const [tid, threadInfo] of threadsInProcess.get(pid) ?? []) {\n const thread = getOrCreateRendererThread(process, tid);\n thread.name = threadInfo?.args.name ?? `${tid}`;\n }\n }\n }\n}\n\n/**\n * Removes unneeded trace data opportunistically stored while handling events.\n * This currently does the following:\n * - Deletes processes with an unkonwn origin.\n */\nexport function sanitizeProcesses(processes: Map<Types.TraceEvents.ProcessID, RendererProcess>): void {\n for (const [pid, process] of processes) {\n // If the process had no url, or if it had a malformed url that could not be\n // parsed for some reason, or if it's an \"about:\" origin, delete it.\n // This is done because we don't really care about processes for which we\n // can't provide actionable insights to the user (e.g. about:blank pages).\n if (process.url === null) {\n processes.delete(pid);\n continue;\n }\n const asUrl = new URL(process.url);\n if (asUrl.protocol === 'about:') {\n processes.delete(pid);\n }\n }\n}\n\n/**\n * Removes unneeded trace data opportunistically stored while handling events.\n * This currently does the following:\n * - Deletes threads with no roots.\n */\nexport function sanitizeThreads(processes: Map<Types.TraceEvents.ProcessID, RendererProcess>): void {\n for (const [, process] of processes) {\n for (const [tid, thread] of process.threads) {\n // If the thread has no roots, delete it. Otherwise, there's going to\n // be space taken, even though nothing is rendered in the track manager.\n if (!thread.tree?.roots.size) {\n process.threads.delete(tid);\n }\n }\n }\n}\n\n/**\n * Creates a hierarchical structure from the trace events. Each thread in each\n * process will contribute to their own individual hierarchy.\n *\n * The trace data comes in as a contiguous array of events, against which we\n * make a couple of assumptions:\n *\n * 1. Events are temporally-ordered in terms of start time (though they're\n * not necessarily ordered as such in the data stream).\n * 2. If event B's start and end times are within event A's time boundaries\n * we assume that A is the parent of B.\n *\n * Therefore we expect to reformulate something like:\n *\n * [ Task A ][ Task B ][ Task C ][ Task D ][ Task E ]\n *\n * Into something hierarchically-arranged like below:\n *\n * |------------- Task A -------------||-- Task E --|\n * |-- Task B --||-- Task D --|\n * |- Task C -|\n */\nexport function buildHierarchy(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>,\n options?: {filter: {has: (name: Types.TraceEvents.KnownEventName) => boolean}}): void {\n for (const [pid, process] of processes) {\n for (const [tid, thread] of process.threads) {\n if (!thread.entries.length) {\n thread.tree = makeEmptyRendererTree();\n continue;\n }\n // Step 1. Massage the data.\n Helpers.Trace.sortTraceEventsInPlace(thread.entries);\n // Step 2. Inject profile calls from samples\n const cpuProfile = samplesHandlerData().profilesInProcess.get(pid)?.get(tid)?.parsedProfile;\n const samplesIntegrator =\n cpuProfile && new Helpers.SamplesIntegrator.SamplesIntegrator(cpuProfile, pid, tid, config);\n const profileCalls = samplesIntegrator?.buildProfileCalls(thread.entries);\n if (profileCalls) {\n thread.entries = Helpers.Trace.mergeEventsInOrder(thread.entries, profileCalls);\n }\n // Step 3. Build the tree.\n thread.tree = treify(thread.entries, options);\n }\n }\n}\n\n/**\n * Builds a hierarchy of the entries (trace events and profile calls) in\n * a particular thread of a particular process, assuming that they're\n * sorted, by iterating through all of the events in order.\n *\n * The approach is analogous to how a parser would be implemented. A\n * stack maintains local context. A scanner peeks and pops from the data\n * stream. Various \"tokens\" (events) are treated as \"whitespace\"\n * (ignored).\n *\n * The tree starts out empty and is populated as the hierarchy is built.\n * The nodes are also assumed to be created empty, with no known parent\n * or children.\n *\n * Complexity: O(n), where n = number of events\n */\nexport function treify(\n entries: Types.TraceEvents.RendererEntry[],\n options?: {filter: {has: (name: Types.TraceEvents.KnownEventName) => boolean}}): RendererTree {\n const stack = [];\n // Reset the node id counter for every new renderer.\n nodeIdCount = -1;\n const tree = makeEmptyRendererTree();\n for (let i = 0; i < entries.length; i++) {\n const event = entries[i];\n // If the current event should not be part of the tree, then simply proceed\n // with the next event.\n if (options && !options.filter.has(event.name as Types.TraceEvents.KnownEventName)) {\n continue;\n }\n\n const duration = event.dur || 0;\n const nodeId = makeRendererEntrytNodeId();\n const node = makeEmptyRendererEventNode(event, nodeId);\n\n // If the parent stack is empty, then the current event is a root. Create a\n // node for it, mark it as a root, then proceed with the next event.\n if (stack.length === 0) {\n tree.nodes.set(nodeId, node);\n tree.roots.add(node);\n event.selfTime = Types.Timing.MicroSeconds(duration);\n stack.push(node);\n tree.maxDepth = Math.max(tree.maxDepth, stack.length);\n entryToNode.set(event, node);\n continue;\n }\n\n const parentNode = stack.at(-1);\n if (parentNode === undefined) {\n throw new Error('Impossible: no parent node found in the stack');\n }\n\n const parentEvent = parentNode.entry;\n\n const begin = event.ts;\n const parentBegin = parentEvent.ts;\n const parentDuration = parentEvent.dur || 0;\n const end = begin + duration;\n const parentEnd = parentBegin + parentDuration;\n // Check the relationship between the parent event at the top of the stack,\n // and the current event being processed. There are only 4 distinct\n // possiblities, only 2 of them actually valid, given the assumed sorting:\n // 1. Current event starts before the parent event, ends whenever. (invalid)\n // 2. Current event starts after the parent event, ends whenever. (valid)\n // 3. Current event starts during the parent event, ends after. (invalid)\n // 4. Current event starts and ends during the parent event. (valid)\n\n // 1. If the current event starts before the parent event, then the data is\n // not sorted properly, messed up some way, or this logic is incomplete.\n const startsBeforeParent = begin < parentBegin;\n if (startsBeforeParent) {\n throw new Error('Impossible: current event starts before the parent event');\n }\n\n // 2. If the current event starts after the parent event, then it's a new\n // parent. Pop, then handle current event again.\n const startsAfterParent = begin >= parentEnd;\n if (startsAfterParent) {\n stack.pop();\n i--;\n // The last created node has been discarded, so discard this id.\n nodeIdCount--;\n continue;\n }\n // 3. If the current event starts during the parent event, but ends\n // after it, then the data is messed up some way, for example a\n // profile call was sampled too late after its start, ignore the\n // problematic event.\n const endsAfterParent = end > parentEnd;\n if (endsAfterParent) {\n continue;\n }\n\n // 4. The only remaining case is the common case, where the current event is\n // contained within the parent event. Create a node for the current\n // event, establish the parent/child relationship, then proceed with the\n // next event.\n tree.nodes.set(nodeId, node);\n node.depth = stack.length;\n node.parentId = parentNode.id;\n parentNode.children.add(node);\n event.selfTime = Types.Timing.MicroSeconds(duration);\n if (parentEvent.selfTime !== undefined) {\n parentEvent.selfTime = Types.Timing.MicroSeconds(parentEvent.selfTime - (event.dur || 0));\n }\n stack.push(node);\n tree.maxDepth = Math.max(tree.maxDepth, stack.length);\n entryToNode.set(event, node);\n }\n return tree;\n}\n\nexport function makeCompleteEvent(event: Types.TraceEvents.TraceEventBegin|Types.TraceEvents.TraceEventEnd):\n Types.TraceEvents.TraceEventSyntheticCompleteEvent|null {\n if (Types.TraceEvents.isTraceEventEnd(event)) {\n // Quietly ignore unbalanced close events, they're legit (we could\n // have missed start one).\n const beginEvent = completeEventStack.pop();\n if (!beginEvent) {\n return null;\n }\n if (beginEvent.name !== event.name || beginEvent.cat !== event.cat) {\n console.error(\n 'Begin/End events mismatch at ' + beginEvent.ts + ' (' + beginEvent.name + ') vs. ' + event.ts + ' (' +\n event.name + ')');\n return null;\n }\n // Update the begin event's duration using the timestamp of the end\n // event.\n beginEvent.dur = Types.Timing.MicroSeconds(event.ts - beginEvent.ts);\n return null;\n }\n\n // Create a synthetic event using the begin event, when we find the\n // matching end event later we will update its duration.\n const syntheticComplete: Types.TraceEvents.TraceEventSyntheticCompleteEvent = {\n ...event,\n ph: Types.TraceEvents.Phase.COMPLETE,\n dur: Types.Timing.MicroSeconds(0),\n };\n\n completeEventStack.push(syntheticComplete);\n return syntheticComplete;\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta', 'Samples'];\n}\n\nexport interface RendererHandlerData {\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>;\n /**\n * A map of all compositor workers (which we show in the UI as Rasterizers)\n * by the process ID.\n */\n compositorTileWorkers: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.ThreadID[]>;\n entryToNode: Map<Types.TraceEvents.RendererEntry, RendererEntryNode>;\n /**\n * All trace events and synthetic profile calls made from\n * samples.\n */\n allRendererEvents: Types.TraceEvents.TraceEventRendererEvent[];\n}\n\nexport interface RendererProcess {\n // In an ideal world this would be modelled as a URL, but URLs cannot be sent\n // between the main thread and workers, so we have to store it as a string.\n url: string|null;\n isOnMainFrame: boolean;\n threads: Map<Types.TraceEvents.ThreadID, RendererThread>;\n}\n\nexport interface RendererThread {\n name: string|null;\n /**\n * Contains trace events and synthetic profile calls made from\n * samples.\n */\n entries: Types.TraceEvents.RendererEntry[];\n tree?: RendererTree;\n}\n\nexport interface RendererTree {\n nodes: Map<RendererEntryNodeId, RendererEntryNode>;\n roots: Set<RendererEntryNode>;\n maxDepth: number;\n}\n\nexport interface RendererEntryNode {\n entry: Types.TraceEvents.RendererEntry;\n depth: number;\n id: RendererEntryNodeId;\n parentId?: RendererEntryNodeId|null;\n children: Set<RendererEntryNode>;\n}\n\nclass RendererEventNodeIdTag {\n /* eslint-disable-next-line no-unused-private-class-members */\n readonly #tag: (symbol|undefined);\n}\nexport type RendererEntryNodeId = number&RendererEventNodeIdTag;\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as CPUProfile from '../../cpu_profile/cpu_profile.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\nconst events =\n new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventComplete[]>>();\n\nconst profilesInProcess = new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, ProfileData>>();\n\n// The profile head, containing its metadata like its start\n// time, comes in a \"Profile\" event. The sample data comes in\n// \"ProfileChunk\" events. We match these ProfileChunks with their head\n// using process and profile ids. However, in order to integrate sample\n// data with trace data, we need the thread id that owns each profile.\n// This thread id is extracted from the head event.\n// For this reason, we have a preprocessed data structure, where events\n// are matched by profile id, which we then finish processing to export\n// events matched by thread id.\nconst preprocessedData = new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ProfileID, PreprocessedData>>();\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function buildProfileCalls(): void {\n for (const [processId, profiles] of preprocessedData) {\n for (const [profileId, preProcessedData] of profiles) {\n const threadId = preProcessedData.threadId;\n if (!preProcessedData.rawProfile.nodes.length || !threadId) {\n continue;\n }\n const trackingStack: Partial<Types.TraceEvents.TraceEventSyntheticProfileCall>[] = [];\n\n const profileModel = new CPUProfile.CPUProfileDataModel.CPUProfileDataModel(preProcessedData.rawProfile);\n\n const finalizedData:\n ProfileData = {rawProfile: preProcessedData.rawProfile, parsedProfile: profileModel, profileCalls: []};\n\n profileModel.forEachFrame(openFrameCallback, closeFrameCallback);\n Helpers.Trace.sortTraceEventsInPlace(finalizedData.profileCalls);\n const dataByThread = Platform.MapUtilities.getWithDefault(profilesInProcess, processId, () => new Map());\n dataByThread.set(threadId, finalizedData);\n\n function openFrameCallback(\n _depth: number, node: CPUProfile.ProfileTreeModel.ProfileNode, timeStampMs: number): void {\n const ts = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(timeStampMs));\n trackingStack.push({callFrame: node.callFrame, ts, pid: processId, children: [], tid: threadId});\n }\n function closeFrameCallback(\n depth: number, node: CPUProfile.ProfileTreeModel.ProfileNode, _timeStamp: number, durMs: number,\n selfTimeMs: number): void {\n const partialProfileCall = trackingStack.pop();\n if (!partialProfileCall) {\n return;\n }\n const {callFrame, ts, pid, children, tid} = partialProfileCall;\n if (callFrame === undefined || ts === undefined || pid === undefined || profileId === undefined ||\n children === undefined || tid === undefined) {\n return;\n }\n const dur = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(durMs));\n const selfTime = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(selfTimeMs));\n const completeProfileCall: Types.TraceEvents.TraceEventSyntheticProfileCall = {\n callFrame,\n ts,\n pid,\n dur,\n selfTime,\n children,\n ph: Types.TraceEvents.Phase.COMPLETE,\n cat: '',\n args: {},\n name: 'ProfileCall',\n tid,\n nodeId: node.id,\n };\n const parent = trackingStack.at(-1);\n const calls = finalizedData.profileCalls;\n calls.push(completeProfileCall);\n if (!parent) {\n return;\n }\n parent.children = parent.children || [];\n parent.children.push(completeProfileCall);\n if (parent.selfTime) {\n parent.selfTime = Types.Timing.MicroSeconds(parent.selfTime - dur);\n }\n }\n }\n }\n}\n\nexport function reset(): void {\n events.clear();\n preprocessedData.clear();\n profilesInProcess.clear();\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('Samples Handler was not reset');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Samples Handler is not initialized');\n }\n\n if (Types.TraceEvents.isTraceEventProfile(event)) {\n // Do not use event.args.data.startTime as it is in CLOCK_MONOTONIC domain,\n // but use profileEvent.ts which has been translated to Perfetto's clock\n // domain. Also convert from ms to us.\n // Note: events are collected on a different thread than what's sampled.\n // The correct process and thread ids are specified by the profile.\n const profileData = getOrCreatePreProcessedData(event.pid, event.id);\n profileData.rawProfile.startTime = event.ts;\n profileData.threadId = event.tid;\n return;\n }\n if (Types.TraceEvents.isTraceEventProfileChunk(event)) {\n const profileData = getOrCreatePreProcessedData(event.pid, event.id);\n const cdpProfile = profileData.rawProfile;\n const nodesAndSamples: Types.TraceEvents.TraceEventPartialProfile|undefined =\n event.args?.data?.cpuProfile || {samples: []};\n const samples = nodesAndSamples?.samples || [];\n const nodes: CPUProfile.CPUProfileDataModel.ExtendedProfileNode[] = [];\n for (const n of nodesAndSamples?.nodes || []) {\n const lineNumber = typeof n.callFrame.lineNumber === 'undefined' ? -1 : n.callFrame.lineNumber;\n const columnNumber = typeof n.callFrame.columnNumber === 'undefined' ? -1 : n.callFrame.columnNumber;\n\n const scriptId = String(n.callFrame.scriptId) as Protocol.Runtime.ScriptId;\n const url = n.callFrame.url || '';\n const node = {\n ...n,\n callFrame: {\n ...n.callFrame,\n url,\n lineNumber,\n columnNumber,\n scriptId,\n },\n };\n nodes.push(node);\n }\n\n const timeDeltas = event.args.data?.timeDeltas || [];\n const lines = event.args.data?.lines || Array(samples.length).fill(0);\n cdpProfile.nodes.push(...nodes);\n cdpProfile.samples?.push(...samples);\n cdpProfile.timeDeltas?.push(...timeDeltas);\n cdpProfile.lines?.push(...lines);\n if (cdpProfile.samples && cdpProfile.timeDeltas && cdpProfile.samples.length !== cdpProfile.timeDeltas.length) {\n console.error('Failed to parse CPU profile.');\n return;\n }\n if (!cdpProfile.endTime && cdpProfile.timeDeltas) {\n const timeDeltas: number[] = cdpProfile.timeDeltas;\n cdpProfile.endTime = timeDeltas.reduce((x, y) => x + y, cdpProfile.startTime);\n }\n return;\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Samples Handler is not initialized');\n }\n buildProfileCalls();\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): SamplesHandlerData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Samples Handler is not finalized');\n }\n\n return {\n profilesInProcess: new Map(profilesInProcess),\n };\n}\n\nfunction getOrCreatePreProcessedData(\n processId: Types.TraceEvents.ProcessID, profileId: Types.TraceEvents.ProfileID): PreprocessedData {\n const profileById = Platform.MapUtilities.getWithDefault(preprocessedData, processId, () => new Map());\n return Platform.MapUtilities.getWithDefault<Types.TraceEvents.ProfileID, PreprocessedData>(\n profileById, profileId, () => ({\n rawProfile: {\n startTime: 0,\n endTime: 0,\n nodes: [],\n samples: [],\n timeDeltas: [],\n lines: [],\n },\n profileId,\n }));\n}\n\nexport interface SamplesHandlerData {\n profilesInProcess: typeof profilesInProcess;\n}\n\nexport type ProfileData = {\n rawProfile: CPUProfile.CPUProfileDataModel.ExtendedProfile,\n parsedProfile: CPUProfile.CPUProfileDataModel.CPUProfileDataModel,\n profileCalls: Types.TraceEvents.TraceEventSyntheticProfileCall[],\n};\n\ntype PreprocessedData = {\n rawProfile: CPUProfile.CPUProfileDataModel.ExtendedProfile,\n threadId?: Types.TraceEvents.ThreadID, profileId: Types.TraceEvents.ProfileID,\n};\n", "// Copyright 2014 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../core/platform/platform.js';\nimport type * as Protocol from '../../generated/protocol.js';\n\nimport {ProfileNode, ProfileTreeModel} from './ProfileTreeModel.js';\n\nexport class CPUProfileNode extends ProfileNode {\n override id: number;\n override self: number;\n // Position ticks are available in profile nodes coming from CDP\n // profiles and not in those coming from tracing. They are used to\n // calculate the line level execution time shown in the Sources panel\n // after recording a profile. For trace CPU profiles we use the\n // `lines` array instead.\n positionTicks: Protocol.Profiler.PositionTickInfo[]|undefined;\n override deoptReason: string|null;\n\n constructor(node: Protocol.Profiler.ProfileNode, samplingInterval: number /* milliseconds */) {\n const callFrame = node.callFrame || ({\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n functionName: node['functionName'],\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n scriptId: node['scriptId'],\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n url: node['url'],\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n lineNumber: node['lineNumber'] - 1,\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n columnNumber: node['columnNumber'] - 1,\n } as Protocol.Runtime.CallFrame);\n super(callFrame);\n this.id = node.id;\n this.self = (node.hitCount || 0) * samplingInterval;\n this.positionTicks = node.positionTicks;\n // Compatibility: legacy backends could provide \"no reason\" for optimized functions.\n this.deoptReason = node.deoptReason && node.deoptReason !== 'no reason' ? node.deoptReason : null;\n }\n}\n\nexport class CPUProfileDataModel extends ProfileTreeModel {\n profileStartTime: number /* milliseconds */;\n profileEndTime: number /* milliseconds */;\n timestamps: number[];\n samples: number[]|undefined;\n lines?: number[];\n totalHitCount: number;\n profileHead: CPUProfileNode;\n /**\n * A cache for the nodes we have parsed.\n * Note: \"Parsed\" nodes are different from the \"Protocol\" nodes, the\n * latter being the raw data we receive from the backend.\n */\n #idToParsedNode!: Map<number, ProfileNode>;\n gcNode?: ProfileNode;\n programNode?: ProfileNode;\n idleNode?: ProfileNode;\n #stackStartTimes?: number[];\n #stackChildrenDuration?: number[];\n constructor(profile: ExtendedProfile) {\n super();\n // @ts-ignore Legacy types\n const isLegacyFormat = Boolean(profile['head']);\n if (isLegacyFormat) {\n // Legacy format contains raw timestamps and start/stop times are in seconds.\n this.profileStartTime = profile.startTime * 1000;\n this.profileEndTime = profile.endTime * 1000;\n // @ts-ignore Legacy types\n this.timestamps = profile.timestamps;\n this.compatibilityConversionHeadToNodes(profile);\n } else {\n // Current format encodes timestamps as deltas. Start/stop times are in microseconds.\n this.profileStartTime = profile.startTime / 1000;\n this.profileEndTime = profile.endTime / 1000;\n this.timestamps = this.convertTimeDeltas(profile);\n }\n this.samples = profile.samples;\n\n // Lines are available only in profiles coming from tracing.\n // Elements in the lines array have a 1 to 1 correspondance with\n // samples, by array position. They can be 1 or 0 and indicate if\n // there is line data for a given sample, i.e. if a given sample\n // needs to be included to calculate the line level execution time\n // data, which we show in the sources panel after recording a\n // profile.\n this.lines = profile.lines;\n this.totalHitCount = 0;\n this.profileHead = this.translateProfileTree(profile.nodes);\n this.initialize(this.profileHead);\n this.extractMetaNodes();\n if (this.samples) {\n this.sortSamples();\n this.normalizeTimestamps();\n this.fixMissingSamples();\n }\n }\n\n private compatibilityConversionHeadToNodes(profile: Protocol.Profiler.Profile): void {\n // @ts-ignore Legacy types\n if (!profile.head || profile.nodes) {\n return;\n }\n const nodes: Protocol.Profiler.ProfileNode[] = [];\n // @ts-ignore Legacy types\n convertNodesTree(profile.head);\n profile.nodes = nodes;\n // @ts-ignore Legacy types\n delete profile.head;\n function convertNodesTree(node: Protocol.Profiler.ProfileNode): number {\n nodes.push(node);\n // @ts-ignore Legacy types\n node.children = (node.children as Protocol.Profiler.ProfileNode[]).map(convertNodesTree);\n return node.id;\n }\n }\n\n /**\n * Calculate timestamps using timeDeltas. Some CPU profile formats,\n * like the ones contained in traces have timeDeltas instead of\n * timestamps.\n */\n private convertTimeDeltas(profile: Protocol.Profiler.Profile): number[] {\n if (!profile.timeDeltas) {\n return [];\n }\n let lastTimeMicroSec = profile.startTime;\n const timestamps = new Array(profile.timeDeltas.length);\n for (let i = 0; i < profile.timeDeltas.length; ++i) {\n lastTimeMicroSec += profile.timeDeltas[i];\n timestamps[i] = lastTimeMicroSec;\n }\n return timestamps;\n }\n\n /**\n * Creates a Tree of CPUProfileNodes using the Protocol.Profiler.ProfileNodes.\n * As the tree is built, samples of native code (prefixed with \"native \") are\n * filtered out. Samples of filtered nodes are replaced with the parent of the\n * node being filtered.\n *\n * This function supports legacy and new definitions of the CDP Profiler.Profile\n * type.\n */\n private translateProfileTree(nodes: Protocol.Profiler.ProfileNode[]): CPUProfileNode {\n function buildChildrenFromParents(nodes: Protocol.Profiler.ProfileNode[]): void {\n if (nodes[0].children) {\n return;\n }\n nodes[0].children = [];\n for (let i = 1; i < nodes.length; ++i) {\n const node = nodes[i];\n // @ts-ignore Legacy types\n const parentNode = protocolNodeById.get(node.parent);\n // @ts-ignore Legacy types\n if (parentNode.children) {\n // @ts-ignore Legacy types\n parentNode.children.push(node.id);\n } else {\n // @ts-ignore Legacy types\n parentNode.children = [node.id];\n }\n }\n }\n\n /**\n * Calculate how many times each node was sampled in the profile, if\n * not available in the profile data.\n */\n function buildHitCountFromSamples(nodes: Protocol.Profiler.ProfileNode[], samples: number[]|undefined): void {\n // If hit count is available, this profile has the new format, so\n // no need to continue.`\n if (typeof (nodes[0].hitCount) === 'number') {\n return;\n }\n if (!samples) {\n throw new Error('Error: Neither hitCount nor samples are present in profile.');\n }\n for (let i = 0; i < nodes.length; ++i) {\n nodes[i].hitCount = 0;\n }\n for (let i = 0; i < samples.length; ++i) {\n const node = protocolNodeById.get(samples[i]);\n if (!node || node.hitCount === undefined) {\n continue;\n }\n node.hitCount++;\n }\n }\n\n // A cache for the raw nodes received from the traces / CDP.\n const protocolNodeById = new Map<number, Protocol.Profiler.ProfileNode>();\n for (let i = 0; i < nodes.length; ++i) {\n const node = nodes[i];\n protocolNodeById.set(node.id, node);\n }\n\n buildHitCountFromSamples(nodes, this.samples);\n buildChildrenFromParents(nodes);\n this.totalHitCount = nodes.reduce((acc, node) => acc + (node.hitCount || 0), 0);\n const sampleTime = (this.profileEndTime - this.profileStartTime) / this.totalHitCount;\n const root = nodes[0];\n // If a node is filtered out, its samples are replaced with its parent,\n // so we keep track of the which id to use in the samples data.\n const idToUseForRemovedNode = new Map<number, number>([[root.id, root.id]]);\n this.#idToParsedNode = new Map();\n\n const resultRoot = new CPUProfileNode(root, sampleTime);\n this.#idToParsedNode.set(root.id, resultRoot);\n if (!root.children) {\n throw new Error('Missing children for root');\n }\n const parentNodeStack = root.children.map(() => resultRoot);\n const sourceNodeStack = root.children.map(id => protocolNodeById.get(id));\n while (sourceNodeStack.length) {\n let parentNode = parentNodeStack.pop();\n const sourceNode = sourceNodeStack.pop();\n if (!sourceNode || !parentNode) {\n continue;\n }\n if (!sourceNode.children) {\n sourceNode.children = [];\n }\n const targetNode = new CPUProfileNode(sourceNode, sampleTime);\n parentNode.children.push(targetNode);\n parentNode = targetNode;\n\n idToUseForRemovedNode.set(sourceNode.id, parentNode.id);\n parentNodeStack.push.apply(parentNodeStack, sourceNode.children.map(() => parentNode as CPUProfileNode));\n sourceNodeStack.push.apply(sourceNodeStack, sourceNode.children.map(id => protocolNodeById.get(id)));\n this.#idToParsedNode.set(sourceNode.id, targetNode);\n }\n if (this.samples) {\n this.samples = this.samples.map(id => idToUseForRemovedNode.get(id) as number);\n }\n return resultRoot;\n }\n\n /**\n * Sorts the samples array using the timestamps array (there is a one\n * to one matching by index between the two).\n */\n private sortSamples(): void {\n if (!this.timestamps || !this.samples) {\n return;\n }\n\n const timestamps = this.timestamps;\n const samples = this.samples;\n const orderedIndices = timestamps.map((_x, index) => index);\n orderedIndices.sort((a, b) => timestamps[a] - timestamps[b]);\n\n this.timestamps = [];\n this.samples = [];\n\n for (let i = 0; i < orderedIndices.length; i++) {\n const orderedIndex = orderedIndices[i];\n this.timestamps.push(timestamps[orderedIndex]);\n this.samples.push(samples[orderedIndex]);\n }\n }\n\n /**\n * Fills in timestamps and/or time deltas from legacy profiles where\n * they could be missing.\n */\n private normalizeTimestamps(): void {\n if (!this.samples) {\n return;\n }\n let timestamps: number[] = this.timestamps;\n if (!timestamps) {\n // Support loading CPU profiles that are missing timestamps and\n // timedeltas\n const profileStartTime = this.profileStartTime;\n const interval = (this.profileEndTime - profileStartTime) / this.samples.length;\n // Add an extra timestamp used to calculate the last sample duration.\n timestamps = new Array(this.samples.length + 1);\n for (let i = 0; i < timestamps.length; ++i) {\n timestamps[i] = profileStartTime + i * interval;\n }\n this.timestamps = timestamps;\n return;\n }\n\n // Convert samples from micro to milliseconds\n for (let i = 0; i < timestamps.length; ++i) {\n timestamps[i] /= 1000;\n }\n if (this.samples.length === timestamps.length) {\n // Add an extra timestamp used to calculate the last sample duration.\n const lastTimestamp = timestamps.at(-1) || 0;\n const averageIntervalTime = (lastTimestamp - timestamps[0]) / (timestamps.length - 1);\n this.timestamps.push(lastTimestamp + averageIntervalTime);\n }\n this.profileStartTime = timestamps.at(0) || this.profileStartTime;\n this.profileEndTime = timestamps.at(-1) || this.profileEndTime;\n }\n\n /**\n * Some nodes do not refer to JS samples but to V8 system tasks, AKA\n * \"meta\" nodes. This function extracts those nodes from the profile.\n */\n private extractMetaNodes(): void {\n const topLevelNodes = this.profileHead.children;\n for (let i = 0; i < topLevelNodes.length && !(this.gcNode && this.programNode && this.idleNode); i++) {\n const node = topLevelNodes[i];\n if (node.functionName === '(garbage collector)') {\n this.gcNode = node;\n } else if (node.functionName === '(program)') {\n this.programNode = node;\n } else if (node.functionName === '(idle)') {\n this.idleNode = node;\n }\n }\n }\n\n private fixMissingSamples(): void {\n // Sometimes the V8 sampler is not able to parse the JS stack and returns\n // a (program) sample instead. The issue leads to call frames being split\n // apart when they shouldn't.\n // Here's a workaround for that. When there's a single (program) sample\n // between two call stacks sharing the same bottom node, it is replaced\n // with the preceeding sample.\n const samples = this.samples;\n if (!samples) {\n return;\n }\n const samplesCount = samples.length;\n if (!this.programNode || samplesCount < 3) {\n return;\n }\n const idToNode = this.#idToParsedNode;\n const programNodeId = this.programNode.id;\n const gcNodeId = this.gcNode ? this.gcNode.id : -1;\n const idleNodeId = this.idleNode ? this.idleNode.id : -1;\n let prevNodeId: number = samples[0];\n let nodeId: number = samples[1];\n for (let sampleIndex = 1; sampleIndex < samplesCount - 1; sampleIndex++) {\n const nextNodeId = samples[sampleIndex + 1];\n const prevNode = idToNode.get(prevNodeId);\n const nextNode = idToNode.get(nextNodeId);\n if (prevNodeId === undefined || nextNodeId === undefined || !prevNode || !nextNode) {\n console.error(`Unexpectedly found undefined nodes: ${prevNodeId} ${nextNodeId}`);\n continue;\n }\n if (nodeId === programNodeId && !isSystemNode(prevNodeId) && !isSystemNode(nextNodeId) &&\n bottomNode(prevNode) === bottomNode(nextNode)) {\n samples[sampleIndex] = prevNodeId;\n }\n prevNodeId = nodeId;\n nodeId = nextNodeId;\n }\n function bottomNode(node: ProfileNode): ProfileNode {\n while (node.parent && node.parent.parent) {\n node = node.parent;\n }\n return node;\n }\n function isSystemNode(nodeId: number): boolean {\n return nodeId === programNodeId || nodeId === gcNodeId || nodeId === idleNodeId;\n }\n }\n\n /**\n * Traverses the call tree derived from the samples calling back when a call is opened\n * and when it's closed\n */\n forEachFrame(\n openFrameCallback: (depth: number, node: ProfileNode, timestamp: number) => void,\n closeFrameCallback: (depth: number, node: ProfileNode, timestamp: number, dur: number, selfTime: number) => void,\n startTime?: number, stopTime?: number): void {\n if (!this.profileHead || !this.samples) {\n return;\n }\n\n startTime = startTime || 0;\n stopTime = stopTime || Infinity;\n const samples = this.samples;\n const timestamps = this.timestamps;\n const idToNode = this.#idToParsedNode;\n const gcNode = this.gcNode;\n const samplesCount = samples.length;\n const startIndex =\n Platform.ArrayUtilities.lowerBound(timestamps, startTime, Platform.ArrayUtilities.DEFAULT_COMPARATOR);\n let stackTop = 0;\n const stackNodes: ProfileNode[] = [];\n let prevId: number = this.profileHead.id;\n let sampleTime;\n let gcParentNode: ProfileNode|null = null;\n\n // Extra slots for gc being put on top,\n // and one at the bottom to allow safe stackTop-1 access.\n const stackDepth = this.maxDepth + 3;\n if (!this.#stackStartTimes) {\n this.#stackStartTimes = new Array(stackDepth);\n }\n const stackStartTimes = this.#stackStartTimes;\n if (!this.#stackChildrenDuration) {\n this.#stackChildrenDuration = new Array(stackDepth);\n }\n const stackChildrenDuration = this.#stackChildrenDuration;\n\n let node;\n let sampleIndex;\n for (sampleIndex = startIndex; sampleIndex < samplesCount; sampleIndex++) {\n sampleTime = timestamps[sampleIndex];\n if (sampleTime >= stopTime) {\n break;\n }\n const id = samples[sampleIndex];\n if (id === prevId) {\n continue;\n }\n node = idToNode.get(id);\n let prevNode: ProfileNode|null = idToNode.get(prevId) || null;\n if (!prevNode) {\n continue;\n }\n\n if (gcNode && node === gcNode) {\n // GC samples have no stack, so we just put GC node on top of the last recorded sample.\n gcParentNode = prevNode;\n openFrameCallback(gcParentNode.depth + 1, gcNode, sampleTime);\n stackStartTimes[++stackTop] = sampleTime;\n stackChildrenDuration[stackTop] = 0;\n prevId = id;\n continue;\n }\n if (gcNode && prevNode === gcNode && gcParentNode) {\n // end of GC frame\n const start = stackStartTimes[stackTop];\n const duration = sampleTime - start;\n stackChildrenDuration[stackTop - 1] += duration;\n closeFrameCallback(gcParentNode.depth + 1, gcNode, start, duration, duration - stackChildrenDuration[stackTop]);\n --stackTop;\n prevNode = gcParentNode;\n prevId = prevNode.id;\n gcParentNode = null;\n }\n\n // If the depth of this node is greater than the depth of the\n // previous one, new calls happened in between and we need to open\n // them, so track all of them in stackNodes.\n while (node && node.depth > prevNode.depth) {\n stackNodes.push(node);\n node = node.parent;\n }\n\n // If `prevNode` differs from `node`, the current sample was taken\n // after a change in the call stack, meaning that frames in the\n // path of `prevNode` that differ from those in the path of `node`\n // can be closed. So go down to the lowest common ancestor and\n // close current intervals.\n //\n // For example:\n //\n // prevNode node\n // | |\n // v v\n // [---D--]\n // [---C--][--E--]\n // [------B------] <- LCA\n // [------A------]\n //\n // Because a sample was taken with A, B and E in the stack, it\n // means C and D finished and we can close them.\n while (prevNode && prevNode !== node) {\n const start = stackStartTimes[stackTop];\n const duration = sampleTime - start;\n stackChildrenDuration[stackTop - 1] += duration;\n closeFrameCallback(prevNode.depth, prevNode, start, duration, duration - stackChildrenDuration[stackTop]);\n --stackTop;\n // Track calls to open after previous calls were closed\n // In the example above, this would add E to the tracking stack.\n if (node && node.depth === prevNode.depth) {\n stackNodes.push(node);\n node = node.parent;\n }\n prevNode = prevNode.parent;\n }\n\n // Go up the nodes stack and open new intervals.\n while (stackNodes.length) {\n const currentNode = stackNodes.pop();\n if (!currentNode) {\n break;\n }\n node = currentNode;\n openFrameCallback(currentNode.depth, currentNode, sampleTime);\n stackStartTimes[++stackTop] = sampleTime;\n stackChildrenDuration[stackTop] = 0;\n }\n\n prevId = id;\n }\n\n // Close remaining intervals.\n sampleTime = timestamps[sampleIndex] || this.profileEndTime;\n if (node && gcParentNode && idToNode.get(prevId) === gcNode) {\n const start = stackStartTimes[stackTop];\n const duration = sampleTime - start;\n stackChildrenDuration[stackTop - 1] += duration;\n closeFrameCallback(gcParentNode.depth + 1, node, start, duration, duration - stackChildrenDuration[stackTop]);\n --stackTop;\n prevId = gcParentNode.id;\n }\n for (let node = idToNode.get(prevId); node && node.parent; node = node.parent) {\n const start = stackStartTimes[stackTop];\n const duration = sampleTime - start;\n stackChildrenDuration[stackTop - 1] += duration;\n closeFrameCallback(node.depth, node, start, duration, duration - stackChildrenDuration[stackTop]);\n --stackTop;\n }\n }\n /**\n * Returns the node that corresponds to a given index of a sample.\n */\n nodeByIndex(index: number): ProfileNode|null {\n return this.samples && this.#idToParsedNode.get(this.samples[index]) || null;\n }\n /**\n * Returns the node that corresponds to a given node id.\n */\n nodeById(nodeId: number): ProfileNode|null {\n return this.#idToParsedNode.get(nodeId) || null;\n }\n\n nodes(): ProfileNode[]|null {\n if (!this.#idToParsedNode) {\n return null;\n }\n return [...this.#idToParsedNode.values()];\n }\n}\n\n// Format used by profiles coming from traces.\nexport type ExtendedProfileNode = Protocol.Profiler.ProfileNode&{parent?: number};\nexport type ExtendedProfile =\n Protocol.Profiler.Profile&{nodes: Protocol.Profiler.ProfileNode[] | ExtendedProfileNode[], lines?: number[]};\n", "// Copyright 2016 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../generated/protocol.js';\nimport type * as Platform from '../../core/platform/platform.js';\n\nexport class ProfileNode {\n callFrame: Protocol.Runtime.CallFrame;\n callUID: string;\n self: number;\n total: number;\n id: number;\n parent: ProfileNode|null;\n children: ProfileNode[];\n functionName: string;\n depth!: number;\n deoptReason!: string|null;\n constructor(callFrame: Protocol.Runtime.CallFrame) {\n this.callFrame = callFrame;\n this.callUID = `${callFrame.functionName}@${callFrame.scriptId}:${callFrame.lineNumber}:${callFrame.columnNumber}`;\n this.self = 0;\n this.total = 0;\n this.id = 0;\n this.functionName = callFrame.functionName;\n this.parent = null;\n this.children = [];\n }\n\n get scriptId(): Protocol.Runtime.ScriptId {\n return String(this.callFrame.scriptId) as Protocol.Runtime.ScriptId;\n }\n\n get url(): Platform.DevToolsPath.UrlString {\n return this.callFrame.url as Platform.DevToolsPath.UrlString;\n }\n\n get lineNumber(): number {\n return this.callFrame.lineNumber;\n }\n\n get columnNumber(): number {\n return this.callFrame.columnNumber;\n }\n\n setFunctionName(name: string|null): void {\n if (name === null) {\n return;\n }\n this.functionName = name;\n }\n}\n\nexport class ProfileTreeModel {\n root!: ProfileNode;\n total!: number;\n maxDepth!: number;\n constructor() {\n }\n\n initialize(root: ProfileNode): void {\n this.root = root;\n this.assignDepthsAndParents();\n this.total = this.calculateTotals(this.root);\n }\n\n private assignDepthsAndParents(): void {\n const root = this.root;\n // TODO(crbug.com/1354548): start depth from 0 once profiler\n // panel dependencies are gone.\n root.depth = -1;\n root.parent = null;\n this.maxDepth = 0;\n const nodesToTraverse = [root];\n while (nodesToTraverse.length) {\n const parent = (nodesToTraverse.pop() as ProfileNode);\n const depth = parent.depth + 1;\n if (depth > this.maxDepth) {\n this.maxDepth = depth;\n }\n const children = parent.children;\n for (const child of children) {\n child.depth = depth;\n child.parent = parent;\n nodesToTraverse.push(child);\n }\n }\n }\n\n private calculateTotals(root: ProfileNode): number {\n const nodesToTraverse = [root];\n const dfsList = [];\n while (nodesToTraverse.length) {\n const node = (nodesToTraverse.pop() as ProfileNode);\n node.total = node.self;\n dfsList.push(node);\n nodesToTraverse.push(...node.children);\n }\n while (dfsList.length > 1) {\n const node = (dfsList.pop() as ProfileNode);\n if (node.parent) {\n node.parent.total += node.total;\n }\n }\n return root.total;\n }\n}\n", "// Copyright 2014 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n//\n// This is what was SDK.TracingModel moved into models/trace to avoid circular dependency issues. Our ultimate goal is to remove this model entirely once the migration to the new model is done\n\n\n\nimport * as Helpers from './helpers/helpers.js';\nimport {type EventPayload} from './TracingManager.js';\nimport * as Types from './types/types.js';\n\ntype IgnoreListArgs = {\n [key: string]: string|number|ObjectSnapshot,\n};\n\nexport class TracingModel {\n readonly #title: string|undefined;\n readonly #processById: Map<string|number, Process>;\n readonly #processByName: Map<string, Process>;\n #minimumRecordTimeInternal: number;\n #maximumRecordTimeInternal: number;\n readonly #devToolsMetadataEventsInternal: Event[];\n #asyncEvents: AsyncEvent[];\n readonly #openAsyncEvents: Map<string, AsyncEvent>;\n readonly #openNestableAsyncEvents: Map<string, AsyncEvent[]>;\n readonly #profileGroups: Map<string, ProfileEventsGroup>;\n readonly #parsedCategories: Map<string, Set<string>>;\n readonly #allEventsPayload: EventPayload[] = [];\n\n constructor(title?: string) {\n this.#title = title;\n this.#processById = new Map();\n this.#processByName = new Map();\n this.#minimumRecordTimeInternal = Number(Infinity);\n this.#maximumRecordTimeInternal = Number(-Infinity);\n this.#devToolsMetadataEventsInternal = [];\n this.#asyncEvents = [];\n this.#openAsyncEvents = new Map();\n this.#openNestableAsyncEvents = new Map();\n this.#profileGroups = new Map();\n this.#parsedCategories = new Map();\n }\n\n static isTopLevelEvent(event: CompatibleTraceEvent): boolean {\n return eventHasCategory(event, DevToolsTimelineEventCategory) && event.name === 'RunTask' ||\n eventHasCategory(event, LegacyTopLevelEventCategory) ||\n eventHasCategory(event, DevToolsMetadataEventCategory) &&\n event.name === 'Program'; // Older timelines may have this instead of toplevel.\n }\n\n static extractId(payload: EventPayload): string|undefined {\n const scope = payload.scope || '';\n if (typeof payload.id2 === 'undefined') {\n return scope && payload.id ? `${scope}@${payload.id}` : payload.id;\n }\n const id2 = payload.id2;\n if (typeof id2 === 'object' && ('global' in id2) !== ('local' in id2)) {\n return typeof id2['global'] !== 'undefined' ? `:${scope}:${id2['global']}` :\n `:${scope}:${payload.pid}:${id2['local']}`;\n }\n console.error(\n `Unexpected id2 field at ${payload.ts / 1000}, one and only one of 'local' and 'global' should be present.`);\n return undefined;\n }\n\n static browserMainThread(tracingModel: TracingModel): Thread|null {\n const processes = tracingModel.sortedProcesses();\n // Avoid warning for an empty #model.\n if (!processes.length) {\n return null;\n }\n const browserMainThreadName = 'CrBrowserMain';\n const browserProcesses = [];\n const browserMainThreads = [];\n for (const process of processes) {\n if (process.name().toLowerCase().endsWith('browser')) {\n browserProcesses.push(process);\n }\n browserMainThreads.push(...process.sortedThreads().filter(t => t.name() === browserMainThreadName));\n }\n if (browserMainThreads.length === 1) {\n return browserMainThreads[0];\n }\n if (browserProcesses.length === 1) {\n return browserProcesses[0].threadByName(browserMainThreadName);\n }\n const tracingStartedInBrowser =\n tracingModel.devToolsMetadataEvents().filter(e => e.name === 'TracingStartedInBrowser');\n if (tracingStartedInBrowser.length === 1) {\n return tracingStartedInBrowser[0].thread;\n }\n console.error(\n 'Failed to find browser main thread in trace, some timeline features may be unavailable');\n return null;\n }\n\n allRawEvents(): readonly EventPayload[] {\n return this.#allEventsPayload;\n }\n\n devToolsMetadataEvents(): Event[] {\n return this.#devToolsMetadataEventsInternal;\n }\n\n addEvents(events: readonly EventPayload[]): void {\n for (let i = 0; i < events.length; ++i) {\n this.addEvent(events[i]);\n }\n }\n\n tracingComplete(): void {\n this.processPendingAsyncEvents();\n for (const process of this.#processById.values()) {\n for (const thread of process.threads.values()) {\n thread.tracingComplete();\n }\n }\n }\n\n private addEvent(payload: EventPayload): void {\n this.#allEventsPayload.push(payload);\n let process = this.#processById.get(payload.pid);\n if (!process) {\n process = new Process(this, payload.pid);\n this.#processById.set(payload.pid, process);\n }\n\n const timestamp = payload.ts / 1000;\n // We do allow records for unrelated threads to arrive out-of-order,\n // so there's a chance we're getting records from the past.\n if (timestamp && timestamp < this.#minimumRecordTimeInternal &&\n eventPhasesOfInterestForTraceBounds.has(payload.ph as Types.TraceEvents.Phase) &&\n // UMA related events are ignored when calculating the minimumRecordTime because they might\n // be related to previous navigations that happened before the current trace started and\n // will currently not be displayed anyways.\n // See crbug.com/1201198\n (!payload.name.endsWith('::UMA'))) {\n this.#minimumRecordTimeInternal = timestamp;\n }\n\n if (payload.name === 'TracingStartedInBrowser') {\n // If we received a timestamp for tracing start, use that for minimumRecordTime.\n this.#minimumRecordTimeInternal = timestamp;\n }\n\n if (eventPhasesOfInterestForTraceBounds.has(payload.ph as Types.TraceEvents.Phase)) {\n const endTimeStamp = (payload.ts + (payload.dur || 0)) / 1000;\n this.#maximumRecordTimeInternal = Math.max(this.#maximumRecordTimeInternal, endTimeStamp);\n }\n const event = process.addEvent(payload);\n if (!event) {\n return;\n }\n if (payload.ph === Types.TraceEvents.Phase.SAMPLE) {\n this.addSampleEvent(event);\n return;\n }\n // Build async event when we've got events from all threads & processes, so we can sort them and process in the\n // chronological order. However, also add individual async events to the thread flow (above), so we can easily\n // display them on the same chart as other events, should we choose so.\n if (Types.TraceEvents.isAsyncPhase(payload.ph)) {\n this.#asyncEvents.push((event as AsyncEvent));\n }\n if (event.hasCategory(DevToolsMetadataEventCategory)) {\n this.#devToolsMetadataEventsInternal.push(event);\n }\n\n if (payload.ph !== Types.TraceEvents.Phase.METADATA) {\n return;\n }\n\n switch (payload.name) {\n case MetadataEvent.ProcessSortIndex: {\n process.setSortIndex(payload.args['sort_index']);\n break;\n }\n case MetadataEvent.ProcessName: {\n const processName = payload.args['name'];\n process.setName(processName);\n this.#processByName.set(processName, process);\n break;\n }\n case MetadataEvent.ThreadSortIndex: {\n process.threadById(payload.tid).setSortIndex(payload.args['sort_index']);\n break;\n }\n case MetadataEvent.ThreadName: {\n process.threadById(payload.tid).setName(payload.args['name']);\n break;\n }\n }\n }\n\n private addSampleEvent(event: Event): void {\n const id = `${event.thread.process().id()}:${event.id}`;\n const group = this.#profileGroups.get(id);\n if (group) {\n group.addChild(event);\n } else {\n this.#profileGroups.set(id, new ProfileEventsGroup(event));\n }\n }\n\n profileGroup(event: Event): ProfileEventsGroup|null {\n return this.#profileGroups.get(`${event.thread.process().id()}:${event.id}`) || null;\n }\n\n minimumRecordTime(): number {\n return this.#minimumRecordTimeInternal;\n }\n\n maximumRecordTime(): number {\n return this.#maximumRecordTimeInternal;\n }\n\n sortedProcesses(): Process[] {\n return NamedObject.sort([...this.#processById.values()]);\n }\n\n getProcessByName(name: string): Process|null {\n return this.#processByName.get(name) ?? null;\n }\n\n getProcessById(pid: number): Process|null {\n return this.#processById.get(pid) || null;\n }\n\n getThreadByName(processName: string, threadName: string): Thread|null {\n const process = this.getProcessByName(processName);\n return process && process.threadByName(threadName);\n }\n\n private processPendingAsyncEvents(): void {\n this.#asyncEvents.sort(Event.compareStartTime);\n for (let i = 0; i < this.#asyncEvents.length; ++i) {\n const event = this.#asyncEvents[i];\n if (Types.TraceEvents.isNestableAsyncPhase(event.phase)) {\n this.addNestableAsyncEvent(event);\n } else {\n this.addAsyncEvent(event);\n }\n }\n this.#asyncEvents = [];\n this.closeOpenAsyncEvents();\n }\n\n private closeOpenAsyncEvents(): void {\n for (const event of this.#openAsyncEvents.values()) {\n event.setEndTime(this.#maximumRecordTimeInternal);\n // FIXME: remove this once we figure a better way to convert async console\n // events to sync [waterfall] timeline records.\n event.steps[0].setEndTime(this.#maximumRecordTimeInternal);\n }\n this.#openAsyncEvents.clear();\n\n for (const eventStack of this.#openNestableAsyncEvents.values()) {\n while (eventStack.length) {\n const event = eventStack.pop();\n if (!event) {\n continue;\n }\n event.setEndTime(this.#maximumRecordTimeInternal);\n }\n }\n this.#openNestableAsyncEvents.clear();\n }\n\n private addNestableAsyncEvent(event: Event): void {\n const key = event.categoriesString + '.' + event.id;\n let openEventsStack = this.#openNestableAsyncEvents.get(key);\n\n switch (event.phase) {\n case Types.TraceEvents.Phase.ASYNC_NESTABLE_START: {\n if (!openEventsStack) {\n openEventsStack = [];\n this.#openNestableAsyncEvents.set(key, openEventsStack);\n }\n const asyncEvent = new AsyncEvent(event);\n openEventsStack.push(asyncEvent);\n event.thread.addAsyncEvent(asyncEvent);\n break;\n }\n\n case Types.TraceEvents.Phase.ASYNC_NESTABLE_INSTANT: {\n if (openEventsStack && openEventsStack.length) {\n const event = openEventsStack[openEventsStack.length - 1];\n if (event) {\n event.addStep(event);\n }\n }\n break;\n }\n\n case Types.TraceEvents.Phase.ASYNC_NESTABLE_END: {\n if (!openEventsStack || !openEventsStack.length) {\n break;\n }\n const top = openEventsStack.pop();\n if (!top) {\n break;\n }\n if (top.name !== event.name) {\n console.error(\n `Begin/end event mismatch for nestable async event, ${top.name} vs. ${event.name}, key: ${key}`);\n break;\n }\n top.addStep(event);\n }\n }\n }\n\n private addAsyncEvent(event: Event): void {\n const key = event.categoriesString + '.' + event.name + '.' + event.id;\n let asyncEvent = this.#openAsyncEvents.get(key);\n\n if (event.phase === Types.TraceEvents.Phase.ASYNC_BEGIN) {\n if (asyncEvent) {\n console.error(`Event ${event.name} has already been started`);\n return;\n }\n asyncEvent = new AsyncEvent(event);\n this.#openAsyncEvents.set(key, asyncEvent);\n event.thread.addAsyncEvent(asyncEvent);\n return;\n }\n if (!asyncEvent) {\n // Quietly ignore stray async events, we're probably too late for the start.\n return;\n }\n if (event.phase === Types.TraceEvents.Phase.ASYNC_END) {\n asyncEvent.addStep(event);\n this.#openAsyncEvents.delete(key);\n return;\n }\n if (event.phase === Types.TraceEvents.Phase.ASYNC_STEP_INTO ||\n event.phase === Types.TraceEvents.Phase.ASYNC_STEP_PAST) {\n const lastStep = asyncEvent.steps[asyncEvent.steps.length - 1];\n if (lastStep && lastStep.phase !== Types.TraceEvents.Phase.ASYNC_BEGIN && lastStep.phase !== event.phase) {\n console.assert(\n false,\n 'Async event step phase mismatch: ' + lastStep.phase + ' at ' + lastStep.startTime + ' vs. ' + event.phase +\n ' at ' + event.startTime);\n return;\n }\n asyncEvent.addStep(event);\n return;\n }\n console.assert(false, 'Invalid async event phase');\n }\n\n title(): string|undefined {\n return this.#title;\n }\n\n parsedCategoriesForString(str: string): Set<string> {\n let parsedCategories = this.#parsedCategories.get(str);\n if (!parsedCategories) {\n parsedCategories = new Set(str ? str.split(',') : []);\n this.#parsedCategories.set(str, parsedCategories);\n }\n return parsedCategories;\n }\n}\n\nexport const eventPhasesOfInterestForTraceBounds: Set<Types.TraceEvents.Phase> = new Set([\n Types.TraceEvents.Phase.BEGIN,\n Types.TraceEvents.Phase.END,\n Types.TraceEvents.Phase.COMPLETE,\n Types.TraceEvents.Phase.INSTANT,\n]);\n\nexport const MetadataEvent = {\n ProcessSortIndex: 'process_sort_index',\n ProcessName: 'process_name',\n ThreadSortIndex: 'thread_sort_index',\n ThreadName: 'thread_name',\n};\n\n// TODO(alph): LegacyTopLevelEventCategory is not recorded since M74 and used for loading\n// legacy profiles. Drop at some point.\nexport const LegacyTopLevelEventCategory = 'toplevel';\n\nexport const DevToolsMetadataEventCategory = 'disabled-by-default-devtools.timeline';\nexport const DevToolsTimelineEventCategory = 'disabled-by-default-devtools.timeline';\n\nexport function eventHasPayload(event: Event): event is PayloadEvent {\n return 'rawPayload' in event;\n}\n\nexport class Event {\n categoriesString: string;\n readonly #parsedCategories: Set<string>;\n name: string;\n phase: Types.TraceEvents.Phase;\n startTime: number;\n thread: Thread;\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n args: any;\n id!: string|null;\n ordinal: number;\n selfTime: number;\n endTime?: number;\n duration?: number;\n\n // The constructor is protected so that we ensure that only classes or\n // subclasses can directly instantiate events. All other callers should\n // either create ConstructedEvent instances, which have a public constructor,\n // or use the static fromPayload method which can create an event instance\n // from the trace payload.\n protected constructor(\n categories: string|undefined, name: string, phase: Types.TraceEvents.Phase, startTime: number, thread: Thread) {\n this.categoriesString = categories || '';\n this.#parsedCategories = thread.getModel().parsedCategoriesForString(this.categoriesString);\n this.name = name;\n this.phase = phase;\n this.startTime = startTime;\n this.thread = thread;\n this.args = {};\n this.ordinal = 0;\n\n this.selfTime = 0;\n }\n\n static compareStartTime(a: Event|null, b: Event|null): number {\n if (!a || !b) {\n return 0;\n }\n\n return a.startTime - b.startTime;\n }\n\n static orderedCompareStartTime(a: Event, b: Event): number {\n // Array.mergeOrdered coalesces objects if comparator returns 0.\n // To change this behavior this comparator return -1 in the case events\n // startTime's are equal, so both events got placed into the result array.\n return a.startTime - b.startTime || a.ordinal - b.ordinal || -1;\n }\n\n hasCategory(categoryName: string): boolean {\n return this.#parsedCategories.has(categoryName);\n }\n\n setEndTime(endTime: number): void {\n if (endTime < this.startTime) {\n console.assert(false, 'Event out of order: ' + this.name);\n return;\n }\n this.endTime = endTime;\n this.duration = endTime - this.startTime;\n }\n\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n addArgs(args: any): void {\n // Shallow copy args to avoid modifying original #payload which may be saved to file.\n for (const name in args) {\n if (name in this.args) {\n console.error('Same argument name (' + name + ') is used for begin and end phases of ' + this.name);\n }\n\n (this.args as IgnoreListArgs)[name] = (args as IgnoreListArgs)[name];\n }\n }\n\n complete(endEvent: Event): void {\n if (endEvent.args) {\n this.addArgs(endEvent.args);\n } else {\n console.error('Missing mandatory event argument \\'args\\' at ' + endEvent.startTime);\n }\n this.setEndTime(endEvent.startTime);\n }\n}\n\n/**\n * Represents a tracing event that is not directly linked to an individual\n * object in the trace. We construct these events at times, particularly when\n * building up the CPU profile data for JS Profiling.\n **/\nexport class ConstructedEvent extends Event {\n // Because the constructor of Event is marked as protected, but we want\n // people to be able to create constructed events, we override the\n // constructor here, even though we are only calling super, in order to mark\n // it as public.\n constructor(\n categories: string|undefined, name: string, phase: Types.TraceEvents.Phase, startTime: number, thread: Thread) {\n super(categories, name, phase, startTime, thread);\n }\n}\n\n/**\n * Represents a tracing event that has been created directly from an object in\n * the trace file and therefore is guaranteed to have a payload associated with\n * it. The only way to create these events is to use the static fromPayload\n * method, which you must call with a payload.\n **/\nexport class PayloadEvent extends Event {\n #rawPayload: EventPayload;\n\n /**\n * Returns the raw payload that was used to create this event instance.\n **/\n rawLegacyPayload(): EventPayload {\n return this.#rawPayload;\n }\n\n /**\n * Returns the raw payload that was used to create this event instance, but\n * returns it typed as the new engine's TraceEventArgs option.\n **/\n rawPayload(): Types.TraceEvents.TraceEventData {\n return this.#rawPayload as unknown as Types.TraceEvents.TraceEventData;\n }\n\n protected constructor(\n categories: string|undefined, name: string, phase: Types.TraceEvents.Phase, startTime: number, thread: Thread,\n rawPayload: EventPayload) {\n super(categories, name, phase, startTime, thread);\n this.#rawPayload = rawPayload;\n }\n\n static fromPayload(payload: EventPayload, thread: Thread): PayloadEvent {\n const event = new PayloadEvent(payload.cat, payload.name, payload.ph, payload.ts / 1000, thread, payload);\n event.#rawPayload = payload;\n if (payload.args) {\n event.addArgs(payload.args);\n }\n if (typeof payload.dur === 'number') {\n event.setEndTime((payload.ts + payload.dur) / 1000);\n }\n const id = TracingModel.extractId(payload);\n if (typeof id !== 'undefined') {\n event.id = id;\n }\n\n return event;\n }\n}\n\nexport class ObjectSnapshot extends PayloadEvent {\n private constructor(\n category: string|undefined, name: string, startTime: number, thread: Thread, rawPayload: EventPayload) {\n super(category, name, Types.TraceEvents.Phase.OBJECT_SNAPSHOT, startTime, thread, rawPayload);\n }\n\n static override fromPayload(payload: EventPayload, thread: Thread): ObjectSnapshot {\n const snapshot = new ObjectSnapshot(payload.cat, payload.name, payload.ts / 1000, thread, payload);\n const id = TracingModel.extractId(payload);\n if (typeof id !== 'undefined') {\n snapshot.id = id;\n }\n if (!payload.args || !payload.args['snapshot']) {\n console.error('Missing mandatory \\'snapshot\\' argument at ' + payload.ts / 1000);\n return snapshot;\n }\n if (payload.args) {\n snapshot.addArgs(payload.args);\n }\n return snapshot;\n }\n\n getSnapshot(): ObjectSnapshot {\n const snapshot = this.args['snapshot'];\n if (!snapshot) {\n throw new Error('ObjectSnapshot has no snapshot argument.');\n }\n return snapshot;\n }\n}\n\nexport class AsyncEvent extends ConstructedEvent {\n steps: Event[];\n causedFrame: boolean;\n\n constructor(startEvent: Event) {\n super(startEvent.categoriesString, startEvent.name, startEvent.phase, startEvent.startTime, startEvent.thread);\n this.addArgs(startEvent.args);\n this.steps = [startEvent];\n this.causedFrame = false;\n }\n\n addStep(event: Event): void {\n this.steps.push(event);\n if (event.phase === Types.TraceEvents.Phase.ASYNC_END ||\n event.phase === Types.TraceEvents.Phase.ASYNC_NESTABLE_END) {\n this.setEndTime(event.startTime);\n // FIXME: ideally, we shouldn't do this, but this makes the logic of converting\n // async console events to sync ones much simpler.\n this.steps[0].setEndTime(event.startTime);\n }\n }\n}\n\nclass ProfileEventsGroup {\n children: Event[];\n constructor(event: Event) {\n this.children = [event];\n }\n\n addChild(event: Event): void {\n this.children.push(event);\n }\n}\n\nclass NamedObject {\n model: TracingModel;\n readonly idInternal: number;\n #nameInternal: string;\n #sortIndex: number;\n constructor(model: TracingModel, id: number) {\n this.model = model;\n this.idInternal = id;\n this.#nameInternal = '';\n this.#sortIndex = 0;\n }\n\n static sort<Item extends NamedObject>(array: Item[]): Item[] {\n return array.sort((a, b) => {\n return a.#sortIndex !== b.#sortIndex ? a.#sortIndex - b.#sortIndex : a.name().localeCompare(b.name());\n });\n }\n\n setName(name: string): void {\n this.#nameInternal = name;\n }\n\n name(): string {\n return this.#nameInternal;\n }\n\n id(): number {\n return this.idInternal;\n }\n\n setSortIndex(sortIndex: number): void {\n this.#sortIndex = sortIndex;\n }\n\n getModel(): TracingModel {\n return this.model;\n }\n}\n\nexport class Process extends NamedObject {\n readonly threads: Map<number, Thread>;\n readonly #threadByNameInternal: Map<string, Thread|null>;\n constructor(model: TracingModel, id: number) {\n super(model, id);\n this.threads = new Map();\n this.#threadByNameInternal = new Map();\n }\n\n threadById(id: number): Thread {\n let thread = this.threads.get(id);\n if (!thread) {\n thread = new Thread(this, id);\n this.threads.set(id, thread);\n }\n return thread;\n }\n\n threadByName(name: string): Thread|null {\n return this.#threadByNameInternal.get(name) || null;\n }\n\n setThreadByName(name: string, thread: Thread): void {\n this.#threadByNameInternal.set(name, thread);\n }\n\n addEvent(payload: EventPayload): Event|null {\n return this.threadById(payload.tid).addEvent(payload);\n }\n\n sortedThreads(): Thread[] {\n return NamedObject.sort([...this.threads.values()]);\n }\n}\n\nexport class Thread extends NamedObject {\n readonly #processInternal: Process;\n #eventsInternal: Event[];\n readonly #asyncEventsInternal: AsyncEvent[];\n #lastTopLevelEvent: Event|null;\n constructor(process: Process, id: number) {\n super(process.getModel(), id);\n this.#processInternal = process;\n\n this.#eventsInternal = [];\n this.#asyncEventsInternal = [];\n this.#lastTopLevelEvent = null;\n }\n\n /**\n * Whilst we are in the middle of migrating to the new Phase enum, we need to\n * be able to compare events with the legacy phase to the new enum. This method\n * does this by casting the event phase to a string, ensuring we can compare it\n * against either enum. Once the migration is complete (crbug.com/1417587), we\n * will be able to use === to compare with no TS errors and this method can be\n * removed.\n */\n #eventMatchesPhase(event: Event, phase: Types.TraceEvents.Phase): boolean {\n return (event.phase as string) === phase;\n }\n\n tracingComplete(): void {\n this.#asyncEventsInternal.sort(Event.compareStartTime);\n this.#eventsInternal.sort(Event.compareStartTime);\n const stack: Event[] = [];\n const toDelete = new Set<number>();\n for (let i = 0; i < this.#eventsInternal.length; ++i) {\n const e = this.#eventsInternal[i];\n e.ordinal = i;\n if (this.#eventMatchesPhase(e, Types.TraceEvents.Phase.END)) {\n toDelete.add(i); // Mark for removal.\n // Quietly ignore unbalanced close events, they're legit (we could have missed start one).\n if (!stack.length) {\n continue;\n }\n const top = stack.pop();\n if (!top) {\n continue;\n }\n if (top.name !== e.name || top.categoriesString !== e.categoriesString) {\n console.error(\n 'B/E events mismatch at ' + top.startTime + ' (' + top.name + ') vs. ' + e.startTime + ' (' + e.name +\n ')');\n } else {\n top.complete(e);\n }\n } else if (this.#eventMatchesPhase(e, Types.TraceEvents.Phase.BEGIN)) {\n stack.push(e);\n }\n }\n\n // Handle Begin events with no matching End.\n // This commonly happens due to a bug in the trace machinery. See crbug.com/982252\n while (stack.length) {\n const event = stack.pop();\n if (event) {\n // Masquerade the event as Instant, so it's rendered to the user.\n // The ideal fix is resolving crbug.com/1021571, but handling that without a perfetto migration appears prohibitive\n event.phase = Types.TraceEvents.Phase.INSTANT;\n }\n }\n this.#eventsInternal = this.#eventsInternal.filter((_, idx) => !toDelete.has(idx));\n }\n\n addEvent(payload: EventPayload): Event|null {\n const event = payload.ph === Types.TraceEvents.Phase.OBJECT_SNAPSHOT ? ObjectSnapshot.fromPayload(payload, this) :\n PayloadEvent.fromPayload(payload, this);\n if (TracingModel.isTopLevelEvent(event)) {\n // Discard nested \"top-level\" events.\n const lastTopLevelEvent = this.#lastTopLevelEvent;\n if (lastTopLevelEvent && (lastTopLevelEvent.endTime || 0) > event.startTime) {\n return null;\n }\n this.#lastTopLevelEvent = event;\n }\n this.#eventsInternal.push(event);\n return event;\n }\n\n addAsyncEvent(asyncEvent: AsyncEvent): void {\n this.#asyncEventsInternal.push(asyncEvent);\n }\n\n override setName(name: string): void {\n super.setName(name);\n this.#processInternal.setThreadByName(name, this);\n }\n\n process(): Process {\n return this.#processInternal;\n }\n\n events(): Event[] {\n return this.#eventsInternal;\n }\n\n asyncEvents(): AsyncEvent[] {\n return this.#asyncEventsInternal;\n }\n\n removeEventsByName(name: string): Event[] {\n const extracted: Event[] = [];\n this.#eventsInternal = this.#eventsInternal.filter(e => {\n if (!e) {\n return false;\n }\n\n if (e.name !== name) {\n return true;\n }\n\n extracted.push(e);\n return false;\n });\n\n return extracted;\n }\n}\n\nexport interface TimesForEventMs {\n startTime: Types.Timing.MilliSeconds;\n endTime?: Types.Timing.MilliSeconds;\n selfTime: Types.Timing.MilliSeconds;\n duration: Types.Timing.MilliSeconds;\n}\n\nexport function timesForEventInMilliseconds(event: Event|Types.TraceEvents.TraceEventData): TimesForEventMs {\n if (event instanceof Event) {\n return {\n startTime: Types.Timing.MilliSeconds(event.startTime),\n endTime: event.endTime ? Types.Timing.MilliSeconds(event.endTime) : undefined,\n duration: Types.Timing.MilliSeconds(event.duration || 0),\n selfTime: Types.Timing.MilliSeconds(event.selfTime),\n };\n }\n return Helpers.Timing.eventTimingsMilliSeconds(event);\n}\n// Parsed categories are cached to prevent calling cat.split() multiple\n// times on the same categories string.\nconst parsedCategories = new Map<string, Set<string>>();\nexport function eventHasCategory(event: CompatibleTraceEvent, category: string): boolean {\n if (event instanceof Event) {\n return event.hasCategory(category);\n }\n let parsedCategoriesForEvent = parsedCategories.get(event.cat);\n if (!parsedCategoriesForEvent) {\n parsedCategoriesForEvent = new Set(event.cat.split(',') || []);\n }\n return parsedCategoriesForEvent.has(category);\n}\n\nexport function phaseForEvent(event: Event|Types.TraceEvents.TraceEventData): Types.TraceEvents.Phase {\n if (event instanceof Event) {\n return event.phase;\n }\n return event.ph;\n}\n\nexport function threadIDForEvent(event: Event|Types.TraceEvents.TraceEventData): Types.TraceEvents.ThreadID {\n if (event instanceof Event) {\n return event.thread.idInternal as Types.TraceEvents.ThreadID;\n }\n return event.tid;\n}\n\nexport function eventIsFromNewEngine(event: CompatibleTraceEvent|null): event is Types.TraceEvents.TraceEventData {\n return event !== null && !(event instanceof Event);\n}\n\nexport type CompatibleTraceEvent = Event|Types.TraceEvents.TraceEventData;\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../core/platform/platform.js';\n\nimport * as Handlers from './handlers/handlers.js';\nimport * as Helpers from './helpers/helpers.js';\nimport {TraceParseProgressEvent, TraceProcessor} from './Processor.js';\nimport * as Types from './types/types.js';\n\n// Note: this model is implemented in a way that can support multiple trace\n// processors. Currently there is only one implemented, but you will see\n// references to \"processors\" plural because it can easily be extended in the future.\n\nexport interface ParseConfig {\n metadata?: Types.File.MetaData;\n // Unused but will eventually be consumed by UIUtils Linkifier, etc.\n isFreshRecording?: boolean;\n}\n\n/**\n * The new trace engine model we are migrating to. The Model is responsible for\n * parsing arrays of raw trace events and storing the resulting data. It can\n * store multiple traces at once, and can return the data for any of them.\n * Currently as we migrate from the old engine to this, we are turning on the\n * model handlers incrementally as we need the data, to save performance costs\n * of running handlers that we do not use. Therefore, when the model is\n * constructed we pass through a set of handlers that should be used. Once we\n * have migrated all tracks in the Performance Panel to this model, we can\n * remove this ability to run a subset of handlers, as we will need all handlers\n * to be used at that point. For tests, if you want to construct a model with\n * all handlers, you can use the static `Model.createWithAllHandlers` method.\n **/\nexport class Model<EnabledModelHandlers extends {[key: string]: Handlers.Types.TraceEventHandler}> extends EventTarget {\n readonly #traces: ParsedTraceFile<EnabledModelHandlers>[] = [];\n readonly #nextNumberByDomain = new Map<string, number>();\n\n readonly #recordingsAvailable: string[] = [];\n #lastRecordingIndex = 0;\n #processor: TraceProcessor<Handlers.Types.HandlersWithMeta<EnabledModelHandlers>>;\n #config: Types.Configuration.Configuration = Types.Configuration.DEFAULT;\n\n static createWithAllHandlers(): Model<typeof Handlers.ModelHandlers> {\n return new Model(Handlers.ModelHandlers);\n }\n\n static createWithRequiredHandlersForMigration(config?: Types.Configuration.Configuration): Model<{\n [K in keyof typeof Handlers.Migration.ENABLED_TRACE_HANDLERS]: typeof Handlers.Migration.ENABLED_TRACE_HANDLERS[K];\n }> {\n return new Model(Handlers.Migration.ENABLED_TRACE_HANDLERS, config);\n }\n\n constructor(handlers: EnabledModelHandlers, config?: Types.Configuration.Configuration) {\n super();\n if (config) {\n this.#config = config;\n }\n this.#processor = new TraceProcessor(handlers, this.#config);\n }\n\n /**\n * Updates the configuration. Useful if a user changes a setting - this lets\n * us update the model without having to destroy it and recreate it with the\n * new settings.\n */\n updateConfiguration(config: Types.Configuration.Configuration): void {\n this.#config = config;\n this.#processor.updateConfiguration(config);\n }\n\n /**\n * Parses an array of trace events into a structured object containing all the\n * information parsed by the trace handlers.\n * You can `await` this function to pause execution until parsing is complete,\n * or instead rely on the `ModuleUpdateEvent` that is dispatched when the\n * parsing is finished.\n *\n * Once parsed, you then have to call the `traceParsedData` method, providing an\n * index of the trace you want to have the data for. This is because any model\n * can store a number of traces. Each trace is given an index, which starts at 0\n * and increments by one as a new trace is parsed.\n *\n * @example\n * // Awaiting the parse method() to block until parsing complete\n * await this.traceModel.parse(events);\n * const data = this.traceModel.traceParsedData(0)\n *\n * @example\n * // Using an event listener to be notified when tracing is complete.\n * this.traceModel.addEventListener(Trace.ModelUpdateEvent.eventName, (event) => {\n * if(event.data.data === 'done') {\n * // trace complete\n * const data = this.traceModel.traceParsedData(0);\n * }\n * });\n * void this.traceModel.parse(events);\n **/\n async parse(traceEvents: readonly Types.TraceEvents.TraceEventData[], config?: ParseConfig): Promise<void> {\n const metadata = config?.metadata || {};\n const isFreshRecording = config?.isFreshRecording || false;\n // During parsing, periodically update any listeners on each processors'\n // progress (if they have any updates).\n const onTraceUpdate = (event: Event): void => {\n const {data} = event as TraceParseProgressEvent;\n this.dispatchEvent(new ModelUpdateEvent({type: ModelUpdateType.PROGRESS_UPDATE, data: data}));\n };\n\n this.#processor.addEventListener(TraceParseProgressEvent.eventName, onTraceUpdate);\n\n // Create a parsed trace file. It will be populated with data from the processor.\n const file: ParsedTraceFile<EnabledModelHandlers> = {\n traceEvents,\n metadata,\n traceParsedData: null,\n };\n\n try {\n // Wait for all outstanding promises before finishing the async execution,\n // but perform all tasks in parallel.\n await this.#processor.parse(traceEvents, isFreshRecording);\n this.#storeParsedFileData(file, this.#processor.data);\n // We only push the file onto this.#traces here once we know it's valid\n // and there's been no errors in the parsing.\n this.#traces.push(file);\n } catch (e) {\n throw e;\n } finally {\n // All processors have finished parsing, no more updates are expected.\n this.#processor.removeEventListener(TraceParseProgressEvent.eventName, onTraceUpdate);\n // Finally, update any listeners that all processors are 'done'.\n this.dispatchEvent(new ModelUpdateEvent({type: ModelUpdateType.COMPLETE, data: 'done'}));\n }\n }\n\n #storeParsedFileData(\n file: ParsedTraceFile<EnabledModelHandlers>,\n data: Handlers.Types.EnabledHandlerDataWithMeta<EnabledModelHandlers>|null): void {\n file.traceParsedData = data;\n this.#lastRecordingIndex++;\n let recordingName = `Trace ${this.#lastRecordingIndex}`;\n let origin: string|null = null;\n if (file.traceParsedData) {\n origin = Helpers.Trace.extractOriginFromTrace(file.traceParsedData.Meta.mainFrameURL);\n if (origin) {\n const nextSequenceForDomain = Platform.MapUtilities.getWithDefault(this.#nextNumberByDomain, origin, () => 1);\n recordingName = `${origin} (${nextSequenceForDomain})`;\n this.#nextNumberByDomain.set(origin, nextSequenceForDomain + 1);\n }\n }\n this.#recordingsAvailable.push(recordingName);\n }\n\n /**\n * Returns the parsed trace data indexed by the order in which it was stored.\n * If no index is given, the last stored parsed data is returned.\n */\n traceParsedData(index: number = this.#traces.length - 1):\n Handlers.Types.EnabledHandlerDataWithMeta<EnabledModelHandlers>|null {\n if (!this.#traces[index]) {\n return null;\n }\n\n return this.#traces[index].traceParsedData;\n }\n\n metadata(index: number): Types.File.MetaData|null {\n if (!this.#traces[index]) {\n return null;\n }\n\n return this.#traces[index].metadata;\n }\n\n traceEvents(index: number): readonly Types.TraceEvents.TraceEventData[]|null {\n if (!this.#traces[index]) {\n return null;\n }\n\n return this.#traces[index].traceEvents;\n }\n\n size(): number {\n return this.#traces.length;\n }\n\n deleteTraceByIndex(recordingIndex: number): void {\n this.#traces.splice(recordingIndex, 1);\n this.#recordingsAvailable.splice(recordingIndex, 1);\n }\n\n getRecordingsAvailable(): string[] {\n return this.#recordingsAvailable;\n }\n\n resetProcessor(): void {\n this.#processor.reset();\n }\n}\n\n/**\n * This parsed trace file is used by the Model. It keeps multiple instances\n * of these so that the user can swap between them. The key is that it is\n * essentially the TraceFile plus whatever the model has parsed from it.\n */\nexport type ParsedTraceFile<Handlers extends {[key: string]: Handlers.Types.TraceEventHandler}> = Types.File.TraceFile&{\n traceParsedData: Handlers.Types.EnabledHandlerDataWithMeta<Handlers>| null,\n};\n\nexport const enum ModelUpdateType {\n COMPLETE = 'COMPLETE',\n PROGRESS_UPDATE = 'PROGRESS_UPDATE',\n}\n\nexport type ModelUpdateEventData = ModelUpdateEventComplete|ModelUpdateEventProgress;\n\nexport type ModelUpdateEventComplete = {\n type: ModelUpdateType.COMPLETE,\n data: 'done',\n};\nexport type ModelUpdateEventProgress = {\n type: ModelUpdateType.PROGRESS_UPDATE,\n data: TraceParseEventProgressData,\n};\n\nexport type TraceParseEventProgressData = {\n index: number,\n total: number,\n};\n\nexport class ModelUpdateEvent extends Event {\n static readonly eventName = 'modelupdate';\n constructor(public data: ModelUpdateEventData) {\n super(ModelUpdateEvent.eventName);\n }\n}\n\ndeclare global {\n interface HTMLElementEventMap {\n [ModelUpdateEvent.eventName]: ModelUpdateEvent;\n }\n}\n\nexport function isModelUpdateDataComplete(eventData: ModelUpdateEventData): eventData is ModelUpdateEventComplete {\n return eventData.type === ModelUpdateType.COMPLETE;\n}\n\nexport function isModelUpdateDataProgress(eventData: ModelUpdateEventData): eventData is ModelUpdateEventProgress {\n return eventData.type === ModelUpdateType.PROGRESS_UPDATE;\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\nimport * as Handlers from './handlers/handlers.js';\nimport * as Types from './types/types.js';\n\nconst enum Status {\n IDLE = 'IDLE',\n PARSING = 'PARSING',\n FINISHED_PARSING = 'FINISHED_PARSING',\n ERRORED_WHILE_PARSING = 'ERRORED_WHILE_PARSING',\n}\n\nexport type TraceParseEventProgressData = {\n index: number,\n total: number,\n};\n\nexport class TraceParseProgressEvent extends Event {\n static readonly eventName = 'traceparseprogress';\n constructor(public data: TraceParseEventProgressData, init: EventInit = {bubbles: true}) {\n super(TraceParseProgressEvent.eventName, init);\n }\n}\ndeclare global {\n interface HTMLElementEventMap {\n [TraceParseProgressEvent.eventName]: TraceParseProgressEvent;\n }\n}\n\nexport class TraceProcessor<EnabledModelHandlers extends {[key: string]: Handlers.Types.TraceEventHandler}> extends\n EventTarget {\n // We force the Meta handler to be enabled, so the TraceHandlers type here is\n // the model handlers the user passes in and the Meta handler.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n readonly #traceHandlers: Handlers.Types.HandlersWithMeta<EnabledModelHandlers>;\n #status = Status.IDLE;\n #modelConfiguration = Types.Configuration.DEFAULT;\n\n static createWithAllHandlers(): TraceProcessor<typeof Handlers.ModelHandlers> {\n return new TraceProcessor(Handlers.ModelHandlers, Types.Configuration.DEFAULT);\n }\n\n constructor(traceHandlers: EnabledModelHandlers, modelConfiguration?: Types.Configuration.Configuration) {\n super();\n\n this.#verifyHandlers(traceHandlers);\n this.#traceHandlers = {\n Meta: Handlers.ModelHandlers.Meta,\n ...traceHandlers,\n };\n if (modelConfiguration) {\n this.#modelConfiguration = modelConfiguration;\n }\n this.#passConfigToHandlers();\n }\n\n updateConfiguration(config: Types.Configuration.Configuration): void {\n this.#modelConfiguration = config;\n this.#passConfigToHandlers();\n }\n\n #passConfigToHandlers(): void {\n for (const handler of Object.values(this.#traceHandlers)) {\n // Bit of an odd double check, but without this TypeScript refuses to let\n // you call the function as it thinks it might be undefined.\n if ('handleUserConfig' in handler && handler.handleUserConfig) {\n handler.handleUserConfig(this.#modelConfiguration);\n }\n }\n }\n\n /**\n * When the user passes in a set of handlers, we want to ensure that we have all\n * the required handlers. Handlers can depend on other handlers, so if the user\n * passes in FooHandler which depends on BarHandler, they must also pass in\n * BarHandler too. This method verifies that all dependencies are met, and\n * throws if not.\n **/\n #verifyHandlers(providedHandlers: EnabledModelHandlers): void {\n // Tiny optimisation: if the amount of provided handlers matches the amount\n // of handlers in the Handlers.ModelHandlers object, that means that the\n // user has passed in every handler we have. So therefore they cannot have\n // missed any, and there is no need to iterate through the handlers and\n // check the dependencies.\n if (Object.keys(providedHandlers).length === Object.keys(Handlers.ModelHandlers).length) {\n return;\n }\n const requiredHandlerKeys: Set<Handlers.Types.TraceEventHandlerName> = new Set();\n for (const [handlerName, handler] of Object.entries(providedHandlers)) {\n requiredHandlerKeys.add(handlerName as Handlers.Types.TraceEventHandlerName);\n for (const depName of (handler.deps?.() || [])) {\n requiredHandlerKeys.add(depName);\n }\n }\n\n const providedHandlerKeys = new Set(Object.keys(providedHandlers));\n // We always force the Meta handler to be enabled when creating the\n // Processor, so if it is missing from the set the user gave us that is OK,\n // as we will have enabled it anyway.\n requiredHandlerKeys.delete('Meta');\n\n for (const requiredKey of requiredHandlerKeys) {\n if (!providedHandlerKeys.has(requiredKey)) {\n throw new Error(`Required handler ${requiredKey} not provided.`);\n }\n }\n }\n\n reset(): void {\n if (this.#status === Status.PARSING) {\n throw new Error('Trace processor can\\'t reset while parsing.');\n }\n\n const handlers = Object.values(this.#traceHandlers);\n for (const handler of handlers) {\n handler.reset();\n }\n\n this.#status = Status.IDLE;\n }\n\n async parse(traceEvents: readonly Types.TraceEvents.TraceEventData[], freshRecording = false): Promise<void> {\n if (this.#status !== Status.IDLE) {\n throw new Error(`Trace processor can't start parsing when not idle. Current state: ${this.#status}`);\n }\n try {\n this.#status = Status.PARSING;\n await this.#parse(traceEvents, freshRecording);\n this.#status = Status.FINISHED_PARSING;\n } catch (e) {\n this.#status = Status.ERRORED_WHILE_PARSING;\n throw e;\n }\n }\n\n async #parse(traceEvents: readonly Types.TraceEvents.TraceEventData[], freshRecording: boolean): Promise<void> {\n // This iterator steps through all events, periodically yielding back to the\n // main thread to avoid blocking execution. It uses `dispatchEvent` to\n // provide status update events, and other various bits of config like the\n // pause duration and frequency.\n const {pauseDuration, eventsPerChunk} = this.#modelConfiguration.processing;\n const traceEventIterator = new TraceEventIterator(traceEvents, pauseDuration, eventsPerChunk);\n\n // Convert to array so that we are able to iterate all handlers multiple times.\n const sortedHandlers = [...sortHandlers(this.#traceHandlers).values()];\n // Reset.\n for (const handler of sortedHandlers) {\n handler.reset();\n }\n\n // Initialize.\n for (const handler of sortedHandlers) {\n handler.initialize?.(freshRecording);\n }\n\n // Handle each event.\n for await (const item of traceEventIterator) {\n if (item.kind === IteratorItemType.STATUS_UPDATE) {\n this.dispatchEvent(new TraceParseProgressEvent(item.data));\n continue;\n }\n for (const handler of sortedHandlers) {\n handler.handleEvent(item.data);\n }\n }\n\n // Finalize.\n for (const handler of sortedHandlers) {\n await handler.finalize?.();\n }\n }\n\n get data(): Handlers.Types.EnabledHandlerDataWithMeta<EnabledModelHandlers>|null {\n if (this.#status !== Status.FINISHED_PARSING) {\n return null;\n }\n\n const data = {};\n for (const [name, handler] of Object.entries(this.#traceHandlers)) {\n Object.assign(data, {[name]: handler.data()});\n }\n\n return data as Handlers.Types.EnabledHandlerDataWithMeta<EnabledModelHandlers>;\n }\n}\n\n/**\n * Some Handlers need data provided by others. Dependencies of a handler handler are\n * declared in the `deps` field.\n * @returns A map from trace event handler name to trace event hander whose entries\n * iterate in such a way that each handler is visited after its dependencies.\n */\nexport function sortHandlers(\n traceHandlers: Partial<{[key in Handlers.Types.TraceEventHandlerName]: Handlers.Types.TraceEventHandler}>):\n Map<Handlers.Types.TraceEventHandlerName, Handlers.Types.TraceEventHandler> {\n const sortedMap = new Map<Handlers.Types.TraceEventHandlerName, Handlers.Types.TraceEventHandler>();\n const visited = new Set<Handlers.Types.TraceEventHandlerName>();\n const visitHandler = (handlerName: Handlers.Types.TraceEventHandlerName): void => {\n if (sortedMap.has(handlerName)) {\n return;\n }\n if (visited.has(handlerName)) {\n let stackPath = '';\n for (const handler of visited) {\n if (stackPath || handler === handlerName) {\n stackPath += `${handler}->`;\n }\n }\n stackPath += handlerName;\n throw new Error(`Found dependency cycle in trace event handlers: ${stackPath}`);\n }\n visited.add(handlerName);\n const handler = traceHandlers[handlerName];\n if (!handler) {\n return;\n }\n const deps = handler.deps?.();\n if (deps) {\n deps.forEach(visitHandler);\n }\n sortedMap.set(handlerName, handler);\n };\n\n for (const handlerName of Object.keys(traceHandlers)) {\n visitHandler(handlerName as Handlers.Types.TraceEventHandlerName);\n }\n return sortedMap;\n}\n\nconst enum IteratorItemType {\n TRACE_EVENT = 1,\n STATUS_UPDATE = 2,\n}\n\ntype IteratorItem = IteratorTraceEventItem|IteratorStatusUpdateItem;\n\ntype IteratorTraceEventItem = {\n kind: IteratorItemType.TRACE_EVENT,\n data: Types.TraceEvents.TraceEventData,\n};\n\ntype IteratorStatusUpdateItem = {\n kind: IteratorItemType.STATUS_UPDATE,\n data: TraceParseEventProgressData,\n};\n\nclass TraceEventIterator {\n #eventCount: number;\n\n constructor(\n private traceEvents: readonly Types.TraceEvents.TraceEventData[], private pauseDuration: number,\n private eventsPerChunk: number) {\n this.#eventCount = 0;\n }\n\n async * [Symbol.asyncIterator](): AsyncGenerator<IteratorItem, void, void> {\n for (let i = 0, length = this.traceEvents.length; i < length; i++) {\n // Every so often we take a break just to render.\n if (++this.#eventCount % this.eventsPerChunk === 0) {\n // Take the opportunity to provide status update events.\n yield {kind: IteratorItemType.STATUS_UPDATE, data: {index: i, total: length}};\n // Wait for rendering before resuming.\n await new Promise(resolve => setTimeout(resolve, this.pauseDuration));\n }\n\n yield {kind: IteratorItemType.TRACE_EVENT, data: this.traceEvents[i]};\n }\n }\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\nimport * as Platform from '../../core/platform/platform.js';\n\nimport type * as Handlers from './handlers/handlers.js';\nimport type * as Types from './types/types.js';\n\ntype EntryToNodeMap = Map<Types.TraceEvents.RendererEntry, Handlers.ModelHandlers.Renderer.RendererEntryNode>;\n\nexport interface UserTreeAction {\n type: 'MERGE_FUNCTION'|'COLLAPSE_FUNCTION';\n entry: Types.TraceEvents.RendererEntry;\n}\n\n/**\n * This class can take in a thread that has been generated by the\n * RendererHandler and apply certain actions to it in order to modify what is\n * shown to the user. These actions can be automatically applied by DevTools or\n * applied by the user.\n *\n * Once actions are applied, the visibleEntries() method will return only the\n * entries that are still visible, and this is the list of entries that can\n * then be used to render the resulting thread on the timeline.\n **/\nexport class TreeManipulator {\n readonly #thread: Handlers.ModelHandlers.Renderer.RendererThread;\n // Maps from an individual TraceEvent entry to its representation as a\n // RendererEntryNode. We need this so we can then parse the tree structure\n // generated by the RendererHandler.\n #entryToNode: EntryToNodeMap;\n\n // Track the last calculated set of visible entries. This means we can avoid\n // re-generating this if the set of actions that have been applied has not\n // changed.\n #lastVisibleEntries: readonly Types.TraceEvents.RendererEntry[]|null = null;\n #activeActions: UserTreeAction[] = [];\n\n constructor(\n thread: Handlers.ModelHandlers.Renderer.RendererThread,\n entryToNode: EntryToNodeMap,\n ) {\n this.#thread = thread;\n this.#entryToNode = entryToNode;\n }\n\n /**\n * Applies an action to the visible tree. This will also clear the cache of\n * visible entries, ensuring that it will be recalculated with the latest set\n * of actions.\n **/\n applyAction(action: UserTreeAction): void {\n if (this.#actionIsActive(action)) {\n // If the action is already active there is no reason to apply it again.\n return;\n }\n\n this.#activeActions.push(action);\n // Clear the last list of visible entries - this invalidates the cache and\n // ensures that the visible list will be recalculated, which we have to do\n // now we have changed the list of actions.\n this.#lastVisibleEntries = null;\n }\n\n /**\n * Removes a matching action, if one is found, from the active actions set.\n * Note that we do not match on action equality and instead search through\n * the set of active actions for one that is of the same type, and has the\n * same entry associated with it.\n *\n * This is a no-op if the action is not active.\n **/\n removeActiveAction(action: UserTreeAction): void {\n let removedAction = false;\n this.#activeActions = this.#activeActions.filter(activeAction => {\n if (activeAction.type === action.type && activeAction.entry === action.entry) {\n removedAction = true;\n return false;\n }\n return true;\n });\n\n if (removedAction) {\n // If we found and removed an action, we need to clear the cache to force\n // the set of visible entries to be recalculcated.\n this.#lastVisibleEntries = null;\n }\n }\n\n #actionIsActive(action: UserTreeAction): boolean {\n return this.#activeActions.some(activeAction => {\n return action.entry === activeAction.entry && action.type === activeAction.type;\n });\n }\n\n /**\n * The set of entries that are visible given the set of applied actions. If\n * no actions are applied, this will return all entries in the thread.\n *\n * This method is cached, so it is safe to call multiple times.\n **/\n visibleEntries(): readonly Types.TraceEvents.TraceEventData[] {\n if (this.#activeActions.length === 0) {\n return this.#thread.entries;\n }\n return this.#calculateVisibleEntries();\n }\n\n #calculateVisibleEntries(): readonly Types.TraceEvents.TraceEventData[] {\n // When an action is added, we clear this cache. So if this cache is\n // present it means that the set of active actions has not changed, and so\n // we do not need to recalculate anything.\n if (this.#lastVisibleEntries) {\n return this.#lastVisibleEntries;\n }\n\n if (!this.#thread.tree) {\n // We need a tree to be able to calculate user actions, if we do not have\n // it, just return all the entries.\n return this.#thread.entries;\n }\n\n // We apply each user action in turn to the set of all entries, and mark\n // any that should be hidden by adding them to this set. We do this to\n // ensure we minimise the amount of passes through the list of all entries.\n // Another approach would be to use splice() to remove items from the\n // array, but doing this would be a mutation of the arry for every hidden\n // event. Instead, we add entries to this set, and at the very end loop\n // through the entries array once to filter out any that should be hidden.\n const entriesToHide = new Set<Types.TraceEvents.RendererEntry>();\n\n const entries = [...this.#thread.entries];\n for (const action of this.#activeActions) {\n switch (action.type) {\n case 'MERGE_FUNCTION': {\n // The entry that was clicked on is merged into its parent. All its\n // children remain visible, so we just have to hide the entry that was\n // selected.\n entriesToHide.add(action.entry);\n break;\n }\n\n case 'COLLAPSE_FUNCTION': {\n // The entry itself remains visible, but all of its ancestors are hidden.\n const entryNode = this.#entryToNode.get(action.entry);\n if (!entryNode) {\n // Invalid node was given, just ignore and move on.\n continue;\n }\n const allAncestors = this.#findAllAncestorsOfNode(entryNode);\n allAncestors.forEach(ancestor => entriesToHide.add(ancestor));\n break;\n }\n default:\n Platform.assertNever(action.type, `Unknown TreeManipulator action: ${action.type}`);\n }\n }\n\n // Now we have applied all actions, loop through the list of entries and\n // remove any that are marked as hidden.\n // We cache this under lastVisibleEntries - if this function is called\n // again and the user actions have not changed, we can avoid recalculating\n // this and just return the last one. This cache is automatically cleared\n // when the user actions are changed.\n this.#lastVisibleEntries = entries.filter(entry => {\n return entriesToHide.has(entry) === false;\n });\n\n return this.#lastVisibleEntries;\n }\n\n #findAllAncestorsOfNode(\n root: Handlers.ModelHandlers.Renderer.RendererEntryNode): Types.TraceEvents.RendererEntry[] {\n const ancestors: Types.TraceEvents.RendererEntry[] = [];\n\n // Walk through all the ancestors, starting at the root node.\n const children: Handlers.ModelHandlers.Renderer.RendererEntryNode[] = Array.from(root.children);\n while (children.length > 0) {\n const childNode = children.shift();\n if (childNode) {\n ancestors.push(childNode.entry);\n const newChildIds = Array.from(childNode.children);\n children.push(...newChildIds);\n }\n }\n\n return ancestors;\n }\n}\n"],
5
- "mappings": "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",
3
+ "sources": ["../../../../front_end/models/trace/trace.ts", "../../../../front_end/models/trace/handlers/handlers.ts", "../../../../front_end/models/trace/handlers/Migration.ts", "../../../../front_end/models/trace/handlers/AnimationHandler.ts", "../../../../front_end/core/platform/array-utilities.ts", "../../../../front_end/core/platform/map-utilities.ts", "../../../../front_end/core/platform/number-utilities.ts", "../../../../front_end/core/platform/typescript-utilities.ts", "../../../../front_end/models/trace/types/types.ts", "../../../../front_end/models/trace/types/Configuration.ts", "../../../../front_end/models/trace/types/File.ts", "../../../../front_end/models/trace/types/Timing.ts", "../../../../front_end/models/trace/types/TraceEvents.ts", "../../../../front_end/models/trace/handlers/types.ts", "../../../../front_end/models/trace/handlers/AuctionWorkletsHandler.ts", "../../../../front_end/models/trace/handlers/GPUHandler.ts", "../../../../front_end/models/trace/handlers/MetaHandler.ts", "../../../../front_end/models/trace/helpers/helpers.ts", "../../../../front_end/models/trace/helpers/SamplesIntegrator.ts", "../../../../front_end/models/trace/helpers/Timing.ts", "../../../../front_end/models/trace/helpers/Trace.ts", "../../../../front_end/models/trace/helpers/TreeHelpers.ts", "../../../../front_end/models/trace/handlers/LayoutShiftsHandler.ts", "../../../../front_end/models/trace/handlers/PageLoadMetricsHandler.ts", "../../../../front_end/models/trace/handlers/ScreenshotsHandler.ts", "../../../../front_end/models/trace/handlers/MemoryHandler.ts", "../../../../front_end/models/trace/handlers/NetworkRequestsHandler.ts", "../../../../front_end/models/trace/handlers/UserInteractionsHandler.ts", "../../../../front_end/models/trace/handlers/UserTimingsHandler.ts", "../../../../front_end/models/trace/handlers/WarningsHandler.ts", "../../../../front_end/models/trace/handlers/WorkersHandler.ts", "../../../../front_end/models/trace/handlers/ModelHandlers.ts", "../../../../front_end/models/trace/handlers/LargestImagePaintHandler.ts", "../../../../front_end/models/trace/handlers/LargestTextPaintHandler.ts", "../../../../front_end/models/trace/handlers/RendererHandler.ts", "../../../../front_end/models/trace/handlers/SamplesHandler.ts", "../../../../front_end/models/cpu_profile/CPUProfileDataModel.ts", "../../../../front_end/models/cpu_profile/ProfileTreeModel.ts", "../../../../front_end/models/trace/handlers/Threads.ts", "../../../../front_end/models/trace/LegacyTracingModel.ts", "../../../../front_end/models/trace/ModelImpl.ts", "../../../../front_end/models/trace/Processor.ts", "../../../../front_end/models/trace/TreeManipulator.ts"],
4
+ "sourcesContent": ["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Extras from './extras/extras.js';\nimport * as Handlers from './handlers/handlers.js';\nimport * as Helpers from './helpers/helpers.js';\n// Purposefully use a shorter name here so references to this are\n// Legacy.TracingModel.\nimport * as Legacy from './LegacyTracingModel.js';\nimport * as TraceModel from './ModelImpl.js';\nimport * as Processor from './Processor.js';\nimport * as TracingManager from './TracingManager.js';\nimport * as TreeManipulator from './TreeManipulator.js';\nimport * as Types from './types/types.js';\n\nexport {\n Extras,\n Handlers,\n Helpers,\n Legacy,\n Processor,\n TraceModel,\n TracingManager,\n TreeManipulator,\n Types,\n};\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as Migration from './Migration.js';\nexport * as ModelHandlers from './ModelHandlers.js';\nexport * as Threads from './Threads.js';\nexport * as Types from './types.js';\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Animations from './AnimationHandler.js';\nimport * as AuctionWorklets from './AuctionWorkletsHandler.js';\nimport * as GPU from './GPUHandler.js';\nimport * as LayoutShifts from './LayoutShiftsHandler.js';\nimport * as Memory from './MemoryHandler.js';\nimport * as NetworkRequests from './NetworkRequestsHandler.js';\nimport * as PageLoadMetrics from './PageLoadMetricsHandler.js';\nimport type * as Renderer from './RendererHandler.js';\nimport type * as Samples from './SamplesHandler.js';\nimport * as Screenshots from './ScreenshotsHandler.js';\nimport type * as Types from './types.js';\nimport * as UserInteractions from './UserInteractionsHandler.js';\nimport * as UserTimings from './UserTimingsHandler.js';\nimport * as Warnings from './WarningsHandler.js';\nimport * as Workers from './WorkersHandler.js';\n\n// As we migrate the data engine we are incrementally enabling the new handlers\n// one by one, so we do not waste effort parsing data that we do not use. This\n// object should be updated when we add a new handler to enable it.\nexport const ENABLED_TRACE_HANDLERS = {\n Animations,\n AuctionWorklets,\n UserTimings,\n PageLoadMetrics,\n UserInteractions,\n LayoutShifts,\n Screenshots,\n GPU,\n Memory,\n NetworkRequests,\n Warnings,\n Workers,\n};\n\nexport type EnabledHandlersDuringMigration = typeof ENABLED_TRACE_HANDLERS;\n\n// Renderer and Samples handler are only executed when the panel is run\n// from the component examples server. Thus we mark them as optional\n// properties during the migration.\nexport type PartialTraceData = Readonly<Types.EnabledHandlerDataWithMeta<EnabledHandlersDuringMigration>>&{\n // eslint-disable-next-line @typescript-eslint/naming-convention\n readonly Renderer?: Readonly<ReturnType<typeof Renderer['data']>>,\n // eslint-disable-next-line @typescript-eslint/naming-convention\n readonly Samples?: Readonly<ReturnType<typeof Samples['data']>>,\n};\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\nconst animations: Types.TraceEvents.TraceEventAnimation[] = [];\nconst animationsSyntheticEvents: Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[] = [];\n\nexport interface AnimationData {\n animations: readonly Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[];\n}\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function reset(): void {\n animations.length = 0;\n animationsSyntheticEvents.length = 0;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (Types.TraceEvents.isTraceEventAnimation(event)) {\n animations.push(event);\n return;\n }\n}\n\nexport async function finalize(): Promise<void> {\n const matchedEvents = matchBeginningAndEndEvents();\n\n createSortedAnimationsSyntheticEvents(matchedEvents);\n\n handlerState = HandlerState.FINALIZED;\n}\n\nfunction matchBeginningAndEndEvents(): Map<string, {\n begin: Types.TraceEvents.TraceEventNestableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventNestableAsyncEnd | null,\n}> {\n // map to store begin and end of the event\n const matchedEvents: Map<string, {\n begin: Types.TraceEvents.TraceEventNestableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventNestableAsyncEnd | null,\n }> = new Map();\n\n // looking for start and end\n for (const event of animations) {\n const id = event.id2;\n\n if (id === undefined) {\n continue;\n }\n\n const syntheticId = `${event.cat}:${id.local}:${event.name}`;\n\n const otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedEvents, syntheticId, () => {\n return {begin: null, end: null};\n });\n\n const isStartEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_START;\n const isEndEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_END;\n\n if (isStartEvent) {\n otherEventsWithID.begin = {\n ...event,\n ph: Types.TraceEvents.Phase.ASYNC_NESTABLE_START,\n id2: {\n local: event.id2?.local,\n },\n id: event.args?.id,\n };\n } else if (isEndEvent) {\n otherEventsWithID.end = {\n ...event,\n ph: Types.TraceEvents.Phase.ASYNC_NESTABLE_END,\n id2: {\n local: event.id2?.local,\n },\n id: event.args?.id,\n };\n }\n }\n\n return matchedEvents;\n}\n\nfunction createSortedAnimationsSyntheticEvents(matchedEvents: Map<string, {\n begin: Types.TraceEvents.TraceEventNestableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventNestableAsyncEnd | null,\n}>): void {\n for (const [id, eventsPair] of matchedEvents.entries()) {\n if (!eventsPair.begin || !eventsPair.end) {\n continue;\n }\n\n const event: Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent = {\n cat: eventsPair.end.cat,\n ph: eventsPair.end.ph,\n pid: eventsPair.end.pid,\n tid: eventsPair.end.tid,\n id,\n name: eventsPair.begin.name,\n dur: Types.Timing.MicroSeconds(eventsPair.end.ts - eventsPair.begin.ts),\n ts: eventsPair.begin.ts,\n args: {\n data: {\n beginEvent: eventsPair.begin,\n endEvent: eventsPair.end,\n },\n },\n };\n\n if (event.dur < 0) {\n // We have seen in the backend that sometimes animation events get\n // generated with multiple begin entries, or multiple end entries, and this\n // can cause invalid data on the performance panel, so we drop them.\n // crbug.com/1472375\n continue;\n }\n animationsSyntheticEvents.push(event);\n }\n\n animationsSyntheticEvents.sort((a, b) => a.ts - b.ts);\n}\n\nexport function data(): AnimationData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Animation handler is not finalized');\n }\n\n return {\n animations: Array.from(animationsSyntheticEvents),\n };\n}\n", "// Copyright (c) 2020 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport const removeElement = <T>(array: T[], element: T, firstOnly?: boolean): boolean => {\n let index = array.indexOf(element);\n if (index === -1) {\n return false;\n }\n if (firstOnly) {\n array.splice(index, 1);\n return true;\n }\n for (let i = index + 1, n = array.length; i < n; ++i) {\n if (array[i] !== element) {\n array[index++] = array[i];\n }\n }\n array.length = index;\n return true;\n};\n\ntype NumberComparator = (a: number, b: number) => number;\n\nfunction swap(array: number[], i1: number, i2: number): void {\n const temp = array[i1];\n array[i1] = array[i2];\n array[i2] = temp;\n}\n\nfunction partition(\n array: number[], comparator: NumberComparator, left: number, right: number, pivotIndex: number): number {\n const pivotValue = array[pivotIndex];\n swap(array, right, pivotIndex);\n let storeIndex = left;\n for (let i = left; i < right; ++i) {\n if (comparator(array[i], pivotValue) < 0) {\n swap(array, storeIndex, i);\n ++storeIndex;\n }\n }\n swap(array, right, storeIndex);\n return storeIndex;\n}\n\nfunction quickSortRange(\n array: number[], comparator: NumberComparator, left: number, right: number, sortWindowLeft: number,\n sortWindowRight: number): void {\n if (right <= left) {\n return;\n }\n const pivotIndex = Math.floor(Math.random() * (right - left)) + left;\n const pivotNewIndex = partition(array, comparator, left, right, pivotIndex);\n if (sortWindowLeft < pivotNewIndex) {\n quickSortRange(array, comparator, left, pivotNewIndex - 1, sortWindowLeft, sortWindowRight);\n }\n if (pivotNewIndex < sortWindowRight) {\n quickSortRange(array, comparator, pivotNewIndex + 1, right, sortWindowLeft, sortWindowRight);\n }\n}\n\nexport function sortRange(\n array: number[], comparator: NumberComparator, leftBound: number, rightBound: number, sortWindowLeft: number,\n sortWindowRight: number): number[] {\n if (leftBound === 0 && rightBound === (array.length - 1) && sortWindowLeft === 0 && sortWindowRight >= rightBound) {\n array.sort(comparator);\n } else {\n quickSortRange(array, comparator, leftBound, rightBound, sortWindowLeft, sortWindowRight);\n }\n return array;\n}\nexport const binaryIndexOf = <T, S>(array: T[], value: S, comparator: (a: S, b: T) => number): number => {\n const index = lowerBound(array, value, comparator);\n return index < array.length && comparator(value, array[index]) === 0 ? index : -1;\n};\n\nfunction mergeOrIntersect<T>(\n array1: T[], array2: T[], comparator: (a: T, b: T) => number, mergeNotIntersect: boolean): T[] {\n const result = [];\n let i = 0;\n let j = 0;\n while (i < array1.length && j < array2.length) {\n const compareValue = comparator(array1[i], array2[j]);\n if (mergeNotIntersect || !compareValue) {\n result.push(compareValue <= 0 ? array1[i] : array2[j]);\n }\n if (compareValue <= 0) {\n i++;\n }\n if (compareValue >= 0) {\n j++;\n }\n }\n if (mergeNotIntersect) {\n while (i < array1.length) {\n result.push(array1[i++]);\n }\n while (j < array2.length) {\n result.push(array2[j++]);\n }\n }\n return result;\n}\n\nexport const intersectOrdered = <T>(array1: T[], array2: T[], comparator: (a: T, b: T) => number): T[] => {\n return mergeOrIntersect(array1, array2, comparator, false);\n};\n\nexport const mergeOrdered = <T>(array1: T[], array2: T[], comparator: (a: T, b: T) => number): T[] => {\n return mergeOrIntersect(array1, array2, comparator, true);\n};\n\nexport const DEFAULT_COMPARATOR = (a: string|number, b: string|number): -1|0|1 => {\n return a < b ? -1 : (a > b ? 1 : 0);\n};\n\n/**\n * Returns the index of the element closest to the needle that is equal to or\n * greater than it. Assumes that the provided array is sorted.\n *\n * If no element is found, the right bound is returned.\n *\n * Uses the provided comparator function to determine if two items are equal or\n * if one is greater than the other. If you are working with strings or\n * numbers, you can use ArrayUtilities.DEFAULT_COMPARATOR. Otherwise, you\n * should define one that takes the needle element and an element from the\n * array and returns a positive or negative number to indicate which is greater\n * than the other.\n *\n * When specified, |left| (inclusive) and |right| (exclusive) indices\n * define the search window.\n */\nexport function lowerBound<T>(\n array: Uint32Array|Int32Array, needle: T, comparator: (needle: T, b: number) => number, left?: number,\n right?: number): number;\nexport function lowerBound<S, T>(\n array: S[], needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number;\nexport function lowerBound<S, T, A extends S[]>(\n array: A, needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number {\n let l = left || 0;\n let r = right !== undefined ? right : array.length;\n while (l < r) {\n const m = (l + r) >> 1;\n if (comparator(needle, array[m]) > 0) {\n l = m + 1;\n } else {\n r = m;\n }\n }\n return r;\n}\n\n/**\n * Returns the index of the element closest to the needle that is greater than\n * it. Assumes that the provided array is sorted.\n *\n * If no element is found, the right bound is returned.\n *\n * Uses the provided comparator function to determine if two items are equal or\n * if one is greater than the other. If you are working with strings or\n * numbers, you can use ArrayUtilities.DEFAULT_COMPARATOR. Otherwise, you\n * should define one that takes the needle element and an element from the\n * array and returns a positive or negative number to indicate which is greater\n * than the other.\n *\n * When specified, |left| (inclusive) and |right| (exclusive) indices\n * define the search window.\n */\nexport function upperBound<T>(\n array: Uint32Array, needle: T, comparator: (needle: T, b: number) => number, left?: number, right?: number): number;\nexport function upperBound<S, T>(\n array: S[], needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number;\nexport function upperBound<S, T, A extends S[]>(\n array: A, needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number {\n let l = left || 0;\n let r = right !== undefined ? right : array.length;\n while (l < r) {\n const m = (l + r) >> 1;\n if (comparator(needle, array[m]) >= 0) {\n l = m + 1;\n } else {\n r = m;\n }\n }\n return r;\n}\n\nconst enum NearestSearchStart {\n BEGINNING = 'BEGINNING',\n END = 'END',\n}\n/**\n * Obtains the first or last item in the array that satisfies the predicate function.\n * So, for example, if the array were arr = [2, 4, 6, 8, 10], and you are looking for\n * the last item arr[i] such that arr[i] < 5 you would be returned 1, because\n * array[1] is 4, the last item in the array that satisfies the\n * predicate function.\n *\n * If instead you were looking for the first item in the same array that satisfies\n * arr[i] > 5 you would be returned 2 because array[2] = 6.\n *\n * Please note: this presupposes that the array is already ordered.\n */\nfunction nearestIndex<T>(\n arr: readonly T[], predicate: (arrayItem: T) => boolean, searchStart: NearestSearchStart): number|null {\n const searchFromEnd = searchStart === NearestSearchStart.END;\n if (arr.length === 0) {\n return null;\n }\n\n let left = 0;\n let right = arr.length - 1;\n let pivot = 0;\n let matchesPredicate = false;\n let moveToTheRight = false;\n let middle = 0;\n do {\n middle = left + (right - left) / 2;\n pivot = searchFromEnd ? Math.ceil(middle) : Math.floor(middle);\n matchesPredicate = predicate(arr[pivot]);\n moveToTheRight = matchesPredicate === searchFromEnd;\n if (moveToTheRight) {\n left = Math.min(right, pivot + (left === pivot ? 1 : 0));\n } else {\n right = Math.max(left, pivot + (right === pivot ? -1 : 0));\n }\n } while (right !== left);\n\n // Special-case: the indexed item doesn't pass the predicate. This\n // occurs when none of the items in the array are a match for the\n // predicate.\n if (!predicate(arr[left])) {\n return null;\n }\n return left;\n}\n\n/**\n * Obtains the first item in the array that satisfies the predicate function.\n * So, for example, if the array was arr = [2, 4, 6, 8, 10], and you are looking for\n * the first item arr[i] such that arr[i] > 5 you would be returned 2, because\n * array[2] is 6, the first item in the array that satisfies the\n * predicate function.\n *\n * Please note: this presupposes that the array is already ordered.\n */\nexport function nearestIndexFromBeginning<T>(arr: T[], predicate: (arrayItem: T) => boolean): number|null {\n return nearestIndex(arr, predicate, NearestSearchStart.BEGINNING);\n}\n\n/**\n * Obtains the last item in the array that satisfies the predicate function.\n * So, for example, if the array was arr = [2, 4, 6, 8, 10], and you are looking for\n * the last item arr[i] such that arr[i] < 5 you would be returned 1, because\n * arr[1] is 4, the last item in the array that satisfies the\n * predicate function.\n *\n * Please note: this presupposes that the array is already ordered.\n */\n\nexport function nearestIndexFromEnd<T>(arr: readonly T[], predicate: (arrayItem: T) => boolean): number|null {\n return nearestIndex(arr, predicate, NearestSearchStart.END);\n}\n\n// Type guard for ensuring that `arr` does not contain null or undefined\nexport function arrayDoesNotContainNullOrUndefined<T>(arr: (T|null|undefined)[]): arr is T[] {\n return !arr.includes(null) && !arr.includes(undefined);\n}\n", "// Copyright (c) 2020 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport const inverse = function<K, V>(map: Map<K, V>): Multimap<V, K> {\n const result = new Multimap<V, K>();\n for (const [key, value] of map.entries()) {\n result.set(value, key);\n }\n return result;\n};\n\nexport class Multimap<K, V> {\n private map = new Map<K, Set<V>>();\n\n set(key: K, value: V): void {\n let set = this.map.get(key);\n if (!set) {\n set = new Set();\n this.map.set(key, set);\n }\n set.add(value);\n }\n\n get(key: K): Set<V> {\n return this.map.get(key) || new Set();\n }\n\n has(key: K): boolean {\n return this.map.has(key);\n }\n\n hasValue(key: K, value: V): boolean {\n const set = this.map.get(key);\n if (!set) {\n return false;\n }\n return set.has(value);\n }\n\n get size(): number {\n return this.map.size;\n }\n\n delete(key: K, value: V): boolean {\n const values = this.get(key);\n if (!values) {\n return false;\n }\n const result = values.delete(value);\n if (!values.size) {\n this.map.delete(key);\n }\n return result;\n }\n\n deleteAll(key: K): void {\n this.map.delete(key);\n }\n\n keysArray(): K[] {\n return [...this.map.keys()];\n }\n\n valuesArray(): V[] {\n const result = [];\n for (const set of this.map.values()) {\n result.push(...set.values());\n }\n return result;\n }\n\n clear(): void {\n this.map.clear();\n }\n}\n\n/**\n * Gets value for key, assigning a default if value is falsy.\n */\nexport function getWithDefault<K extends {}, V>(\n map: WeakMap<K, V>|Map<K, V>, key: K, defaultValueFactory: (key?: K) => V): V {\n let value = map.get(key);\n if (!value) {\n value = defaultValueFactory(key);\n map.set(key, value);\n }\n\n return value;\n}\n", "// Copyright (c) 2020 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport const clamp = (num: number, min: number, max: number): number => {\n let clampedNumber = num;\n if (num < min) {\n clampedNumber = min;\n } else if (num > max) {\n clampedNumber = max;\n }\n return clampedNumber;\n};\n\nexport const mod = (m: number, n: number): number => {\n return ((m % n) + n) % n;\n};\n\nexport const bytesToString = (bytes: number): string => {\n if (bytes < 1000) {\n return `${bytes.toFixed(0)}\\xA0B`;\n }\n\n const kilobytes = bytes / 1000;\n if (kilobytes < 100) {\n return `${kilobytes.toFixed(1)}\\xA0kB`;\n }\n if (kilobytes < 1000) {\n return `${kilobytes.toFixed(0)}\\xA0kB`;\n }\n\n const megabytes = kilobytes / 1000;\n if (megabytes < 100) {\n return `${megabytes.toFixed(1)}\\xA0MB`;\n }\n return `${megabytes.toFixed(0)}\\xA0MB`;\n};\n\nexport const toFixedIfFloating = (value: string): string => {\n if (!value || Number.isNaN(Number(value))) {\n return value;\n }\n const number = Number(value);\n return number % 1 ? number.toFixed(3) : String(number);\n};\n\n/**\n * Rounds a number (including float) down.\n */\nexport const floor = (value: number, precision: number = 0): number => {\n const mult = Math.pow(10, precision);\n return Math.floor(value * mult) / mult;\n};\n\n/**\n * Computes the great common divisor for two numbers.\n * If the numbers are floats, they will be rounded to an integer.\n */\nexport const greatestCommonDivisor = (a: number, b: number): number => {\n a = Math.round(a);\n b = Math.round(b);\n while (b !== 0) {\n const t = b;\n b = a % b;\n a = t;\n }\n return a;\n};\n\nconst commonRatios = new Map([\n ['8\u22365', '16\u223610'],\n]);\n\nexport const aspectRatio = (width: number, height: number): string => {\n const divisor = greatestCommonDivisor(width, height);\n if (divisor !== 0) {\n width /= divisor;\n height /= divisor;\n }\n const result = `${width}\u2236${height}`;\n return commonRatios.get(result) || result;\n};\n\nexport const withThousandsSeparator = function(num: number): string {\n let str = String(num);\n const re = /(\\d+)(\\d{3})/;\n while (str.match(re)) {\n str = str.replace(re, '$1\\xA0$2');\n } // \\xa0 is a non-breaking space\n return str;\n};\n", "// Copyright 2020 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * This is useful to keep TypeScript happy in a test - if you have a value\n * that's potentially `null` you can use this function to assert that it isn't,\n * and satisfy TypeScript that the value is present.\n */\nexport function assertNotNullOrUndefined<T>(val: T): asserts val is NonNullable<T> {\n if (val === null || val === undefined) {\n throw new Error(`Expected given value to not be null/undefined but it was: ${val}`);\n }\n}\n\nexport function assertNever(type: never, message: string): never {\n throw new Error(message);\n}\n\n/**\n * This is useful to check on the type-level that the unhandled cases of\n * a switch are exactly `T` (where T is usually a union type of enum values).\n * @param caseVariable\n */\nexport function assertUnhandled<T>(_caseVariable: T): T {\n return _caseVariable;\n}\n\nexport type FieldsThatExtend<Type, Selector> = {\n [Key in keyof Type]: Type[Key] extends Selector ? Key : never;\n}[keyof Type];\n\nexport type PickFieldsThatExtend<Type, Selector> = Pick<Type, FieldsThatExtend<Type, Selector>>;\n\n/**\n * Turns a Union type (a | b) into an Intersection type (a & b).\n * This is a helper type to implement the \"NoUnion\" guard.\n *\n * Adapted from https://stackoverflow.com/a/50375286.\n *\n * The tautological `T extends any` is necessary to trigger distributivity for\n * plain unions, e.g. in IntersectionFromUnion<'a'|'b'> TypeScript expands it\n * to ('a' extends any ? (arg: 'a') => void : never)\n * | ('b' extends any ? (arg: 'b') => void : never)\n *\n * The second extends clause then asks TypeScript to find a type of the form\n * `(arg: infer U) => void` that upper-bounds the union, i.e., intuitively,\n * a type that converts to each of the union members. This forces U to be the\n * intersection of 'a' and 'b' in the example.\n *\n * Please note that some intersection types are simply impossible, e.g.\n * `string & number`. There is no type that fulfills both at the same time. A\n * union of this kind is reduced to `never`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype IntersectionFromUnion<T> = (T extends any ? (arg: T) => void : never) extends((arg: infer U) => void) ? U : never;\n\n/**\n * When writing generic code it may be desired to disallow Union types from\n * being passed. This type can be used in those cases.\n *\n * function foo<T>(argument: NoUnion<T>) {...}\n *\n * Would result in a compile error for foo<a|b>(...); invocations as `argument`\n * would be typed as `never`.\n *\n * Adapted from https://stackoverflow.com/a/50641073.\n *\n * Conditional types become distributive when receiving a union type. To\n * prevent this from happening, we use `[T] extends [IntersectionFromUnion<T>]`\n * instead of `T extends IntersectionFromUnion<T>`.\n * See: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html\n */\nexport type NoUnion<T> = [T] extends [IntersectionFromUnion<T>] ? T : never;\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as Configuration from './Configuration.js';\nexport * as File from './File.js';\nexport * as Timing from './Timing.js';\nexport * as TraceEvents from './TraceEvents.js';\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport type Configuration = Readonly<{\n settings: {\n // Currently empty but defining here as we will migrate more settings into this.\n },\n experiments: {\n /**\n * Include V8 RCS in the timeline\n */\n timelineV8RuntimeCallStats: boolean,\n /**\n * Show all events: disable the default filtering which hides and excludes some events.\n */\n timelineShowAllEvents: boolean,\n },\n processing: {\n /**\n * How long the processor should pause between event chunks.\n */\n pauseDuration: number,\n /**\n * How many events should be processed before yielding to the main thread for a pause.\n */\n eventsPerChunk: number,\n },\n}>;\n\nexport const DEFAULT: Configuration = {\n settings: {},\n experiments: {\n timelineV8RuntimeCallStats: false,\n timelineShowAllEvents: false,\n },\n processing: {\n eventsPerChunk: 15_000,\n pauseDuration: 1,\n },\n};\n\n/**\n * Generates a key that can be used to represent this config in a cache. This is\n * used mainly in tests, where we want to avoid re-parsing a file if we have\n * already processed it with the same configuration. This cache key purposefully\n * does not include all settings in the configuration; the processing settings\n * do not impact the actual resulting data. Only new flags in the config that\n * alter parsing should be added to this cache key.\n */\nexport function configToCacheKey(config: Configuration): string {\n return [\n `experiments.timelineShowAllEvents:${config.experiments.timelineShowAllEvents}`,\n `experiments.timelineV8RuntimeCallStats:${config.experiments.timelineV8RuntimeCallStats}`,\n ].join('-');\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport {type TraceEventData} from './TraceEvents.js';\nexport type TraceFile = {\n traceEvents: readonly TraceEventData[],\n metadata: MetaData,\n};\n\nexport const enum DataOrigin {\n CPUProfile = 'CPUProfile',\n TraceEvents = 'TraceEvents',\n}\n\n/**\n * Trace metadata that we persist to the file. This will allow us to\n * store specifics for the trace, e.g., which tracks should be visible\n * on load.\n */\nexport interface MetaData {\n source?: 'DevTools';\n startTime?: string;\n networkThrottling?: string;\n cpuThrottling?: number;\n hardwareConcurrency?: number;\n dataOrigin?: DataOrigin;\n}\n\nexport type Contents = TraceFile|TraceEventData[];\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/* eslint-disable no-unused-private-class-members */\n\nexport type MicroSeconds = number&{_tag: 'MicroSeconds'};\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function MicroSeconds(value: number): MicroSeconds {\n return value as MicroSeconds;\n}\n\nexport type MilliSeconds = number&{_tag: 'MilliSeconds'};\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function MilliSeconds(value: number): MilliSeconds {\n return value as MilliSeconds;\n}\nexport type Seconds = number&{_tag: 'Seconds'};\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function Seconds(value: number): Seconds {\n return value as Seconds;\n}\n\nexport const enum TimeUnit {\n MICROSECONDS = 0,\n MILLISECONDS = 1,\n SECONDS = 2,\n MINUTES = 3,\n}\n\n// Other types.\n\nexport interface TraceWindow {\n min: MicroSeconds;\n max: MicroSeconds;\n range: MicroSeconds;\n}\n\nexport interface TraceWindowMilliSeconds {\n min: MilliSeconds;\n max: MilliSeconds;\n range: MilliSeconds;\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/* eslint-disable no-unused-private-class-members */\nimport type * as Protocol from '../../../generated/protocol.js';\n\nimport {type MicroSeconds, type MilliSeconds, type Seconds} from './Timing.js';\n\n// Trace Events.\nexport const enum Phase {\n // Standard\n BEGIN = 'B',\n END = 'E',\n COMPLETE = 'X',\n INSTANT = 'I',\n COUNTER = 'C',\n\n // Async\n ASYNC_NESTABLE_START = 'b',\n ASYNC_NESTABLE_INSTANT = 'n',\n ASYNC_NESTABLE_END = 'e',\n ASYNC_STEP_INTO = 'T',\n ASYNC_BEGIN = 'S',\n ASYNC_END = 'F',\n ASYNC_STEP_PAST = 'p',\n\n // Flow\n FLOW_START = 's',\n FLOW_STEP = 't',\n FLOW_END = 'f',\n\n // Sample\n SAMPLE = 'P',\n\n // Object\n OBJECT_CREATED = 'N',\n OBJECT_SNAPSHOT = 'O',\n OBJECT_DESTROYED = 'D',\n\n // Metadata\n METADATA = 'M',\n\n // Memory Dump\n MEMORY_DUMP_GLOBAL = 'V',\n MEMORY_DUMP_PROCESS = 'v',\n\n // Mark\n MARK = 'R',\n\n // Clock sync\n CLOCK_SYNC = 'c',\n}\n\nexport function isNestableAsyncPhase(phase: Phase): boolean {\n return phase === Phase.ASYNC_NESTABLE_START || phase === Phase.ASYNC_NESTABLE_END ||\n phase === Phase.ASYNC_NESTABLE_INSTANT;\n}\n\nexport function isAsyncPhase(phase: Phase): boolean {\n return isNestableAsyncPhase(phase) || phase === Phase.ASYNC_BEGIN || phase === Phase.ASYNC_STEP_INTO ||\n phase === Phase.ASYNC_END || phase === Phase.ASYNC_STEP_PAST;\n}\n\nexport function isFlowPhase(phase: Phase): boolean {\n return phase === Phase.FLOW_START || phase === Phase.FLOW_STEP || phase === Phase.FLOW_END;\n}\n\nexport const enum TraceEventScope {\n THREAD = 't',\n PROCESS = 'p',\n GLOBAL = 'g',\n}\n\nexport interface TraceEventData {\n args?: TraceEventArgs;\n cat: string;\n name: string;\n ph: Phase;\n pid: ProcessID;\n tid: ThreadID;\n tts?: MicroSeconds;\n ts: MicroSeconds;\n tdur?: MicroSeconds;\n dur?: MicroSeconds;\n}\n\nexport interface TraceEventArgs {\n data?: TraceEventArgsData;\n}\n\nexport interface TraceEventArgsData {\n stackTrace?: TraceEventCallFrame[];\n navigationId?: string;\n frame?: string;\n}\n\nexport interface TraceEventCallFrame {\n codeType?: string;\n functionName: string;\n scriptId: number;\n columnNumber?: number;\n lineNumber?: number;\n url?: string;\n}\n\nexport interface TraceFrame {\n frame: string;\n name: string;\n processId: ProcessID;\n url: string;\n parent?: string;\n}\n\n// Sample events.\n\nexport interface TraceEventSample extends TraceEventData {\n ph: Phase.SAMPLE;\n}\n\n/**\n * A fake trace event created to support CDP.Profiler.Profiles in the\n * trace engine.\n */\nexport interface SyntheticTraceEventCpuProfile extends TraceEventInstant {\n name: 'CpuProfile';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n cpuProfile: Protocol.Profiler.Profile,\n },\n };\n}\n\nexport interface TraceEventProfile extends TraceEventSample {\n name: 'Profile';\n id: ProfileID;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n startTime: MicroSeconds,\n },\n };\n}\n\nexport interface TraceEventProfileChunk extends TraceEventSample {\n name: 'ProfileChunk';\n id: ProfileID;\n args: TraceEventArgs&{\n // `data` is only missing in \"fake\" traces\n data?: TraceEventArgsData & {\n cpuProfile?: TraceEventPartialProfile,\n timeDeltas?: MicroSeconds[],\n lines?: MicroSeconds[],\n },\n };\n}\n\nexport interface TraceEventPartialProfile {\n nodes?: TraceEventPartialNode[];\n samples: CallFrameID[];\n}\n\nexport interface TraceEventPartialNode {\n callFrame: TraceEventCallFrame;\n id: CallFrameID;\n parent?: CallFrameID;\n}\n\n// Complete events.\n\nexport interface TraceEventComplete extends TraceEventData {\n ph: Phase.COMPLETE;\n dur: MicroSeconds;\n}\n\nexport interface TraceEventFireIdleCallback extends TraceEventComplete {\n name: 'FireIdleCallback';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n allottedMilliseconds: MilliSeconds,\n frame: string,\n id: number,\n timedOut: boolean,\n },\n };\n}\n\nexport interface TraceEventDispatch extends TraceEventComplete {\n name: 'EventDispatch';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n type: string,\n },\n };\n}\n\nexport interface TraceEventParseHTML extends TraceEventComplete {\n name: 'ParseHTML';\n args: TraceEventArgs&{\n beginData: {\n frame: string,\n startLine: number,\n url: string,\n },\n endData?: {\n endLine: number,\n },\n };\n}\n\nexport interface TraceEventBegin extends TraceEventData {\n ph: Phase.BEGIN;\n}\n\nexport interface TraceEventEnd extends TraceEventData {\n ph: Phase.END;\n}\n\n/**\n * This denotes a complete event created from a pair of begin and end\n * events. For practicality, instead of always having to look for the\n * end event corresponding to a begin event, we create a synthetic\n * complete event that comprises the data of both from the beginning in\n * the RendererHandler.\n */\nexport type TraceEventSyntheticCompleteEvent = TraceEventComplete;\n\nexport interface TraceEventEventTiming extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_START|Phase.ASYNC_NESTABLE_END;\n name: KnownEventName.EventTiming;\n id: string;\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n cancelable: boolean,\n duration: MilliSeconds,\n processingEnd: MicroSeconds,\n processingStart: MicroSeconds,\n timeStamp: MicroSeconds,\n interactionId?: number, type: string,\n },\n };\n}\n\nexport interface TraceEventEventTimingBegin extends TraceEventEventTiming {\n ph: Phase.ASYNC_NESTABLE_START;\n}\nexport interface TraceEventEventTimingEnd extends TraceEventEventTiming {\n ph: Phase.ASYNC_NESTABLE_END;\n}\n\nexport interface TraceEventGPUTask extends TraceEventComplete {\n name: 'GPUTask';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n /* eslint-disable @typescript-eslint/naming-convention */\n renderer_pid: ProcessID,\n used_bytes: number,\n /* eslint-enable @typescript-eslint/naming-convention */\n },\n };\n}\n\nexport interface TraceEventSyntheticNetworkRedirect {\n url: string;\n priority: string;\n requestMethod?: string;\n ts: MicroSeconds;\n dur: MicroSeconds;\n}\n\n// TraceEventProcessedArgsData is used to store the processed data of a network\n// request. Which is used to distinguish from the date we extract from the\n// trace event directly.\ninterface TraceEventSyntheticArgsData {\n dnsLookup: MicroSeconds;\n download: MicroSeconds;\n downloadStart: MicroSeconds;\n finishTime: MicroSeconds;\n initialConnection: MicroSeconds;\n isDiskCached: boolean;\n isHttps: boolean;\n isMemoryCached: boolean;\n isPushedResource: boolean;\n networkDuration: MicroSeconds;\n processingDuration: MicroSeconds;\n proxyNegotiation: MicroSeconds;\n queueing: MicroSeconds;\n redirectionDuration: MicroSeconds;\n requestSent: MicroSeconds;\n sendStartTime: MicroSeconds;\n ssl: MicroSeconds;\n stalled: MicroSeconds;\n totalTime: MicroSeconds;\n waiting: MicroSeconds;\n}\n\nexport interface TraceEventSyntheticNetworkRequest extends TraceEventComplete {\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n syntheticData: TraceEventSyntheticArgsData,\n // All fields below are from TraceEventsForNetworkRequest,\n // Required fields\n decodedBodyLength: number,\n encodedDataLength: number,\n frame: string,\n fromServiceWorker: boolean,\n host: string,\n mimeType: string,\n pathname: string,\n search: string,\n priority: Priority,\n initialPriority: Priority,\n protocol: string,\n redirects: TraceEventSyntheticNetworkRedirect[],\n renderBlocking: RenderBlocking,\n requestId: string,\n requestingFrameUrl: string,\n statusCode: number,\n url: string,\n // Optional fields\n requestMethod?: string,\n timing?: TraceEventResourceReceiveResponseTimingData,\n },\n };\n cat: 'loading';\n name: 'SyntheticNetworkRequest';\n ph: Phase.COMPLETE;\n dur: MicroSeconds;\n tdur: MicroSeconds;\n ts: MicroSeconds;\n tts: MicroSeconds;\n pid: ProcessID;\n tid: ThreadID;\n}\n\nexport const enum AuctionWorkletType {\n BIDDER = 'bidder',\n SELLER = 'seller',\n // Not expected to be used, but here as a fallback in case new types get\n // added and we have yet to update the trace engine.\n UNKNOWN = 'unknown',\n}\n\nexport interface SyntheticAuctionWorkletEvent extends TraceEventInstant {\n name: 'SyntheticAuctionWorkletEvent';\n // The PID that the AuctionWorklet is running in.\n pid: ProcessID;\n // URL\n host: string;\n // An ID used to pair up runningInProcessEvents with doneWithProcessEvents\n target: string;\n type: AuctionWorkletType;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n // There are two threads for a worklet that we care about, so we gather\n // the thread_name events so we can know the PID and TID for them (and\n // hence display the right events in the track for each thread)\n utilityThread: TraceEventThreadName,\n v8HelperThread: TraceEventThreadName,\n } &\n (\n // This type looks odd, but this is because these events could either have:\n // 1. Just the DoneWithProcess event\n // 2. Just the RunningInProcess event\n // 3. Both events\n // But crucially it cannot have both events missing, hence listing all the\n // allowed cases.\n // Clang is disabled as the combination of nested types and optional\n // properties cause it to weirdly indent some of the properties and make it\n // very unreadable.\n // clang-format off\n {\n runningInProcessEvent: TraceEventAuctionWorkletRunningInProcess,\n doneWithProcessEvent: TraceEventAuctionWorkletDoneWithProcess,\n } |\n {\n runningInProcessEvent?: TraceEventAuctionWorkletRunningInProcess,\n doneWithProcessEvent: TraceEventAuctionWorkletDoneWithProcess,\n } |\n {\n doneWithProcessEvent?: TraceEventAuctionWorkletDoneWithProcess,\n runningInProcessEvent: TraceEventAuctionWorkletRunningInProcess,\n\n }),\n // clang-format on\n };\n}\nexport interface TraceEventAuctionWorkletRunningInProcess extends TraceEventData {\n name: 'AuctionWorkletRunningInProcess';\n ph: Phase.INSTANT;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n host: string,\n pid: ProcessID,\n target: string,\n type: AuctionWorkletType,\n },\n };\n}\nexport interface TraceEventAuctionWorkletDoneWithProcess extends TraceEventData {\n name: 'AuctionWorkletDoneWithProcess';\n ph: Phase.INSTANT;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n host: string,\n pid: ProcessID,\n target: string,\n type: AuctionWorkletType,\n },\n };\n}\n\nexport function isTraceEventAuctionWorkletRunningInProcess(event: TraceEventData):\n event is TraceEventAuctionWorkletRunningInProcess {\n return event.name === 'AuctionWorkletRunningInProcess';\n}\nexport function isTraceEventAuctionWorkletDoneWithProcess(event: TraceEventData):\n event is TraceEventAuctionWorkletDoneWithProcess {\n return event.name === 'AuctionWorkletDoneWithProcess';\n}\n\n// Snapshot events.\n\nexport interface TraceEventSnapshot extends TraceEventData {\n args: TraceEventArgs&{\n snapshot: string,\n };\n name: 'Screenshot';\n cat: 'disabled-by-default-devtools.screenshot';\n ph: Phase.OBJECT_SNAPSHOT|Phase.INSTANT; // In Oct 2023, the phase was changed to Instant. crbug.com/798755\n}\n\n// Animation events.\n\nexport interface TraceEventAnimation extends TraceEventData {\n args: TraceEventArgs&{\n id?: string,\n name?: string,\n nodeId?: number,\n nodeName?: string,\n state?: string,\n compositeFailed?: number,\n unsupportedProperties?: string[],\n };\n name: 'Animation';\n id2?: {\n local?: string,\n };\n}\n\n// Metadata events.\n\nexport interface TraceEventMetadata extends TraceEventData {\n ph: Phase.METADATA;\n args: TraceEventArgs&{\n name?: string,\n uptime?: string,\n };\n}\n\nexport interface TraceEventThreadName extends TraceEventMetadata {\n name: 'thread_name';\n args: TraceEventArgs&{\n name?: string,\n };\n}\n\nexport interface TraceEventProcessName extends TraceEventMetadata {\n name: 'process_name';\n}\n\n// Mark events.\n\nexport interface TraceEventMark extends TraceEventData {\n ph: Phase.MARK;\n}\n\nexport interface TraceEventNavigationStart extends TraceEventMark {\n name: 'navigationStart';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n documentLoaderURL: string,\n isLoadingMainFrame: boolean,\n // isOutermostMainFrame was introduced in crrev.com/c/3625434 and exists\n // because of Fenced Frames\n // [github.com/WICG/fenced-frame/tree/master/explainer].\n // Fenced frames introduce a situation where isLoadingMainFrame could be\n // true for a navigation, but that navigation be within an embedded \"main\n // frame\", and therefore it wouldn't be on the top level main frame.\n // In situations where we need to distinguish that, we can rely on\n // isOutermostMainFrame, which will only be true for navigations on the\n // top level main frame.\n\n // This flag is optional as it was introduced in May 2022; so users\n // reasonably may import traces from before that date that do not have\n // this field present.\n isOutermostMainFrame?: boolean, navigationId: string,\n },\n frame: string,\n };\n}\n\nexport interface TraceEventFirstContentfulPaint extends TraceEventMark {\n name: 'firstContentfulPaint';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n navigationId: string,\n },\n };\n}\n\nexport interface TraceEventFirstPaint extends TraceEventMark {\n name: 'firstPaint';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n navigationId: string,\n },\n };\n}\n\nexport type PageLoadEvent = TraceEventFirstContentfulPaint|TraceEventMarkDOMContent|TraceEventInteractiveTime|\n TraceEventLargestContentfulPaintCandidate|TraceEventLayoutShift|TraceEventFirstPaint|TraceEventMarkLoad|\n TraceEventNavigationStart;\n\nexport interface TraceEventLargestContentfulPaintCandidate extends TraceEventMark {\n name: 'largestContentfulPaint::Candidate';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n candidateIndex: number,\n isOutermostMainFrame: boolean,\n isMainFrame: boolean,\n navigationId: string,\n nodeId: Protocol.DOM.BackendNodeId,\n type?: string,\n },\n };\n}\nexport interface TraceEventLargestImagePaintCandidate extends TraceEventMark {\n name: 'LargestImagePaint::Candidate';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n candidateIndex: number,\n imageUrl: string,\n // eslint-disable-next-line @typescript-eslint/naming-convention\n DOMNodeId: Protocol.DOM.BackendNodeId,\n },\n };\n}\nexport interface TraceEventLargestTextPaintCandidate extends TraceEventMark {\n name: 'LargestTextPaint::Candidate';\n args: TraceEventArgs&{\n frame: string,\n data?: TraceEventArgsData&{\n candidateIndex: number,\n // eslint-disable-next-line @typescript-eslint/naming-convention\n DOMNodeId: Protocol.DOM.BackendNodeId,\n },\n };\n}\n\nexport interface TraceEventInteractiveTime extends TraceEventMark {\n name: 'InteractiveTime';\n args: TraceEventArgs&{\n args: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n total_blocking_time_ms: number,\n },\n frame: string,\n };\n}\n\n// Instant events.\n\nexport interface TraceEventInstant extends TraceEventData {\n ph: Phase.INSTANT;\n s: TraceEventScope;\n}\n\nexport interface TraceEventUpdateCounters extends TraceEventInstant {\n name: 'UpdateCounters';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n documents: number,\n jsEventListeners: number,\n jsHeapSizeUsed: number,\n nodes: number,\n },\n };\n}\n\nexport type TraceEventRendererEvent = TraceEventInstant|TraceEventComplete;\n\nexport interface TraceEventTracingStartedInBrowser extends TraceEventInstant {\n name: 'TracingStartedInBrowser';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n frameTreeNodeId: number,\n // Frames can only missing in \"fake\" traces\n frames?: TraceFrame[], persistentIds: boolean,\n },\n };\n}\n\nexport interface TraceEventTracingSessionIdForWorker extends TraceEventInstant {\n name: 'TracingSessionIdForWorker';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n url: string,\n workerId: WorkerId,\n workerThreadId: ThreadID,\n frame: string,\n },\n };\n}\nexport function isTraceEventTracingSessionIdForWorker(event: TraceEventData):\n event is TraceEventTracingSessionIdForWorker {\n return event.name === 'TracingSessionIdForWorker';\n}\n\nexport interface TraceEventFrameCommittedInBrowser extends TraceEventInstant {\n name: 'FrameCommittedInBrowser';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & TraceFrame,\n };\n}\n\nexport interface TraceEventMainFrameViewport extends TraceEventInstant {\n name: 'PaintTimingVisualizer::Viewport';\n args: {\n data: TraceEventArgsData&{\n // eslint-disable-next-line @typescript-eslint/naming-convention\n viewport_rect: number[],\n },\n };\n}\n\nexport interface TraceEventCommitLoad extends TraceEventInstant {\n name: 'CommitLoad';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n frame: string,\n isMainFrame: boolean,\n name: string,\n nodeId: number,\n page: string,\n parent: string,\n url: string,\n },\n };\n}\n\nexport interface TraceEventMarkDOMContent extends TraceEventInstant {\n name: 'MarkDOMContent';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n frame: string,\n isMainFrame: boolean,\n page: string,\n },\n };\n}\n\nexport interface TraceEventMarkLoad extends TraceEventInstant {\n name: 'MarkLoad';\n args: TraceEventArgs&{\n data?: TraceEventArgsData & {\n frame: string,\n isMainFrame: boolean,\n page: string,\n },\n };\n}\n\nexport interface TraceEventAsync extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_START|Phase.ASYNC_NESTABLE_INSTANT|Phase.ASYNC_NESTABLE_END|Phase.ASYNC_STEP_INTO|\n Phase.ASYNC_BEGIN|Phase.ASYNC_END|Phase.ASYNC_STEP_PAST;\n}\n\nexport type TraceRect = [number, number, number, number];\nexport type TraceImpactedNode = {\n // These keys come from the trace data, so we have to use underscores.\n /* eslint-disable @typescript-eslint/naming-convention */\n new_rect: TraceRect,\n node_id: Protocol.DOM.BackendNodeId,\n old_rect: TraceRect,\n /* eslint-enable @typescript-eslint/naming-convention */\n};\n\ntype LayoutShiftData = TraceEventArgsData&{\n // These keys come from the trace data, so we have to use underscores.\n /* eslint-disable @typescript-eslint/naming-convention */\n cumulative_score: number,\n frame_max_distance: number,\n had_recent_input: boolean,\n impacted_nodes: TraceImpactedNode[] | undefined,\n is_main_frame: boolean,\n overall_max_distance: number,\n region_rects: TraceRect[],\n score: number,\n weighted_score_delta: number,\n /* eslint-enable @typescript-eslint/naming-convention */\n};\n// These keys come from the trace data, so we have to use underscores.\nexport interface TraceEventLayoutShift extends TraceEventInstant {\n name: 'LayoutShift';\n normalized?: boolean;\n args: TraceEventArgs&{\n frame: string,\n data?: LayoutShiftData,\n };\n}\n\ninterface LayoutShiftSessionWindowData {\n // The sum of the weighted score of all the shifts\n // that belong to a session window.\n cumulativeWindowScore: number;\n // A consecutive generated in the frontend to\n // to identify a session window.\n id: number;\n}\nexport interface LayoutShiftParsedData {\n screenshotSource?: string;\n timeFromNavigation?: MicroSeconds;\n // The sum of the weighted scores of the shifts that\n // belong to a session window up until this shift\n // (inclusive).\n cumulativeWeightedScoreInWindow: number;\n sessionWindowData: LayoutShiftSessionWindowData;\n}\nexport interface SyntheticLayoutShift extends TraceEventLayoutShift {\n args: TraceEventArgs&{\n frame: string,\n data?: LayoutShiftData&{\n rawEvent: TraceEventLayoutShift,\n },\n };\n parsedData: LayoutShiftParsedData;\n}\n\nexport type Priority = 'Low'|'High'|'Medium'|'VeryHigh'|'Highest';\nexport type RenderBlocking = 'blocking'|'non_blocking'|'in_body_parser_blocking'|'potentially_blocking';\nexport interface TraceEventResourceSendRequest extends TraceEventInstant {\n name: 'ResourceSendRequest';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n requestId: string,\n url: string,\n priority: Priority,\n // TODO(crbug.com/1457985): change requestMethod to enum when confirm in the backend code.\n requestMethod?: string,\n renderBlocking?: RenderBlocking,\n },\n };\n}\n\nexport interface TraceEventResourceChangePriority extends TraceEventInstant {\n name: 'ResourceChangePriority';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n requestId: string,\n priority: Priority,\n },\n };\n}\n\nexport interface TraceEventResourceWillSendRequest extends TraceEventInstant {\n name: 'ResourceWillSendRequest';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n requestId: string,\n },\n };\n}\n\nexport interface TraceEventResourceFinish extends TraceEventInstant {\n name: 'ResourceFinish';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n decodedBodyLength: number,\n didFail: boolean,\n encodedDataLength: number,\n finishTime: Seconds,\n requestId: string,\n },\n };\n}\n\nexport interface TraceEventResourceReceivedData extends TraceEventInstant {\n name: 'ResourceReceivedData';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n encodedDataLength: number,\n frame: string,\n requestId: string,\n },\n };\n}\n\ninterface TraceEventResourceReceiveResponseTimingData {\n connectEnd: MilliSeconds;\n connectStart: MilliSeconds;\n dnsEnd: MilliSeconds;\n dnsStart: MilliSeconds;\n proxyEnd: MilliSeconds;\n proxyStart: MilliSeconds;\n pushEnd: MilliSeconds;\n pushStart: MilliSeconds;\n receiveHeadersEnd: MilliSeconds;\n requestTime: Seconds;\n sendEnd: MilliSeconds;\n sendStart: MilliSeconds;\n sslEnd: MilliSeconds;\n sslStart: MilliSeconds;\n workerReady: MilliSeconds;\n workerStart: MilliSeconds;\n}\n\nexport interface TraceEventResourceReceiveResponse extends TraceEventInstant {\n name: 'ResourceReceiveResponse';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n encodedDataLength: number,\n frame: string,\n fromCache: boolean,\n fromServiceWorker: boolean,\n mimeType: string,\n requestId: string,\n responseTime: MilliSeconds,\n statusCode: number,\n timing: TraceEventResourceReceiveResponseTimingData,\n },\n };\n}\n\nexport interface TraceEventResourceMarkAsCached extends TraceEventInstant {\n name: 'ResourceMarkAsCached';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n requestId: string,\n },\n };\n}\n\nexport const enum LayoutInvalidationReason {\n SIZE_CHANGED = 'Size changed',\n ATTRIBUTE = 'Attribute',\n ADDED_TO_LAYOUT = 'Added to layout',\n SCROLLBAR_CHANGED = 'Scrollbar changed',\n REMOVED_FROM_LAYOUT = 'Removed from layout',\n STYLE_CHANGED = 'Style changed',\n FONTS_CHANGED = 'Fonts changed',\n UNKNOWN = 'Unknown',\n}\n\nexport interface TraceEventLayoutInvalidation extends TraceEventInstant {\n name: 'LayoutInvalidationTracking'|'ScheduleStyleInvalidationTracking';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n nodeId: Protocol.DOM.BackendNodeId,\n reason: LayoutInvalidationReason,\n nodeName?: string,\n },\n };\n}\n\nexport const enum StyleRecalcInvalidationReason {\n ANIMATION = 'Animation',\n}\n\nexport interface TraceEventStyleRecalcInvalidation extends TraceEventInstant {\n name: 'StyleRecalcInvalidationTracking';\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n nodeId: Protocol.DOM.BackendNodeId,\n reason: StyleRecalcInvalidationReason,\n subtree: boolean,\n nodeName?: string,\n extraData?: string,\n },\n };\n}\n\nexport interface TraceEventPrePaint extends TraceEventComplete {\n name: 'PrePaint';\n}\n\nexport type TraceEventNestableAsync = TraceEventNestableAsyncBegin|TraceEventNestableAsyncEnd;\nexport interface TraceEventNestableAsyncBegin extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_START;\n // The id2 field gives flexibility to explicitly specify if an event\n // id is global among processes or process local. However not all\n // events use it, so both kind of ids need to be marked as optional.\n id2?: {local?: string, global?: string};\n id?: string;\n}\n\nexport interface TraceEventNestableAsyncEnd extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_END;\n id2?: {local?: string, global?: string};\n id?: string;\n}\n\nexport type TraceEventAsyncPerformanceMeasure = TraceEventPerformanceMeasureBegin|TraceEventPerformanceMeasureEnd;\n\nexport interface TraceEventPerformanceMeasureBegin extends TraceEventNestableAsyncBegin {\n cat: 'blink.user_timing';\n id: string;\n}\n\nexport interface TraceEventPerformanceMeasureEnd extends TraceEventNestableAsyncEnd {\n cat: 'blink.user_timing';\n id: string;\n}\n\nexport interface TraceEventConsoleTimeBegin extends TraceEventNestableAsyncBegin {\n cat: 'blink.console';\n id2: {\n local: string,\n };\n}\n\nexport interface TraceEventConsoleTimeEnd extends TraceEventNestableAsyncEnd {\n cat: 'blink.console';\n id2: {\n local: string,\n };\n}\n\nexport interface TraceEventTimeStamp extends TraceEventData {\n cat: 'devtools.timeline';\n name: 'TimeStamp';\n ph: Phase.INSTANT;\n id: string;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n message: string,\n },\n };\n}\n\nexport interface TraceEventPerformanceMark extends TraceEventData {\n cat: 'blink.user_timing';\n ph: Phase.INSTANT|Phase.MARK;\n id: string;\n}\n\n// Nestable async events with a duration are made up of two distinct\n// events: the begin, and the end. We need both of them to be able to\n// display the right information, so we create these synthetic events.\nexport interface TraceEventSyntheticNestableAsyncEvent extends TraceEventData {\n id?: string;\n id2?: {local?: string, global?: string};\n dur: MicroSeconds;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n beginEvent: TraceEventNestableAsyncBegin,\n endEvent: TraceEventNestableAsyncEnd,\n },\n };\n}\n\nexport interface TraceEventSyntheticUserTiming extends TraceEventSyntheticNestableAsyncEvent {\n id: string;\n dur: MicroSeconds;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n beginEvent: TraceEventPerformanceMeasureBegin,\n endEvent: TraceEventPerformanceMeasureEnd,\n },\n };\n}\n\nexport interface TraceEventSyntheticConsoleTiming extends TraceEventSyntheticNestableAsyncEvent {\n id2: {local: string};\n dur: MicroSeconds;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n beginEvent: TraceEventConsoleTimeBegin,\n endEvent: TraceEventConsoleTimeEnd,\n },\n };\n}\n\nexport interface SyntheticInteractionEvent extends TraceEventSyntheticNestableAsyncEvent {\n // InteractionID and type are available within the beginEvent's data, but we\n // put them on the top level for ease of access.\n interactionId: number;\n type: string;\n // This is equivalent to startEvent.ts;\n ts: MicroSeconds;\n // This duration can be calculated via endEvent.ts - startEvent.ts, but we do\n // that and put it here to make it easier. This also makes these events\n // consistent with real events that have a dur field.\n dur: MicroSeconds;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n beginEvent: TraceEventEventTimingBegin,\n endEvent: TraceEventEventTimingEnd,\n },\n };\n}\n\n/**\n * An event created synthetically in the frontend that has a self time\n * (the time spent running the task itself).\n */\nexport interface SyntheticEventWithSelfTime extends TraceEventData {\n selfTime?: MicroSeconds;\n}\n\n/**\n * A profile call created in the frontend from samples disguised as a\n * trace event.\n */\nexport interface TraceEventSyntheticProfileCall extends SyntheticEventWithSelfTime {\n callFrame: Protocol.Runtime.CallFrame;\n nodeId: Protocol.integer;\n}\n\n/**\n * A trace event augmented synthetically in the frontend to contain\n * its self time.\n */\nexport type SyntheticRendererEvent = TraceEventRendererEvent&SyntheticEventWithSelfTime;\n\nexport type TraceEntry = SyntheticRendererEvent|TraceEventSyntheticProfileCall;\n\nexport function isSyntheticInteractionEvent(event: TraceEventData): event is SyntheticInteractionEvent {\n return Boolean(\n 'interactionId' in event && event.args?.data && 'beginEvent' in event.args.data && 'endEvent' in event.args.data);\n}\n\nexport function isRendererEvent(event: TraceEventData): event is TraceEntry {\n return isTraceEventRendererEvent(event) || isProfileCall(event);\n}\n\nclass ProfileIdTag {\n readonly #profileIdTag: (symbol|undefined);\n}\nexport type ProfileID = string&ProfileIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function ProfileID(value: string): ProfileID {\n return value as ProfileID;\n}\n\nclass CallFrameIdTag {\n readonly #callFrameIdTag: (symbol|undefined);\n}\nexport type CallFrameID = number&CallFrameIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function CallFrameID(value: number): CallFrameID {\n return value as CallFrameID;\n}\n\nclass ProcessIdTag {\n readonly #processIdTag: (symbol|undefined);\n}\nexport type ProcessID = number&ProcessIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function ProcessID(value: number): ProcessID {\n return value as ProcessID;\n}\n\nclass ThreadIdTag {\n readonly #threadIdTag: (symbol|undefined);\n}\nexport type ThreadID = number&ThreadIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function ThreadID(value: number): ThreadID {\n return value as ThreadID;\n}\n\nclass WorkerIdTag {\n readonly #workerIdTag: (symbol|undefined);\n}\nexport type WorkerId = string&WorkerIdTag;\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function WorkerId(value: string): WorkerId {\n return value as WorkerId;\n}\n\nexport function isTraceEventComplete(event: TraceEventData): event is TraceEventComplete {\n return event.ph === Phase.COMPLETE;\n}\n\nexport function isTraceEventBegin(event: TraceEventData): event is TraceEventBegin {\n return event.ph === Phase.BEGIN;\n}\n\nexport function isTraceEventEnd(event: TraceEventData): event is TraceEventEnd {\n return event.ph === Phase.END;\n}\n\nexport function isTraceEventDispatch(event: TraceEventData): event is TraceEventDispatch {\n return event.name === 'EventDispatch';\n}\n\nexport function isTraceEventInstant(event: TraceEventData): event is TraceEventInstant {\n return event.ph === Phase.INSTANT;\n}\n\nexport function isTraceEventRendererEvent(event: TraceEventData): event is TraceEventRendererEvent {\n return isTraceEventInstant(event) || isTraceEventComplete(event);\n}\n\nexport function isTraceEventFireIdleCallback(event: TraceEventData): event is TraceEventFireIdleCallback {\n return event.name === 'FireIdleCallback';\n}\n\nexport function isTraceEventUpdateCounters(event: TraceEventData): event is TraceEventUpdateCounters {\n return event.name === 'UpdateCounters';\n}\n\nexport function isThreadName(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventThreadName {\n return traceEventData.name === 'thread_name';\n}\n\nexport function isProcessName(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventProcessName {\n return traceEventData.name === 'process_name';\n}\n\nexport function isTraceEventTracingStartedInBrowser(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventTracingStartedInBrowser {\n return traceEventData.name === 'TracingStartedInBrowser';\n}\n\nexport function isTraceEventFrameCommittedInBrowser(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventFrameCommittedInBrowser {\n return traceEventData.name === 'FrameCommittedInBrowser';\n}\n\nexport function isTraceEventCommitLoad(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventCommitLoad {\n return traceEventData.name === 'CommitLoad';\n}\n\nexport function isTraceEventNavigationStart(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventNavigationStart {\n return traceEventData.name === 'navigationStart';\n}\n\nexport function isTraceEventAnimation(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventAnimation {\n return traceEventData.name === 'Animation';\n}\n\nexport function isTraceEventLayoutShift(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventLayoutShift {\n return traceEventData.name === 'LayoutShift';\n}\n\nexport function isTraceEventLayoutInvalidation(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventLayoutInvalidation {\n return traceEventData.name === 'LayoutInvalidationTracking' ||\n traceEventData.name === 'ScheduleStyleInvalidationTracking';\n}\n\nexport function isTraceEventStyleRecalcInvalidation(traceEventData: TraceEventData):\n traceEventData is TraceEventStyleRecalcInvalidation {\n return traceEventData.name === 'StyleRecalcInvalidationTracking';\n}\n\nexport function isTraceEventFirstContentfulPaint(traceEventData: TraceEventData):\n traceEventData is TraceEventFirstContentfulPaint {\n return traceEventData.name === 'firstContentfulPaint';\n}\n\nexport function isTraceEventLargestContentfulPaintCandidate(traceEventData: TraceEventData):\n traceEventData is TraceEventLargestContentfulPaintCandidate {\n return traceEventData.name === 'largestContentfulPaint::Candidate';\n}\nexport function isTraceEventLargestImagePaintCandidate(traceEventData: TraceEventData):\n traceEventData is TraceEventLargestImagePaintCandidate {\n return traceEventData.name === 'LargestImagePaint::Candidate';\n}\nexport function isTraceEventLargestTextPaintCandidate(traceEventData: TraceEventData):\n traceEventData is TraceEventLargestTextPaintCandidate {\n return traceEventData.name === 'LargestTextPaint::Candidate';\n}\n\nexport function isTraceEventMarkLoad(traceEventData: TraceEventData): traceEventData is TraceEventMarkLoad {\n return traceEventData.name === 'MarkLoad';\n}\n\nexport function isTraceEventFirstPaint(traceEventData: TraceEventData): traceEventData is TraceEventFirstPaint {\n return traceEventData.name === 'firstPaint';\n}\n\nexport function isTraceEventMarkDOMContent(traceEventData: TraceEventData): traceEventData is TraceEventMarkDOMContent {\n return traceEventData.name === 'MarkDOMContent';\n}\n\nexport function isTraceEventInteractiveTime(traceEventData: TraceEventData):\n traceEventData is TraceEventInteractiveTime {\n return traceEventData.name === 'InteractiveTime';\n}\n\nexport function isTraceEventEventTiming(traceEventData: TraceEventData): traceEventData is TraceEventEventTiming {\n return traceEventData.name === KnownEventName.EventTiming;\n}\n\nexport function isTraceEventEventTimingEnd(traceEventData: TraceEventData): traceEventData is TraceEventEventTimingEnd {\n return isTraceEventEventTiming(traceEventData) && traceEventData.ph === Phase.ASYNC_NESTABLE_END;\n}\nexport function isTraceEventEventTimingStart(traceEventData: TraceEventData):\n traceEventData is TraceEventEventTimingBegin {\n return isTraceEventEventTiming(traceEventData) && traceEventData.ph === Phase.ASYNC_NESTABLE_START;\n}\n\nexport function isTraceEventGPUTask(traceEventData: TraceEventData): traceEventData is TraceEventGPUTask {\n return traceEventData.name === 'GPUTask';\n}\n\nexport function isTraceEventProfile(traceEventData: TraceEventData): traceEventData is TraceEventProfile {\n return traceEventData.name === 'Profile';\n}\n\nexport function isSyntheticTraceEventCpuProfile(traceEventData: TraceEventData):\n traceEventData is SyntheticTraceEventCpuProfile {\n return traceEventData.name === 'CpuProfile';\n}\n\nexport function isTraceEventProfileChunk(traceEventData: TraceEventData): traceEventData is TraceEventProfileChunk {\n return traceEventData.name === 'ProfileChunk';\n}\n\nexport function isTraceEventResourceChangePriority(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceChangePriority {\n return traceEventData.name === 'ResourceChangePriority';\n}\n\nexport function isTraceEventResourceSendRequest(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceSendRequest {\n return traceEventData.name === 'ResourceSendRequest';\n}\n\nexport function isTraceEventResourceReceiveResponse(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceReceiveResponse {\n return traceEventData.name === 'ResourceReceiveResponse';\n}\n\nexport function isTraceEventResourceMarkAsCached(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceMarkAsCached {\n return traceEventData.name === 'ResourceMarkAsCached';\n}\n\nexport function isTraceEventResourceFinish(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceFinish {\n return traceEventData.name === 'ResourceFinish';\n}\n\nexport function isTraceEventResourceWillSendRequest(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceWillSendRequest {\n return traceEventData.name === 'ResourceWillSendRequest';\n}\n\nexport function isTraceEventResourceReceivedData(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventResourceReceivedData {\n return traceEventData.name === 'ResourceReceivedData';\n}\n\nexport function isSyntheticNetworkRequestDetailsEvent(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventSyntheticNetworkRequest {\n return traceEventData.name === 'SyntheticNetworkRequest';\n}\n\nexport function isTraceEventPrePaint(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventPrePaint {\n return traceEventData.name === 'PrePaint';\n}\n\nexport function isTraceEventNavigationStartWithURL(event: TraceEventData): event is TraceEventNavigationStart {\n return Boolean(isTraceEventNavigationStart(event) && event.args.data && event.args.data.documentLoaderURL !== '');\n}\n\nexport function isTraceEventMainFrameViewport(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventMainFrameViewport {\n return traceEventData.name === 'PaintTimingVisualizer::Viewport';\n}\n\nexport function isSyntheticUserTimingTraceEvent(traceEventData: TraceEventData):\n traceEventData is TraceEventSyntheticUserTiming {\n if (traceEventData.cat !== 'blink.user_timing') {\n return false;\n }\n const data = traceEventData.args?.data;\n if (!data) {\n return false;\n }\n return 'beginEvent' in data && 'endEvent' in data;\n}\n\nexport function isSyntheticConsoleTimingTraceEvent(traceEventData: TraceEventData):\n traceEventData is TraceEventSyntheticConsoleTiming {\n if (traceEventData.cat !== 'blink.console') {\n return false;\n }\n const data = traceEventData.args?.data;\n if (!data) {\n return false;\n }\n return 'beginEvent' in data && 'endEvent' in data;\n}\n\nexport function isTraceEventPerformanceMeasure(traceEventData: TraceEventData):\n traceEventData is TraceEventPerformanceMeasureBegin|TraceEventPerformanceMeasureEnd {\n return traceEventData.cat === 'blink.user_timing' && isTraceEventAsyncPhase(traceEventData);\n}\n\nexport function isTraceEventPerformanceMark(traceEventData: TraceEventData):\n traceEventData is TraceEventPerformanceMark {\n return traceEventData.cat === 'blink.user_timing' &&\n (traceEventData.ph === Phase.MARK || traceEventData.ph === Phase.INSTANT);\n}\n\nexport function isTraceEventConsoleTime(traceEventData: TraceEventData): traceEventData is TraceEventConsoleTimeBegin|\n TraceEventConsoleTimeEnd {\n return traceEventData.cat === 'blink.console' && isTraceEventAsyncPhase(traceEventData);\n}\n\nexport function isTraceEventTimeStamp(traceEventData: TraceEventData): traceEventData is TraceEventTimeStamp {\n return traceEventData.ph === Phase.INSTANT && traceEventData.name === 'TimeStamp';\n}\n\nexport function isTraceEventParseHTML(traceEventData: TraceEventData): traceEventData is TraceEventParseHTML {\n return traceEventData.name === 'ParseHTML';\n}\n\nexport interface TraceEventAsync extends TraceEventData {\n ph: Phase.ASYNC_NESTABLE_START|Phase.ASYNC_NESTABLE_INSTANT|Phase.ASYNC_NESTABLE_END|Phase.ASYNC_STEP_INTO|\n Phase.ASYNC_BEGIN|Phase.ASYNC_END|Phase.ASYNC_STEP_PAST;\n}\n\nexport function isTraceEventAsyncPhase(traceEventData: TraceEventData): boolean {\n const asyncPhases = new Set([\n Phase.ASYNC_NESTABLE_START,\n Phase.ASYNC_NESTABLE_INSTANT,\n Phase.ASYNC_NESTABLE_END,\n Phase.ASYNC_STEP_INTO,\n Phase.ASYNC_BEGIN,\n Phase.ASYNC_END,\n Phase.ASYNC_STEP_PAST,\n ]);\n return asyncPhases.has(traceEventData.ph);\n}\n\nexport function isSyntheticLayoutShift(traceEventData: TraceEventData): traceEventData is SyntheticLayoutShift {\n if (!isTraceEventLayoutShift(traceEventData) || !traceEventData.args.data) {\n return false;\n }\n return 'rawEvent' in traceEventData.args.data;\n}\n\nexport function isProfileCall(event: TraceEventData): event is TraceEventSyntheticProfileCall {\n return 'callFrame' in event;\n}\n\n/**\n * This is an exhaustive list of events we track in the Performance\n * panel. Note not all of them are necessarliry shown in the flame\n * chart, some of them we only use for parsing.\n * TODO(crbug.com/1428024): Complete this enum.\n */\nexport const enum KnownEventName {\n /* Task */\n Program = 'Program',\n RunTask = 'RunTask',\n AsyncTask = 'AsyncTask',\n RunMicrotasks = 'RunMicrotasks',\n\n /* Load */\n XHRLoad = 'XHRLoad',\n XHRReadyStateChange = 'XHRReadyStateChange',\n /* Parse */\n ParseHTML = 'ParseHTML',\n ParseCSS = 'ParseAuthorStyleSheet',\n /* V8 */\n CompileScript = 'V8.CompileScript',\n CompileCode = 'V8.CompileCode',\n CompileModule = 'V8.CompileModule',\n Optimize = 'V8.OptimizeCode',\n WasmStreamFromResponseCallback = 'v8.wasm.streamFromResponseCallback',\n WasmCompiledModule = 'v8.wasm.compiledModule',\n WasmCachedModule = 'v8.wasm.cachedModule',\n WasmModuleCacheHit = 'v8.wasm.moduleCacheHit',\n WasmModuleCacheInvalid = 'v8.wasm.moduleCacheInvalid',\n /* Js */\n ProfileCall = 'ProfileCall',\n EvaluateScript = 'EvaluateScript',\n FunctionCall = 'FunctionCall',\n EventDispatch = 'EventDispatch',\n EvaluateModule = 'v8.evaluateModule',\n RequestMainThreadFrame = 'RequestMainThreadFrame',\n RequestAnimationFrame = 'RequestAnimationFrame',\n CancelAnimationFrame = 'CancelAnimationFrame',\n FireAnimationFrame = 'FireAnimationFrame',\n RequestIdleCallback = 'RequestIdleCallback',\n CancelIdleCallback = 'CancelIdleCallback',\n FireIdleCallback = 'FireIdleCallback',\n TimerInstall = 'TimerInstall',\n TimerRemove = 'TimerRemove',\n TimerFire = 'TimerFire',\n WebSocketCreate = 'WebSocketCreate',\n WebSocketSendHandshake = 'WebSocketSendHandshakeRequest',\n WebSocketReceiveHandshake = 'WebSocketReceiveHandshakeResponse',\n WebSocketDestroy = 'WebSocketDestroy',\n CryptoDoEncrypt = 'DoEncrypt',\n CryptoDoEncryptReply = 'DoEncryptReply',\n CryptoDoDecrypt = 'DoDecrypt',\n CryptoDoDecryptReply = 'DoDecryptReply',\n CryptoDoDigest = 'DoDigest',\n CryptoDoDigestReply = 'DoDigestReply',\n CryptoDoSign = 'DoSign',\n CryptoDoSignReply = 'DoSignReply',\n CryptoDoVerify = 'DoVerify',\n CryptoDoVerifyReply = 'DoVerifyReply',\n V8Execute = 'V8.Execute',\n\n /* Gc */\n GC = 'GCEvent',\n DOMGC = 'BlinkGC.AtomicPhase',\n IncrementalGCMarking = 'V8.GCIncrementalMarking',\n MajorGC = 'MajorGC',\n MinorGC = 'MinorGC',\n GCCollectGarbage = 'BlinkGC.AtomicPhase',\n\n /* Layout */\n ScheduleStyleRecalculation = 'ScheduleStyleRecalculation',\n RecalculateStyles = 'RecalculateStyles',\n Layout = 'Layout',\n UpdateLayoutTree = 'UpdateLayoutTree',\n InvalidateLayout = 'InvalidateLayout',\n LayoutInvalidationTracking = 'LayoutInvalidationTracking',\n ComputeIntersections = 'ComputeIntersections',\n HitTest = 'HitTest',\n PrePaint = 'PrePaint',\n Layerize = 'Layerize',\n LayoutShift = 'LayoutShift',\n UpdateLayerTree = 'UpdateLayerTree',\n ScheduleStyleInvalidationTracking = 'ScheduleStyleInvalidationTracking',\n StyleRecalcInvalidationTracking = 'StyleRecalcInvalidationTracking',\n StyleInvalidatorInvalidationTracking = 'StyleInvalidatorInvalidationTracking',\n\n /* Paint */\n ScrollLayer = 'ScrollLayer',\n UpdateLayer = 'UpdateLayer',\n PaintSetup = 'PaintSetup',\n Paint = 'Paint',\n PaintImage = 'PaintImage',\n Commit = 'Commit',\n CompositeLayers = 'CompositeLayers',\n RasterTask = 'RasterTask',\n ImageDecodeTask = 'ImageDecodeTask',\n ImageUploadTask = 'ImageUploadTask',\n DecodeImage = 'Decode Image',\n ResizeImage = 'Resize Image',\n DrawLazyPixelRef = 'Draw LazyPixelRef',\n DecodeLazyPixelRef = 'Decode LazyPixelRef',\n GPUTask = 'GPUTask',\n Rasterize = 'Rasterize',\n EventTiming = 'EventTiming',\n\n /* Compile */\n OptimizeCode = 'V8.OptimizeCode',\n CacheScript = 'v8.produceCache',\n CacheModule = 'v8.produceModuleCache',\n // V8Sample events are coming from tracing and contain raw stacks with function addresses.\n // After being processed with help of JitCodeAdded and JitCodeMoved events they\n // get translated into function infos and stored as stacks in JSSample events.\n V8Sample = 'V8Sample',\n JitCodeAdded = 'JitCodeAdded',\n JitCodeMoved = 'JitCodeMoved',\n StreamingCompileScript = 'v8.parseOnBackground',\n StreamingCompileScriptWaiting = 'v8.parseOnBackgroundWaiting',\n StreamingCompileScriptParsing = 'v8.parseOnBackgroundParsing',\n BackgroundDeserialize = 'v8.deserializeOnBackground',\n FinalizeDeserialization = 'V8.FinalizeDeserialization',\n\n /* Markers */\n CommitLoad = 'CommitLoad',\n MarkLoad = 'MarkLoad',\n MarkDOMContent = 'MarkDOMContent',\n MarkFirstPaint = 'firstPaint',\n MarkFCP = 'firstContentfulPaint',\n MarkLCPCandidate = 'largestContentfulPaint::Candidate',\n MarkLCPInvalidate = 'largestContentfulPaint::Invalidate',\n NavigationStart = 'navigationStart',\n TimeStamp = 'TimeStamp',\n ConsoleTime = 'ConsoleTime',\n UserTiming = 'UserTiming',\n InteractiveTime = 'InteractiveTime',\n\n /* Frames */\n BeginFrame = 'BeginFrame',\n NeedsBeginFrameChanged = 'NeedsBeginFrameChanged',\n BeginMainThreadFrame = 'BeginMainThreadFrame',\n ActivateLayerTree = 'ActivateLayerTree',\n DrawFrame = 'DrawFrame',\n DroppedFrame = 'DroppedFrame',\n FrameStartedLoading = 'FrameStartedLoading',\n\n /* Network request events */\n ResourceWillSendRequest = 'ResourceWillSendRequest',\n ResourceSendRequest = 'ResourceSendRequest',\n ResourceReceiveResponse = 'ResourceReceiveResponse',\n ResourceReceivedData = 'ResourceReceivedData',\n ResourceFinish = 'ResourceFinish',\n ResourceMarkAsCached = 'ResourceMarkAsCached',\n\n /* Web sockets */\n WebSocketSendHandshakeRequest = 'WebSocketSendHandshakeRequest',\n WebSocketReceiveHandshakeResponse = 'WebSocketReceiveHandshakeResponse',\n\n /* CPU Profiling */\n Profile = 'Profile',\n StartProfiling = 'CpuProfiler::StartProfiling',\n ProfileChunk = 'ProfileChunk',\n UpdateCounters = 'UpdateCounters',\n\n /* Other */\n Animation = 'Animation',\n ParseAuthorStyleSheet = 'ParseAuthorStyleSheet',\n EmbedderCallback = 'EmbedderCallback',\n SetLayerTreeId = 'SetLayerTreeId',\n TracingStartedInPage = 'TracingStartedInPage',\n TracingSessionIdForWorker = 'TracingSessionIdForWorker',\n LazyPixelRef = 'LazyPixelRef',\n LayerTreeHostImplSnapshot = 'cc::LayerTreeHostImpl',\n PictureSnapshot = 'cc::Picture',\n DisplayItemListSnapshot = 'cc::DisplayItemList',\n InputLatencyMouseMove = 'InputLatency::MouseMove',\n InputLatencyMouseWheel = 'InputLatency::MouseWheel',\n ImplSideFling = 'InputHandlerProxy::HandleGestureFling::started',\n}\n", "\n// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\nimport type * as Types from './../types/types.js';\nimport type * as ModelHandlers from './ModelHandlers.js';\n\nexport interface TraceEventHandler {\n reset(): void;\n initialize?(freshRecording?: boolean): void;\n handleEvent(data: {}): void;\n finalize?(): Promise<void>;\n data(): unknown;\n deps?(): TraceEventHandlerName[];\n handleUserConfig?(config: Types.Configuration.Configuration): void;\n}\nexport type TraceEventHandlerName = keyof typeof ModelHandlers;\n\n// This type maps TraceEventHandler names to the return type of their data\n// function. So, for example, if we are given an object with a key of 'foo'\n// and a value which is a TraceHandler containing a data() function that\n// returns a string, this type will be { foo: string }.\n//\n// This allows us to model the behavior of the TraceProcessor in the model,\n// which takes an object with TraceEventHandlers as part of its config, and\n// which ultimately returns an object keyed off the names of the\n// TraceEventHandlers, and with values that are derived from each\n// TraceEventHandler's data function.\n//\n// So, concretely, we provide a TraceEventHandler for calculating the #time\n// bounds of a trace called TraceBounds, whose data() function returns a\n// TraceWindow. The HandlerData, therefore, would determine that the\n// TraceProcessor would contain a key called 'TraceBounds' whose value is\n// a TraceWindow.\nexport type EnabledHandlerDataWithMeta<T extends {[key: string]: TraceEventHandler}> = {\n // We allow the user to configure which handlers are created by passing them\n // in when constructing a model instance. However, we then ensure that the\n // Meta handler is added to that, as the Model relies on some of the data\n // from the Meta handler when creating the file. Therefore, this type\n // explicitly defines that the Meta data is present, before then extending it\n // with the index type to represent all the other handlers.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Meta: Readonly<ReturnType<typeof ModelHandlers['Meta']['data']>>,\n}&{\n // For every key in the object, look up the TraceEventHandler's data function\n // and use its return type as the value for the object.\n [K in keyof T]: Readonly<ReturnType<T[K]['data']>>;\n};\n\nexport type HandlersWithMeta<T extends {[key: string]: TraceEventHandler}> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Meta: typeof ModelHandlers.Meta,\n}&{\n [K in keyof T]: T[K];\n};\n\n// Represents the final parsed data from all of the handlers. Note that because\n// we are currently in the middle of the migration of data engines, not all the\n// handlers are enabled. Therefore for now you should use the type defined in\n// models/trace/handlers/Migration.ts, `PartialTraceData`, which\n// represents the final parsed data for only the enabled handlers.\nexport type TraceParseData = Readonly<EnabledHandlerDataWithMeta<typeof ModelHandlers>>;\n\nexport type Handlers = typeof ModelHandlers;\n\nexport const enum HandlerState {\n UNINITIALIZED = 1,\n INITIALIZED = 2,\n FINALIZED = 3,\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Types from '../types/types.js';\n\n/**\n * There are two metadata events that we care about.\n * => AuctionWorkletRunningInProcess tells us which process the Auction Worklet\n * has taken to run in.\n * => AuctionWorkletDoneWithProcess tells us when the worklet is done with that\n * process. This is less useful - but in the future we might want to surface\n * this information so we still parse and return the event.\n *\n * It is important to note that the top level PID on these events is NOT the\n * PID that the worklet is running on; instead we have to look at its\n * args.data.pid property, which is the PID of the process that it is running\n * on.\n *\n * For any given RunningInProcess event, we would typically expect to see a\n * DoneWithProcess event, however this is not guaranteed, especially as users\n * can record any chunk of time in DevTools.\n *\n * Similarly, it is also possible to see a DoneWithProcess event without a\n * RunningInProcess event, if the user started recording after the auction\n * worklets started. Therefore we are happy to create\n * SyntheticAuctionWorkletEvents as long as we see just one of these events.\n *\n * If we do get two events and need to pair them, we can use the\n * args.data.target property, which is a string ID shared by both\n * events.\n */\nconst runningInProcessEvents:\n Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventAuctionWorkletRunningInProcess> = new Map();\nconst doneWithProcessEvents:\n Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventAuctionWorkletDoneWithProcess> = new Map();\n\n// Keyed by the PID defined in `args.data.pid` on AuctionWorklet trace events..\nconst createdSyntheticEvents: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.SyntheticAuctionWorkletEvent> =\n new Map();\n\n// Each AuctonWorklet takes over a process and has 2 threads (that we care\n// about and want to show as tracks):\n// 1. A CrUtilityMain thread which is known as the \"control process\".\n// 2. A AuctionV8HelperThread which is the actual auction worklet and will be\n// either a \"Seller\" or a \"Bidder\"\n// To detect these we look for the metadata thread_name events. We key these by\n// PID so that we can easily look them up later without having to loop through.\nconst utilityThreads: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventThreadName> = new Map();\nconst v8HelperThreads: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventThreadName> = new Map();\n\nexport function reset(): void {\n runningInProcessEvents.clear();\n doneWithProcessEvents.clear();\n createdSyntheticEvents.clear();\n utilityThreads.clear();\n v8HelperThreads.clear();\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (Types.TraceEvents.isTraceEventAuctionWorkletRunningInProcess(event)) {\n runningInProcessEvents.set(event.args.data.pid, event);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventAuctionWorkletDoneWithProcess(event)) {\n doneWithProcessEvents.set(event.args.data.pid, event);\n return;\n }\n\n if (Types.TraceEvents.isThreadName(event)) {\n if (event.args.name === 'auction_worklet.CrUtilityMain') {\n utilityThreads.set(event.pid, event);\n return;\n }\n if (event.args.name === 'AuctionV8HelperThread') {\n v8HelperThreads.set(event.pid, event);\n }\n }\n}\n\nfunction workletType(input: string): Types.TraceEvents.AuctionWorkletType {\n switch (input) {\n case 'seller':\n return Types.TraceEvents.AuctionWorkletType.SELLER;\n case 'bidder':\n return Types.TraceEvents.AuctionWorkletType.BIDDER;\n default:\n return Types.TraceEvents.AuctionWorkletType.UNKNOWN;\n }\n}\n\n/**\n * We cannot make the full event without knowing the type of event, but we can\n * create everything other than the `args` field, as those are identical\n * regardless of the type of event.\n */\nfunction makeSyntheticEventBase(event: Types.TraceEvents.TraceEventAuctionWorkletDoneWithProcess|\n Types.TraceEvents.TraceEventAuctionWorkletRunningInProcess):\n Omit<Types.TraceEvents.SyntheticAuctionWorkletEvent, 'args'> {\n return {\n name: 'SyntheticAuctionWorkletEvent',\n s: Types.TraceEvents.TraceEventScope.THREAD,\n cat: event.cat,\n tid: event.tid,\n ts: event.ts,\n ph: Types.TraceEvents.Phase.INSTANT,\n pid: event.args.data.pid,\n host: event.args.data.host,\n target: event.args.data.target,\n type: workletType(event.args.data.type),\n };\n}\n\nexport async function finalize(): Promise<void> {\n // Loop through the utility threads we found to create the worklet events. We\n // expect each worklet to have a utility thread, so we can use them as the\n // root of our list of worklets.\n for (const [pid, utilityThreadNameEvent] of utilityThreads) {\n const v8HelperEvent = v8HelperThreads.get(pid);\n if (!v8HelperEvent) {\n // Bad trace data - AuctionWorklets are expected to always have both threads.\n continue;\n }\n\n const runningEvent = runningInProcessEvents.get(pid);\n const doneWithEvent = doneWithProcessEvents.get(pid);\n\n // We can create a worklet from either the runningEvent or doneWithEvent -\n // we do not need both. We cannot express that to TypeScript with an early\n // return here, so instead we set the event initially to null, and then\n // create it from either the running event or the doneWith event. If it is\n // still null after this, that means neither event was found, and we drop\n // the worklet as we do not have enough information to create the synthetic\n // event.\n\n let syntheticEvent: Types.TraceEvents.SyntheticAuctionWorkletEvent|null = null;\n\n if (runningEvent) {\n syntheticEvent = {\n ...makeSyntheticEventBase(runningEvent),\n args: {\n data: {\n runningInProcessEvent: runningEvent,\n utilityThread: utilityThreadNameEvent,\n v8HelperThread: v8HelperEvent,\n },\n },\n };\n if (doneWithEvent) {\n syntheticEvent.args.data.doneWithProcessEvent = doneWithEvent;\n }\n } else if (doneWithEvent) {\n syntheticEvent = {\n ...makeSyntheticEventBase(doneWithEvent),\n args: {\n data: {\n doneWithProcessEvent: doneWithEvent,\n utilityThread: utilityThreadNameEvent,\n v8HelperThread: v8HelperEvent,\n },\n },\n };\n if (runningEvent) {\n syntheticEvent.args.data.runningInProcessEvent = runningEvent;\n }\n }\n if (syntheticEvent === null) {\n continue;\n }\n createdSyntheticEvents.set(pid, syntheticEvent);\n }\n}\n\nexport interface AuctionWorkletsData {\n worklets: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.SyntheticAuctionWorkletEvent>;\n}\n\nexport function data(): AuctionWorkletsData {\n return {\n worklets: new Map(createdSyntheticEvents),\n };\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport {data as metaHandlerData} from './MetaHandler.js';\n\nimport {type TraceEventHandlerName, HandlerState} from './types.js';\n\nimport * as Types from '../types/types.js';\nimport * as Helpers from '../helpers/helpers.js';\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\n// Each thread contains events. Events indicate the thread and process IDs, which are\n// used to store the event in the correct process thread entry below.\nconst eventsInProcessThread =\n new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventGPUTask[]>>();\n\nlet mainGPUThreadTasks: Types.TraceEvents.TraceEventGPUTask[] = [];\n\nexport function reset(): void {\n eventsInProcessThread.clear();\n mainGPUThreadTasks = [];\n\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('GPU Handler was not reset before being initialized');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('GPU Handler is not initialized');\n }\n\n if (!Types.TraceEvents.isTraceEventGPUTask(event)) {\n return;\n }\n\n Helpers.Trace.addEventToProcessThread(event, eventsInProcessThread);\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('GPU Handler is not initialized');\n }\n\n const {gpuProcessId, gpuThreadId} = metaHandlerData();\n const gpuThreadsForProcess = eventsInProcessThread.get(gpuProcessId);\n if (gpuThreadsForProcess && gpuThreadId) {\n mainGPUThreadTasks = gpuThreadsForProcess.get(gpuThreadId) || [];\n }\n handlerState = HandlerState.FINALIZED;\n}\n\nexport interface GPUHandlerReturnData {\n mainGPUThreadTasks: readonly Types.TraceEvents.TraceEventGPUTask[];\n}\n\nexport function data(): GPUHandlerReturnData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('GPU Handler is not finalized');\n }\n return {\n mainGPUThreadTasks: [...mainGPUThreadTasks],\n };\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta'];\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\n// We track the renderer processes we see in each frame on the way through the trace.\nconst rendererProcessesByFrameId: FrameProcessData = new Map();\n\n// We will often want to key data by Frame IDs, and commonly we'll care most\n// about the main frame's ID, so we store and expose that.\nlet mainFrameId: string = '';\nlet mainFrameURL: string = '';\n\nconst framesByProcessId = new Map<Types.TraceEvents.ProcessID, Map<string, Types.TraceEvents.TraceFrame>>();\n\n// We will often want to key data by the browser process, GPU process and top\n// level renderer IDs, so keep a track on those.\nlet browserProcessId: Types.TraceEvents.ProcessID = Types.TraceEvents.ProcessID(-1);\nlet browserThreadId: Types.TraceEvents.ThreadID = Types.TraceEvents.ThreadID(-1);\nlet gpuProcessId: Types.TraceEvents.ProcessID = Types.TraceEvents.ProcessID(-1);\nlet gpuThreadId: Types.TraceEvents.ThreadID = Types.TraceEvents.ThreadID(-1);\nlet viewportRect: DOMRect|null = null;\n\nconst topLevelRendererIds = new Set<Types.TraceEvents.ProcessID>();\nconst traceBounds: Types.Timing.TraceWindow = {\n min: Types.Timing.MicroSeconds(Number.POSITIVE_INFINITY),\n max: Types.Timing.MicroSeconds(Number.NEGATIVE_INFINITY),\n range: Types.Timing.MicroSeconds(Number.POSITIVE_INFINITY),\n};\n\n/**\n * These represent the user navigating. Values such as First Contentful Paint,\n * etc, are relative to the navigation.\n *\n * We store navigation events both by the frame and navigation ID. This means\n * when we need to look them up, we can use whichever ID we have.\n *\n * Note that these Maps will have the same values in them; these are just keyed\n * differently to make look-ups easier.\n *\n * We also additionally maintain an array of only navigations that occured on\n * the main frame. In many places in the UI we only care about highlighting\n * main frame navigations, so calculating this list here is better than\n * filtering either of the below maps over and over again at the UI layer.\n */\nconst navigationsByFrameId = new Map<string, Types.TraceEvents.TraceEventNavigationStart[]>();\nconst navigationsByNavigationId = new Map<string, Types.TraceEvents.TraceEventNavigationStart>();\nconst mainFrameNavigations: Types.TraceEvents.TraceEventNavigationStart[] = [];\n\n// Represents all the threads in the trace, organized by process. This is mostly for internal\n// bookkeeping so that during the finalize pass we can obtain the main and browser thread IDs.\nconst threadsInProcess =\n new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventThreadName>>();\n\nlet traceStartedTimeFromTracingStartedEvent = Types.Timing.MicroSeconds(-1);\nconst eventPhasesOfInterestForTraceBounds = new Set([\n Types.TraceEvents.Phase.BEGIN,\n Types.TraceEvents.Phase.END,\n Types.TraceEvents.Phase.COMPLETE,\n Types.TraceEvents.Phase.INSTANT,\n]);\n\nlet handlerState = HandlerState.UNINITIALIZED;\nexport function reset(): void {\n navigationsByFrameId.clear();\n navigationsByNavigationId.clear();\n mainFrameNavigations.length = 0;\n\n browserProcessId = Types.TraceEvents.ProcessID(-1);\n browserThreadId = Types.TraceEvents.ThreadID(-1);\n gpuProcessId = Types.TraceEvents.ProcessID(-1);\n gpuThreadId = Types.TraceEvents.ThreadID(-1);\n viewportRect = null;\n topLevelRendererIds.clear();\n threadsInProcess.clear();\n rendererProcessesByFrameId.clear();\n framesByProcessId.clear();\n\n traceBounds.min = Types.Timing.MicroSeconds(Number.POSITIVE_INFINITY);\n traceBounds.max = Types.Timing.MicroSeconds(Number.NEGATIVE_INFINITY);\n traceBounds.range = Types.Timing.MicroSeconds(Number.POSITIVE_INFINITY);\n traceStartedTimeFromTracingStartedEvent = Types.Timing.MicroSeconds(-1);\n\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('Meta Handler was not reset');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nfunction updateRendererProcessByFrame(\n event: Types.TraceEvents.TraceEventData, frame: Types.TraceEvents.TraceFrame): void {\n const framesInProcessById = Platform.MapUtilities.getWithDefault(framesByProcessId, frame.processId, () => new Map());\n framesInProcessById.set(frame.frame, frame);\n\n const rendererProcessInFrame = Platform.MapUtilities.getWithDefault(\n rendererProcessesByFrameId, frame.frame,\n () => new Map<\n Types.TraceEvents.ProcessID, {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindow}[]>());\n const rendererProcessInfo = Platform.MapUtilities.getWithDefault(rendererProcessInFrame, frame.processId, () => {\n return [];\n });\n const lastProcessData = rendererProcessInfo.at(-1);\n\n // Only store a new entry if the URL changed, otherwise it's just\n // redundant information.\n if (lastProcessData && lastProcessData.frame.url === frame.url) {\n return;\n }\n // For now we store the time of the event as the min. In the finalize we step\n // through each of these windows and update their max and range values.\n rendererProcessInfo.push({\n frame,\n window: {\n min: event.ts,\n max: Types.Timing.MicroSeconds(0),\n range: Types.Timing.MicroSeconds(0),\n },\n });\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Meta Handler is not initialized');\n }\n\n // If there is a timestamp (which meta events do not have), and the event does\n // not end with ::UMA then it, and the event is in the set of valid phases,\n // then it should be included for the purposes of calculating the trace bounds.\n // The UMA events in particular seem to be reported on page unloading, which\n // often extends the bounds of the trace unhelpfully.\n if (event.ts !== 0 && !event.name.endsWith('::UMA') && eventPhasesOfInterestForTraceBounds.has(event.ph)) {\n traceBounds.min = Types.Timing.MicroSeconds(Math.min(event.ts, traceBounds.min));\n const eventDuration = event.dur || Types.Timing.MicroSeconds(0);\n traceBounds.max = Types.Timing.MicroSeconds(Math.max(event.ts + eventDuration, traceBounds.max));\n }\n\n if (Types.TraceEvents.isProcessName(event) &&\n (event.args.name === 'Browser' || event.args.name === 'HeadlessBrowser')) {\n browserProcessId = event.pid;\n return;\n }\n\n if (Types.TraceEvents.isProcessName(event) && (event.args.name === 'Gpu' || event.args.name === 'GPU Process')) {\n gpuProcessId = event.pid;\n return;\n }\n\n if (Types.TraceEvents.isThreadName(event) && event.args.name === 'CrGpuMain') {\n gpuThreadId = event.tid;\n return;\n }\n\n if (Types.TraceEvents.isThreadName(event) && event.args.name === 'CrBrowserMain') {\n browserThreadId = event.tid;\n }\n\n if (Types.TraceEvents.isTraceEventMainFrameViewport(event) && viewportRect === null) {\n const rectAsArray = event.args.data.viewport_rect;\n const viewportX = rectAsArray[0];\n const viewportY = rectAsArray[1];\n const viewportWidth = rectAsArray[2];\n const viewportHeight = rectAsArray[5];\n viewportRect = new DOMRect(viewportX, viewportY, viewportWidth, viewportHeight);\n }\n\n // The TracingStartedInBrowser event includes the data on which frames are\n // in scope at the start of the trace. We use this to identify the frame with\n // no parent, i.e. the top level frame.\n if (Types.TraceEvents.isTraceEventTracingStartedInBrowser(event)) {\n traceStartedTimeFromTracingStartedEvent = event.ts;\n\n if (!event.args.data) {\n throw new Error('No frames found in trace data');\n }\n\n for (const frame of (event.args.data.frames ?? [])) {\n updateRendererProcessByFrame(event, frame);\n\n if (frame.parent) {\n continue;\n }\n\n mainFrameId = frame.frame;\n mainFrameURL = frame.url;\n topLevelRendererIds.add(frame.processId);\n }\n return;\n }\n\n // FrameCommittedInBrowser events tell us information about each frame\n // and we use these to track how long each individual renderer is active\n // for. We track all renderers here (top level and those in frames), but\n // for convenience we also populate a set of top level renderer IDs.\n if (Types.TraceEvents.isTraceEventFrameCommittedInBrowser(event)) {\n const frame = event.args.data;\n if (!frame) {\n return;\n }\n\n updateRendererProcessByFrame(event, frame);\n\n if (frame.parent) {\n return;\n }\n\n topLevelRendererIds.add(frame.processId);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventCommitLoad(event)) {\n const frameData = event.args.data;\n if (!frameData) {\n return;\n }\n\n const {frame, name, url} = frameData;\n updateRendererProcessByFrame(event, {processId: event.pid, frame, name, url});\n return;\n }\n\n // Track all threads based on the process & thread IDs.\n if (Types.TraceEvents.isThreadName(event)) {\n const threads = Platform.MapUtilities.getWithDefault(threadsInProcess, event.pid, () => new Map());\n threads.set(event.tid, event);\n return;\n }\n\n // Track all navigation events. Note that there can be navigation start events\n // but where the documentLoaderURL is empty. As far as the trace rendering is\n // concerned, these events are noise so we filter them out here.\n if (Types.TraceEvents.isTraceEventNavigationStartWithURL(event) && event.args.data) {\n const navigationId = event.args.data.navigationId;\n if (navigationsByNavigationId.has(navigationId)) {\n throw new Error('Found multiple navigation start events with the same navigation ID.');\n }\n navigationsByNavigationId.set(navigationId, event);\n\n const frameId = event.args.frame;\n const existingFrameNavigations = navigationsByFrameId.get(frameId) || [];\n existingFrameNavigations.push(event);\n navigationsByFrameId.set(frameId, existingFrameNavigations);\n if (frameId === mainFrameId) {\n mainFrameNavigations.push(event);\n }\n return;\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Handler is not initialized');\n }\n\n // We try to set the minimum time by finding the event with the smallest\n // timestamp. However, if we also got a timestamp from the\n // TracingStartedInBrowser event, we should always use that.\n // But in some traces (for example, CPU profiles) we do not get that event,\n // hence why we need to check we got a timestamp from it before setting it.\n if (traceStartedTimeFromTracingStartedEvent >= 0) {\n traceBounds.min = traceStartedTimeFromTracingStartedEvent;\n }\n traceBounds.range = Types.Timing.MicroSeconds(traceBounds.max - traceBounds.min);\n\n // If we go from foo.com to example.com we will get a new renderer, and\n // therefore the \"top level renderer\" will have a different PID as it has\n // changed. Here we step through each renderer process and updated its window\n // bounds, such that we end up with the time ranges in the trace for when\n // each particular renderer started and stopped being the main renderer\n // process.\n for (const [, processWindows] of rendererProcessesByFrameId) {\n const processWindowValues = [...processWindows.values()].flat();\n for (let i = 0; i < processWindowValues.length; i++) {\n const currentWindow = processWindowValues[i];\n const nextWindow = processWindowValues[i + 1];\n\n // For the last window we set its max to be positive infinity.\n // TODO: Move the trace bounds handler into meta so we can clamp first and last windows.\n if (!nextWindow) {\n currentWindow.window.max = Types.Timing.MicroSeconds(traceBounds.max);\n currentWindow.window.range = Types.Timing.MicroSeconds(traceBounds.max - currentWindow.window.min);\n } else {\n currentWindow.window.max = Types.Timing.MicroSeconds(nextWindow.window.min - 1);\n currentWindow.window.range = Types.Timing.MicroSeconds(currentWindow.window.max - currentWindow.window.min);\n }\n }\n }\n\n // Frame ids which we didn't register using either the TracingStartedInBrowser or\n // the FrameCommittedInBrowser events are considered noise, so we filter them out, as well\n // as the navigations that belong to such frames.\n for (const [frameId, navigations] of navigationsByFrameId) {\n // The frames in the rendererProcessesByFrameId map come only from the\n // TracingStartedInBrowser and FrameCommittedInBrowser events, so we can use it as point\n // of comparison to determine if a frameId should be discarded.\n if (rendererProcessesByFrameId.has(frameId)) {\n continue;\n }\n navigationsByFrameId.delete(frameId);\n for (const navigation of navigations) {\n if (!navigation.args.data) {\n continue;\n }\n navigationsByNavigationId.delete(navigation.args.data.navigationId);\n }\n }\n\n handlerState = HandlerState.FINALIZED;\n}\n\ntype MetaHandlerData = {\n traceBounds: Types.Timing.TraceWindow,\n browserProcessId: Types.TraceEvents.ProcessID,\n browserThreadId: Types.TraceEvents.ThreadID,\n gpuProcessId: Types.TraceEvents.ProcessID,\n gpuThreadId?: Types.TraceEvents.ThreadID,\n viewportRect?: DOMRect,\n navigationsByFrameId: Map<string, Types.TraceEvents.TraceEventNavigationStart[]>,\n navigationsByNavigationId: Map<string, Types.TraceEvents.TraceEventNavigationStart>,\n threadsInProcess:\n Map<Types.TraceEvents.ProcessID,\n Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventThreadName>>,\n mainFrameId: string,\n mainFrameURL: string,\n /**\n * A frame can have multiple renderer processes, at the same time,\n * a renderer process can have multiple URLs. This map tracks the\n * processes active on a given frame, with the time window in which\n * they were active. Because a renderer process might have multiple\n * URLs, each process in each frame has an array of windows, with an\n * entry for each URL it had.\n */\n rendererProcessesByFrame: FrameProcessData,\n topLevelRendererIds: Set<Types.TraceEvents.ProcessID>,\n frameByProcessId: Map<Types.TraceEvents.ProcessID, Map<string, Types.TraceEvents.TraceFrame>>,\n mainFrameNavigations: Types.TraceEvents.TraceEventNavigationStart[],\n};\n\n// Each frame has a single render process at a given time but it can have\n// multiple render processes during a trace, for example if a navigation\n// occurred in the frame. This map tracks the process that was active for\n// each frame at each point in time. Also, because a process can be\n// assigned to multiple URLs, there is a window for each URL a process\n// was assigned.\n//\n// Note that different sites always end up in different render\n// processes, however two different URLs can point to the same site.\n// For example: https://google.com and https://maps.google.com point to\n// the same site.\n// Read more about this in\n// https://developer.chrome.com/articles/renderingng-architecture/#threads\n// and https://web.dev/same-site-same-origin/\nexport type FrameProcessData =\n Map<string,\n Map<Types.TraceEvents.ProcessID, {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindow}[]>>;\n\nexport function data(): MetaHandlerData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Meta Handler is not finalized');\n }\n\n return {\n traceBounds: {...traceBounds},\n browserProcessId,\n browserThreadId,\n gpuProcessId,\n gpuThreadId: gpuThreadId === Types.TraceEvents.ThreadID(-1) ? undefined : gpuThreadId,\n viewportRect: viewportRect || undefined,\n mainFrameId,\n mainFrameURL,\n navigationsByFrameId: new Map(navigationsByFrameId),\n navigationsByNavigationId: new Map(navigationsByNavigationId),\n threadsInProcess: new Map(threadsInProcess),\n rendererProcessesByFrame: new Map(rendererProcessesByFrameId),\n topLevelRendererIds: new Set(topLevelRendererIds),\n frameByProcessId: new Map(framesByProcessId),\n mainFrameNavigations: [...mainFrameNavigations],\n };\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as SamplesIntegrator from './SamplesIntegrator.js';\nexport * as Timing from './Timing.js';\nexport * as Trace from './Trace.js';\nexport * as TreeHelpers from './TreeHelpers.js';\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport type * as CPUProfile from '../../cpu_profile/cpu_profile.js';\nimport * as Types from '../types/types.js';\n\nimport {millisecondsToMicroseconds} from './Timing.js';\nimport {makeProfileCall, mergeEventsInOrder} from './Trace.js';\n\n/**\n * This is a helper that integrates CPU profiling data coming in the\n * shape of samples, with trace events. Samples indicate what the JS\n * stack trace looked at a given point in time, but they don't have\n * duration. The SamplesIntegrator task is to make an approximation\n * of what the duration of each JS call was, given the sample data and\n * given the trace events profiled during that time. At the end of its\n * execution, the SamplesIntegrator returns an array of ProfileCalls\n * (under SamplesIntegrator::buildProfileCalls()), which\n * represent JS calls, with a call frame and duration. These calls have\n * the shape of a complete trace events and can be treated as flame\n * chart entries in the timeline.\n *\n * The approach to build the profile calls consists in tracking the\n * current stack as the following events happen (in order):\n * 1. A sample was done.\n * 2. A trace event started.\n * 3. A trace event ended.\n * Depending on the event and on the data that's coming with it the\n * stack is updated by adding or removing JS calls to it and updating\n * the duration of the calls in the tracking stack.\n *\n * note: Although this approach has been implemented since long ago, and\n * is relatively efficent (adds a complexity over the trace parsing of\n * O(n) where n is the number of samples) it has proven to be faulty.\n * It might be worthwhile experimenting with improvements or with a\n * completely different approach. Improving the approach is tracked in\n * crbug.com/1417439\n */\nexport class SamplesIntegrator {\n /**\n * The result of runing the samples integrator. Holds the JS calls\n * with their approximated duration after integrating samples into the\n * trace event tree.\n */\n #constructedProfileCalls: Types.TraceEvents.TraceEventSyntheticProfileCall[] = [];\n /**\n * tracks the state of the JS stack at each point in time to update\n * the profile call durations as new events arrive. This doesn't only\n * happen with new profile calls (in which case we would compare the\n * stack in them) but also with trace events (in which case we would\n * update the duration of the events we are tracking at the moment).\n */\n #currentJSStack: Types.TraceEvents.TraceEventSyntheticProfileCall[] = [];\n /**\n * Process holding the CPU profile and trace events.\n */\n #processId: Types.TraceEvents.ProcessID;\n /**\n * Thread holding the CPU profile and trace events.\n */\n #threadId: Types.TraceEvents.ThreadID;\n /**\n * Tracks the depth of the JS stack at the moment a trace event starts\n * or ends. It is assumed that for the duration of a trace event, the\n * JS stack's depth cannot decrease, since JS calls that started\n * before a trace event cannot end during the trace event. So as trace\n * events arrive, we store the \"locked\" amount of JS frames that were\n * in the stack before the event came.\n */\n #lockedJsStackDepth: number[] = [];\n /**\n * Used to keep track when samples should be integrated even if they\n * are not children of invocation trace events. This is useful in\n * cases where we can be missing the start of JS invocation events if\n * we start tracing half-way through.\n */\n #fakeJSInvocation = false;\n /**\n * The parsed CPU profile, holding the tree hierarchy of JS frames and\n * the sample data.\n */\n #profileModel: CPUProfile.CPUProfileDataModel.CPUProfileDataModel;\n /**\n * Because GC nodes don't have a stack, we artificially add a stack to\n * them which corresponds to that of the previous sample. This map\n * tracks which node is used for the stack of a GC call.\n * Note that GC samples are not shown in the flamechart, however they\n * are used during the construction of for profile calls, as we can\n * infer information about the duration of the executed code when a\n * GC node is sampled.\n */\n #nodeForGC = new Map<Types.TraceEvents.TraceEventSyntheticProfileCall, CPUProfile.ProfileTreeModel.ProfileNode>();\n\n #engineConfig: Types.Configuration.Configuration;\n\n constructor(\n profileModel: CPUProfile.CPUProfileDataModel.CPUProfileDataModel, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID, configuration?: Types.Configuration.Configuration) {\n this.#profileModel = profileModel;\n this.#threadId = tid;\n this.#processId = pid;\n this.#engineConfig = configuration || Types.Configuration.DEFAULT;\n }\n\n buildProfileCalls(traceEvents: Types.TraceEvents.TraceEventData[]):\n Types.TraceEvents.TraceEventSyntheticProfileCall[] {\n const mergedEvents = mergeEventsInOrder(traceEvents, this.callsFromProfileSamples());\n const stack = [];\n for (let i = 0; i < mergedEvents.length; i++) {\n const event = mergedEvents[i];\n // Because instant trace events have no duration, they don't provide\n // useful information for possible changes in the duration of calls\n // in the JS stack.\n if (event.ph === Types.TraceEvents.Phase.INSTANT) {\n continue;\n }\n if (stack.length === 0) {\n if (Types.TraceEvents.isProfileCall(event)) {\n this.#onProfileCall(event);\n continue;\n }\n stack.push(event);\n this.#onTraceEventStart(event);\n continue;\n }\n\n const parentEvent = stack.at(-1);\n if (parentEvent === undefined) {\n continue;\n }\n const begin = event.ts;\n const parentBegin = parentEvent.ts;\n const parentDuration = parentEvent.dur || 0;\n const parentEnd = parentBegin + parentDuration;\n\n const startsAfterParent = begin >= parentEnd;\n if (startsAfterParent) {\n this.#onTraceEventEnd(parentEvent);\n stack.pop();\n i--;\n continue;\n }\n if (Types.TraceEvents.isProfileCall(event)) {\n this.#onProfileCall(event, parentEvent);\n continue;\n }\n this.#onTraceEventStart(event);\n stack.push(event);\n }\n while (stack.length) {\n const last = stack.pop();\n if (last) {\n this.#onTraceEventEnd(last);\n }\n }\n return this.#constructedProfileCalls;\n }\n\n #onTraceEventStart(event: Types.TraceEvents.TraceEventData): void {\n // Top level events cannot be nested into JS frames so we reset\n // the stack when we find one.\n if (event.name === Types.TraceEvents.KnownEventName.RunMicrotasks ||\n event.name === Types.TraceEvents.KnownEventName.RunTask) {\n this.#lockedJsStackDepth = [];\n this.#truncateJSStack(0, event.ts);\n this.#fakeJSInvocation = false;\n }\n\n if (this.#fakeJSInvocation) {\n this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, event.ts);\n this.#fakeJSInvocation = false;\n }\n this.#extractStackTrace(event);\n // Keep track of the call frames in the stack before the event\n // happened. For the duration of this event, these frames cannot\n // change (none can be terminated before this event finishes).\n //\n // Also, every frame that is opened after this event, is considered\n // to be a descendant of the event. So once the event finishes, the\n // frames that were opened after it, need to be closed (see\n // onEndEvent).\n //\n // TODO(crbug.com/1417439):\n // The assumption that every frame opened after an event is a\n // descendant of the event is incorrect. For example, a JS call that\n // parents a trace event might have been sampled after the event was\n // dispatched. In this case the JS call would be discarded if this\n // event isn't an invocation event, otherwise the call will be\n // considered a child of the event. In both cases, the result would\n // be incorrect.\n this.#lockedJsStackDepth.push(this.#currentJSStack.length);\n }\n\n #onProfileCall(event: Types.TraceEvents.TraceEventSyntheticProfileCall, parent?: Types.TraceEvents.TraceEventData):\n void {\n if ((parent && SamplesIntegrator.isJSInvocationEvent(parent)) || this.#fakeJSInvocation) {\n this.#extractStackTrace(event);\n } else if (Types.TraceEvents.isProfileCall(event) && this.#currentJSStack.length === 0) {\n // Force JS Samples to show up even if we are not inside a JS\n // invocation event, because we can be missing the start of JS\n // invocation events if we start tracing half-way through. Pretend\n // we have a top-level JS invocation event.\n this.#fakeJSInvocation = true;\n const stackDepthBefore = this.#currentJSStack.length;\n this.#extractStackTrace(event);\n this.#lockedJsStackDepth.push(stackDepthBefore);\n }\n }\n\n #onTraceEventEnd(event: Types.TraceEvents.TraceEventData): void {\n // Because the event has ended, any frames that happened after\n // this event are terminated. Frames that are ancestors to this\n // event are extended to cover its ending.\n const endTime = Types.Timing.MicroSeconds(event.ts + (event.dur || 0));\n this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, endTime);\n }\n\n /**\n * Builds the initial calls with no duration from samples. Their\n * purpose is to be merged with the trace event array being parsed so\n * that they can be traversed in order with them and their duration\n * can be updated as the SampleIntegrator callbacks are invoked.\n */\n callsFromProfileSamples(): Types.TraceEvents.TraceEventSyntheticProfileCall[] {\n const samples = this.#profileModel.samples;\n const timestamps = this.#profileModel.timestamps;\n if (!samples) {\n return [];\n }\n const calls: Types.TraceEvents.TraceEventSyntheticProfileCall[] = [];\n let prevNode;\n for (let i = 0; i < samples.length; i++) {\n const node = this.#profileModel.nodeByIndex(i);\n const timestamp = millisecondsToMicroseconds(Types.Timing.MilliSeconds(timestamps[i]));\n if (!node) {\n continue;\n }\n const call = makeProfileCall(node, timestamp, this.#processId, this.#threadId);\n calls.push(call);\n if (node.id === this.#profileModel.gcNode?.id && prevNode) {\n // GC samples have no stack, so we just put GC node on top of the\n // last recorded sample. Cache the previous sample for future\n // reference.\n this.#nodeForGC.set(call, prevNode);\n continue;\n }\n prevNode = node;\n }\n return calls;\n }\n\n #getStackTraceFromProfileCall(profileCall: Types.TraceEvents.TraceEventSyntheticProfileCall):\n Types.TraceEvents.TraceEventSyntheticProfileCall[] {\n let node = this.#profileModel.nodeById(profileCall.nodeId);\n const isGarbageCollection = Boolean(node?.id === this.#profileModel.gcNode?.id);\n if (isGarbageCollection) {\n // Because GC don't have a stack, we use the stack of the previous\n // sample.\n node = this.#nodeForGC.get(profileCall) || null;\n }\n if (!node) {\n return [];\n }\n // `node.depth` is 0 based, so to set the size of the array we need\n // to add 1 to its value.\n const callFrames =\n new Array<Types.TraceEvents.TraceEventSyntheticProfileCall>(node.depth + 1 + Number(isGarbageCollection));\n // Add the stack trace in reverse order (bottom first).\n let i = callFrames.length - 1;\n if (isGarbageCollection) {\n // Place the garbage collection call frame on top of the stack.\n callFrames[i--] = profileCall;\n }\n while (node) {\n callFrames[i--] = makeProfileCall(node, profileCall.ts, this.#processId, this.#threadId);\n node = node.parent;\n }\n return callFrames;\n }\n\n /**\n * Update tracked stack using this event's call stack.\n */\n #extractStackTrace(event: Types.TraceEvents.TraceEventData): void {\n const stackTrace =\n Types.TraceEvents.isProfileCall(event) ? this.#getStackTraceFromProfileCall(event) : this.#currentJSStack;\n SamplesIntegrator.filterStackFrames(stackTrace, this.#engineConfig);\n\n const endTime = event.ts + (event.dur || 0);\n const minFrames = Math.min(stackTrace.length, this.#currentJSStack.length);\n let i;\n // Merge a sample's stack frames with the stack frames we have\n // so far if we detect they are equivalent.\n // Graphically\n // This:\n // Current stack trace Sample\n // [-------A------] [A]\n // [-------B------] [B]\n // [-------C------] [C]\n // ^ t = x1 ^ t = x2\n\n // Becomes this:\n // New stack trace after merge\n // [--------A-------]\n // [--------B-------]\n // [--------C-------]\n // ^ t = x2\n for (i = this.#lockedJsStackDepth.at(-1) || 0; i < minFrames; ++i) {\n const newFrame = stackTrace[i].callFrame;\n const oldFrame = this.#currentJSStack[i].callFrame;\n if (!SamplesIntegrator.framesAreEqual(newFrame, oldFrame)) {\n break;\n }\n // Scoot the right edge of this callFrame to the right\n this.#currentJSStack[i].dur =\n Types.Timing.MicroSeconds(Math.max(this.#currentJSStack[i].dur || 0, endTime - this.#currentJSStack[i].ts));\n }\n\n // If there are call frames in the sample that differ with the stack\n // we have, update the stack, but keeping the common frames in place\n // Graphically\n // This:\n // Current stack trace Sample\n // [-------A------] [A]\n // [-------B------] [B]\n // [-------C------] [C]\n // [-------D------] [E]\n // ^ t = x1 ^ t = x2\n // Becomes this:\n // New stack trace after merge\n // [--------A-------]\n // [--------B-------]\n // [--------C-------]\n // [E]\n // ^ t = x2\n this.#truncateJSStack(i, event.ts);\n\n for (; i < stackTrace.length; ++i) {\n const call = stackTrace[i];\n if (call.nodeId === this.#profileModel.programNode?.id || call.nodeId === this.#profileModel.root?.id ||\n call.nodeId === this.#profileModel.idleNode?.id || call.nodeId === this.#profileModel.gcNode?.id) {\n // Skip (root), (program) and (idle) frames, since this are not\n // relevant for web profiling and we don't want to show them in\n // the timeline.\n continue;\n }\n this.#currentJSStack.push(call);\n this.#constructedProfileCalls.push(call);\n }\n }\n\n /**\n * When a call stack that differs from the one we are tracking has\n * been detected in the samples, the latter is \"truncated\" by\n * setting the ending time of its call frames and removing the top\n * call frames that aren't shared with the new call stack. This way,\n * we can update the tracked stack with the new call frames on top.\n * @param depth the amount of call frames from bottom to top that\n * should be kept in the tracking stack trace. AKA amount of shared\n * call frames between two stacks.\n * @param time the new end of the call frames in the stack.\n */\n #truncateJSStack(depth: number, time: Types.Timing.MicroSeconds): void {\n if (this.#lockedJsStackDepth.length) {\n const lockedDepth = this.#lockedJsStackDepth.at(-1);\n if (lockedDepth && depth < lockedDepth) {\n console.error(`Child stack is shallower (${depth}) than the parent stack (${lockedDepth}) at ${time}`);\n depth = lockedDepth;\n }\n }\n if (this.#currentJSStack.length < depth) {\n console.error(`Trying to truncate higher than the current stack size at ${time}`);\n depth = this.#currentJSStack.length;\n }\n for (let k = 0; k < this.#currentJSStack.length; ++k) {\n this.#currentJSStack[k].dur = Types.Timing.MicroSeconds(Math.max(time - this.#currentJSStack[k].ts, 0));\n }\n this.#currentJSStack.length = depth;\n }\n\n /**\n * Generally, before JS is executed, a trace event is dispatched that\n * parents the JS calls. These we call \"invocation\" events. This\n * function determines if an event is one of such.\n */\n static isJSInvocationEvent(event: Types.TraceEvents.TraceEventData): boolean {\n switch (event.name) {\n case Types.TraceEvents.KnownEventName.RunMicrotasks:\n case Types.TraceEvents.KnownEventName.FunctionCall:\n case Types.TraceEvents.KnownEventName.EvaluateScript:\n case Types.TraceEvents.KnownEventName.EvaluateModule:\n case Types.TraceEvents.KnownEventName.EventDispatch:\n case Types.TraceEvents.KnownEventName.V8Execute:\n return true;\n }\n // Also consider any new v8 trace events. (eg 'V8.RunMicrotasks' and 'v8.run')\n if (event.name.startsWith('v8') || event.name.startsWith('V8')) {\n return true;\n }\n return false;\n }\n\n static framesAreEqual(frame1: Protocol.Runtime.CallFrame, frame2: Protocol.Runtime.CallFrame): boolean {\n return frame1.scriptId === frame2.scriptId && frame1.functionName === frame2.functionName &&\n frame1.lineNumber === frame2.lineNumber;\n }\n\n static showNativeName(name: string, runtimeCallStatsEnabled: boolean): boolean {\n return runtimeCallStatsEnabled && Boolean(SamplesIntegrator.nativeGroup(name));\n }\n\n static nativeGroup(nativeName: string): 'Parse'|'Compile'|null {\n if (nativeName.startsWith('Parse')) {\n return 'Parse';\n }\n if (nativeName.startsWith('Compile') || nativeName.startsWith('Recompile')) {\n return 'Compile';\n }\n return null;\n }\n\n static isNativeRuntimeFrame(frame: Protocol.Runtime.CallFrame): boolean {\n return frame.url === 'native V8Runtime';\n }\n\n static filterStackFrames(\n stack: Types.TraceEvents.TraceEventSyntheticProfileCall[],\n engineConfig: Types.Configuration.Configuration): void {\n const showAllEvents = engineConfig.experiments.timelineShowAllEvents;\n if (showAllEvents) {\n return;\n }\n let previousNativeFrameName: string|null = null;\n let j = 0;\n for (let i = 0; i < stack.length; ++i) {\n const frame = stack[i].callFrame;\n const nativeRuntimeFrame = SamplesIntegrator.isNativeRuntimeFrame(frame);\n if (nativeRuntimeFrame &&\n !SamplesIntegrator.showNativeName(frame.functionName, engineConfig.experiments.timelineV8RuntimeCallStats)) {\n continue;\n }\n const nativeFrameName = nativeRuntimeFrame ? SamplesIntegrator.nativeGroup(frame.functionName) : null;\n if (previousNativeFrameName && previousNativeFrameName === nativeFrameName) {\n continue;\n }\n previousNativeFrameName = nativeFrameName;\n stack[j++] = stack[i];\n }\n stack.length = j;\n }\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Types from '../types/types.js';\n\nimport {getNavigationForTraceEvent} from './Trace.js';\n\nexport const millisecondsToMicroseconds = (value: Types.Timing.MilliSeconds): Types.Timing.MicroSeconds =>\n Types.Timing.MicroSeconds(value * 1000);\n\nexport const secondsToMilliseconds = (value: Types.Timing.Seconds): Types.Timing.MilliSeconds =>\n Types.Timing.MilliSeconds(value * 1000);\n\nexport const secondsToMicroseconds = (value: Types.Timing.Seconds): Types.Timing.MicroSeconds =>\n millisecondsToMicroseconds(secondsToMilliseconds(value));\n\nexport const microSecondsToMilliseconds = (value: Types.Timing.MicroSeconds): Types.Timing.MilliSeconds =>\n Types.Timing.MilliSeconds(value / 1000);\n\nexport const microSecondsToSeconds = (value: Types.Timing.MicroSeconds): Types.Timing.Seconds =>\n Types.Timing.Seconds(value / 1000 / 1000);\n\nexport function detectBestTimeUnit(timeInMicroseconds: Types.Timing.MicroSeconds): Types.Timing.TimeUnit {\n if (timeInMicroseconds < 1000) {\n return Types.Timing.TimeUnit.MICROSECONDS;\n }\n\n const timeInMilliseconds = timeInMicroseconds / 1000;\n if (timeInMilliseconds < 1000) {\n return Types.Timing.TimeUnit.MILLISECONDS;\n }\n\n const timeInSeconds = timeInMilliseconds / 1000;\n if (timeInSeconds < 60) {\n return Types.Timing.TimeUnit.SECONDS;\n }\n\n return Types.Timing.TimeUnit.MINUTES;\n}\n\ninterface FormatOptions extends Intl.NumberFormatOptions {\n format?: Types.Timing.TimeUnit;\n}\n\nconst defaultFormatOptions = {\n style: 'unit',\n unit: 'millisecond',\n unitDisplay: 'narrow',\n};\n\n// Create a bunch of common formatters up front, so that we're not creating\n// them repeatedly during rendering.\nconst serialize = (value: {}): string => JSON.stringify(value);\nconst formatterFactory = (key: string|undefined): Intl.NumberFormat => {\n // If we pass undefined as the locale, that achieves two things:\n // 1. Avoids us referencing window.navigatior to fetch the locale, which is\n // useful given long term we would like this engine to run in NodeJS\n // environments.\n // 2. Will cause the formatter to fallback to the locale of the system, which\n // is likely going to be the most accurate one to use anyway.\n return new Intl.NumberFormat(undefined, key ? JSON.parse(key) : {});\n};\nconst formatters = new Map<string, Intl.NumberFormat>();\n\n// Microsecond Formatter.\nPlatform.MapUtilities.getWithDefault(formatters, serialize({style: 'decimal'}), formatterFactory);\n\n// Millisecond Formatter\nPlatform.MapUtilities.getWithDefault(formatters, serialize(defaultFormatOptions), formatterFactory);\n\n// Second Formatter\nPlatform.MapUtilities.getWithDefault(\n formatters, serialize({...defaultFormatOptions, unit: 'second'}), formatterFactory);\n\n// Minute Formatter\nPlatform.MapUtilities.getWithDefault(\n formatters, serialize({...defaultFormatOptions, unit: 'minute'}), formatterFactory);\n\nexport function formatMicrosecondsTime(\n timeInMicroseconds: Types.Timing.MicroSeconds, opts: FormatOptions = {}): string {\n if (!opts.format) {\n opts.format = detectBestTimeUnit(timeInMicroseconds);\n }\n\n const timeInMilliseconds = timeInMicroseconds / 1000;\n const timeInSeconds = timeInMilliseconds / 1000;\n const formatterOpts = {...defaultFormatOptions, ...opts};\n\n switch (opts.format) {\n case Types.Timing.TimeUnit.MICROSECONDS: {\n const formatter =\n Platform.MapUtilities.getWithDefault(formatters, serialize({style: 'decimal'}), formatterFactory);\n return `${formatter.format(timeInMicroseconds)}\u03BCs`;\n }\n\n case Types.Timing.TimeUnit.MILLISECONDS: {\n const formatter = Platform.MapUtilities.getWithDefault(formatters, serialize(formatterOpts), formatterFactory);\n return formatter.format(timeInMilliseconds);\n }\n\n case Types.Timing.TimeUnit.SECONDS: {\n const formatter = Platform.MapUtilities.getWithDefault(\n formatters, serialize({...formatterOpts, unit: 'second'}), formatterFactory);\n return formatter.format(timeInSeconds);\n }\n\n default: {\n // Switch to mins & seconds.\n const minuteFormatter = Platform.MapUtilities.getWithDefault(\n formatters, serialize({...formatterOpts, unit: 'minute'}), formatterFactory);\n const secondFormatter = Platform.MapUtilities.getWithDefault(\n formatters, serialize({...formatterOpts, unit: 'second'}), formatterFactory);\n const timeInMinutes = timeInSeconds / 60;\n const [mins, divider, fraction] = minuteFormatter.formatToParts(timeInMinutes);\n\n let seconds = 0;\n if (divider && fraction) {\n // Convert the fraction value (a string) to the nearest second.\n seconds = Math.round(Number(`0.${fraction.value}`) * 60);\n }\n return `${minuteFormatter.format(Number(mins.value))} ${secondFormatter.format(seconds)}`;\n }\n }\n}\n\nexport function timeStampForEventAdjustedByClosestNavigation(\n event: Types.TraceEvents.TraceEventData,\n traceBounds: Types.Timing.TraceWindow,\n navigationsByNavigationId: Map<string, Types.TraceEvents.TraceEventNavigationStart>,\n navigationsByFrameId: Map<string, Types.TraceEvents.TraceEventNavigationStart[]>,\n ): Types.Timing.MicroSeconds {\n let eventTimeStamp = event.ts - traceBounds.min;\n if (event.args?.data?.navigationId) {\n const navigationForEvent = navigationsByNavigationId.get(event.args.data.navigationId);\n if (navigationForEvent) {\n eventTimeStamp = event.ts - navigationForEvent.ts;\n }\n } else if (event.args?.data?.frame) {\n const navigationForEvent = getNavigationForTraceEvent(event, event.args.data.frame, navigationsByFrameId);\n if (navigationForEvent) {\n eventTimeStamp = event.ts - navigationForEvent.ts;\n }\n }\n return Types.Timing.MicroSeconds(eventTimeStamp);\n}\n\nexport interface EventTimingsData<\n ValueType extends Types.Timing.MicroSeconds|Types.Timing.MilliSeconds|Types.Timing.Seconds,\n> {\n startTime: ValueType;\n endTime: ValueType;\n duration: ValueType;\n selfTime: ValueType;\n}\n\nexport function eventTimingsMicroSeconds(event: Types.TraceEvents.TraceEventData):\n EventTimingsData<Types.Timing.MicroSeconds> {\n return {\n startTime: event.ts,\n endTime: Types.Timing.MicroSeconds(event.ts + (event.dur || Types.Timing.MicroSeconds(0))),\n duration: Types.Timing.MicroSeconds(event.dur || 0),\n // TODO(crbug.com/1434599): Implement selfTime calculation for events\n // from the new engine.\n selfTime: Types.TraceEvents.isRendererEvent(event) ? Types.Timing.MicroSeconds(event.selfTime || 0) :\n Types.Timing.MicroSeconds(event.dur || 0),\n };\n}\nexport function eventTimingsMilliSeconds(event: Types.TraceEvents.TraceEventData):\n EventTimingsData<Types.Timing.MilliSeconds> {\n const microTimes = eventTimingsMicroSeconds(event);\n return {\n startTime: microSecondsToMilliseconds(microTimes.startTime),\n endTime: microSecondsToMilliseconds(microTimes.endTime),\n duration: microSecondsToMilliseconds(microTimes.duration),\n selfTime: microSecondsToMilliseconds(microTimes.selfTime),\n };\n}\nexport function eventTimingsSeconds(event: Types.TraceEvents.TraceEventData): EventTimingsData<Types.Timing.Seconds> {\n const microTimes = eventTimingsMicroSeconds(event);\n return {\n startTime: microSecondsToSeconds(microTimes.startTime),\n endTime: microSecondsToSeconds(microTimes.endTime),\n duration: microSecondsToSeconds(microTimes.duration),\n selfTime: microSecondsToSeconds(microTimes.selfTime),\n };\n}\n\nexport function traceWindowMilliSeconds(bounds: Types.Timing.TraceWindow): Types.Timing.TraceWindowMilliSeconds {\n return {\n min: microSecondsToMilliseconds(bounds.min),\n max: microSecondsToMilliseconds(bounds.max),\n range: microSecondsToMilliseconds(bounds.range),\n };\n}\n\nexport function traceWindowMillisecondsToMicroSeconds(bounds: Types.Timing.TraceWindowMilliSeconds):\n Types.Timing.TraceWindow {\n return {\n min: millisecondsToMicroseconds(bounds.min),\n max: millisecondsToMicroseconds(bounds.max),\n range: millisecondsToMicroseconds(bounds.range),\n };\n}\n\nexport function traceWindowFromMilliSeconds(\n min: Types.Timing.MilliSeconds, max: Types.Timing.MilliSeconds): Types.Timing.TraceWindow {\n const traceWindow: Types.Timing.TraceWindow = {\n min: millisecondsToMicroseconds(min),\n max: millisecondsToMicroseconds(max),\n range: millisecondsToMicroseconds(Types.Timing.MilliSeconds(max - min)),\n };\n return traceWindow;\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Types from '../types/types.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as CPUProfile from '../../cpu_profile/cpu_profile.js';\n\nexport function extractOriginFromTrace(firstNavigationURL: string): string|null {\n const url = new URL(firstNavigationURL);\n if (url) {\n // We do this to save some space in the toolbar - seeing the `www` is less\n // useful than seeing `foo.com` if it's truncated at narrow widths\n if (url.host.startsWith('www.')) {\n return url.host.slice(4);\n }\n return url.host;\n }\n return null;\n}\n\nexport type EventsInThread<T extends Types.TraceEvents.TraceEventData> = Map<Types.TraceEvents.ThreadID, T[]>;\n// Each thread contains events. Events indicate the thread and process IDs, which are\n// used to store the event in the correct process thread entry below.\nexport function addEventToProcessThread<T extends Types.TraceEvents.TraceEventData>(\n event: T,\n eventsInProcessThread: Map<Types.TraceEvents.ProcessID, EventsInThread<T>>,\n ): void {\n const {tid, pid} = event;\n let eventsInThread = eventsInProcessThread.get(pid);\n if (!eventsInThread) {\n eventsInThread = new Map<Types.TraceEvents.ThreadID, T[]>();\n }\n\n let events = eventsInThread.get(tid);\n if (!events) {\n events = [];\n }\n\n events.push(event);\n eventsInThread.set(event.tid, events);\n eventsInProcessThread.set(event.pid, eventsInThread);\n}\n\ntype TimeSpan = {\n ts: Types.Timing.MicroSeconds,\n dur?: Types.Timing.MicroSeconds,\n};\nfunction eventTimeComparator(a: TimeSpan, b: TimeSpan): -1|0|1 {\n const aBeginTime = a.ts;\n const bBeginTime = b.ts;\n if (aBeginTime < bBeginTime) {\n return -1;\n }\n if (aBeginTime > bBeginTime) {\n return 1;\n }\n const aDuration = a.dur ?? 0;\n const bDuration = b.dur ?? 0;\n const aEndTime = aBeginTime + aDuration;\n const bEndTime = bBeginTime + bDuration;\n if (aEndTime > bEndTime) {\n return -1;\n }\n if (aEndTime < bEndTime) {\n return 1;\n }\n return 0;\n}\n/**\n * Sorts all the events in place, in order, by their start time. If they have\n * the same start time, orders them by longest first.\n */\nexport function sortTraceEventsInPlace(events: {ts: Types.Timing.MicroSeconds, dur?: Types.Timing.MicroSeconds}[]):\n void {\n events.sort(eventTimeComparator);\n}\n\n/**\n * Returns an array of ordered events that results after merging the two\n * ordered input arrays.\n */\nexport function\nmergeEventsInOrder<T1 extends Types.TraceEvents.TraceEventData, T2 extends Types.TraceEvents.TraceEventData>(\n eventsArray1: T1[], eventsArray2: T2[]): (T1|T2)[] {\n const result = [];\n let i = 0;\n let j = 0;\n while (i < eventsArray1.length && j < eventsArray2.length) {\n const event1 = eventsArray1[i];\n const event2 = eventsArray2[j];\n const compareValue = eventTimeComparator(event1, event2);\n if (compareValue <= 0) {\n result.push(event1);\n i++;\n }\n if (compareValue === 1) {\n result.push(event2);\n j++;\n }\n }\n while (i < eventsArray1.length) {\n result.push(eventsArray1[i++]);\n }\n while (j < eventsArray2.length) {\n result.push(eventsArray2[j++]);\n }\n return result;\n}\n\nexport function getNavigationForTraceEvent(\n event: Types.TraceEvents.TraceEventData,\n eventFrameId: string,\n navigationsByFrameId: Map<string, Types.TraceEvents.TraceEventNavigationStart[]>,\n ): Types.TraceEvents.TraceEventNavigationStart|null {\n const navigations = navigationsByFrameId.get(eventFrameId);\n if (!navigations || eventFrameId === '') {\n // This event's navigation has been filtered out by the meta handler as a noise event\n // or contains an empty frameId.\n return null;\n }\n\n const eventNavigationIndex =\n Platform.ArrayUtilities.nearestIndexFromEnd(navigations, navigation => navigation.ts <= event.ts);\n\n if (eventNavigationIndex === null) {\n // This event's navigation has been filtered out by the meta handler as a noise event.\n return null;\n }\n return navigations[eventNavigationIndex];\n}\n\nexport function extractId(event: Types.TraceEvents.TraceEventNestableAsync): string|undefined {\n return event.id || event.id2?.global || event.id2?.local;\n}\n\nexport function activeURLForFrameAtTime(\n frameId: string, time: Types.Timing.MicroSeconds,\n rendererProcessesByFrame: Map<\n string,\n Map<Types.TraceEvents.ProcessID, {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindow}[]>>):\n string|null {\n const processData = rendererProcessesByFrame.get(frameId);\n if (!processData) {\n return null;\n }\n for (const processes of processData.values()) {\n for (const processInfo of processes) {\n if (processInfo.window.min > time || processInfo.window.max < time) {\n continue;\n }\n return processInfo.frame.url;\n }\n }\n return null;\n}\n\nexport function makeProfileCall(\n node: CPUProfile.ProfileTreeModel.ProfileNode, ts: Types.Timing.MicroSeconds, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID): Types.TraceEvents.TraceEventSyntheticProfileCall {\n return {\n cat: '',\n name: 'ProfileCall',\n nodeId: node.id,\n args: {},\n ph: Types.TraceEvents.Phase.COMPLETE,\n pid,\n tid,\n ts,\n dur: Types.Timing.MicroSeconds(0),\n selfTime: Types.Timing.MicroSeconds(0),\n callFrame: node.callFrame,\n };\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Types from '../types/types.js';\nlet nodeIdCount = 0;\nexport const makeTraceEntryNodeId = (): TraceEntryNodeId => (++nodeIdCount) as TraceEntryNodeId;\n\nexport const makeEmptyTraceEntryTree = (): TraceEntryTree => ({\n nodes: new Map(),\n roots: new Set(),\n maxDepth: 0,\n});\n\nexport const makeEmptyTraceEntryNode = (entry: Types.TraceEvents.TraceEntry, id: TraceEntryNodeId): TraceEntryNode => ({\n entry,\n id,\n parentId: null,\n children: new Set(),\n depth: 0,\n});\n\nexport interface TraceEntryTree {\n nodes: Map<TraceEntryNodeId, TraceEntryNode>;\n roots: Set<TraceEntryNode>;\n maxDepth: number;\n}\n\nexport interface TraceEntryNode {\n entry: Types.TraceEvents.TraceEntry;\n depth: number;\n id: TraceEntryNodeId;\n parentId?: TraceEntryNodeId|null;\n children: Set<TraceEntryNode>;\n}\n\nclass TraceEntryNodeIdTag {\n /* eslint-disable-next-line no-unused-private-class-members */\n readonly #tag: (symbol|undefined);\n}\nexport type TraceEntryNodeId = number&TraceEntryNodeIdTag;\n\n/**\n * Builds a hierarchy of the entries (trace events and profile calls) in\n * a particular thread of a particular process, assuming that they're\n * sorted, by iterating through all of the events in order.\n *\n * The approach is analogous to how a parser would be implemented. A\n * stack maintains local context. A scanner peeks and pops from the data\n * stream. Various \"tokens\" (events) are treated as \"whitespace\"\n * (ignored).\n *\n * The tree starts out empty and is populated as the hierarchy is built.\n * The nodes are also assumed to be created empty, with no known parent\n * or children.\n *\n * Complexity: O(n), where n = number of events\n */\nexport function treify(entries: Types.TraceEvents.TraceEntry[], options?: {\n filter: {has: (name: Types.TraceEvents.KnownEventName) => boolean},\n}): {tree: TraceEntryTree, entryToNode: Map<Types.TraceEvents.TraceEntry, TraceEntryNode>} {\n // As we construct the tree, store a map of each entry to its node. This\n // means if you are iterating over a list of RendererEntry events you can\n // easily look up that node in the tree.\n const entryToNode = new Map<Types.TraceEvents.TraceEntry, TraceEntryNode>();\n\n const stack = [];\n // Reset the node id counter for every new renderer.\n nodeIdCount = -1;\n const tree = makeEmptyTraceEntryTree();\n for (let i = 0; i < entries.length; i++) {\n const event = entries[i];\n // If the current event should not be part of the tree, then simply proceed\n // with the next event.\n if (options && !options.filter.has(event.name as Types.TraceEvents.KnownEventName)) {\n continue;\n }\n\n const duration = event.dur || 0;\n const nodeId = makeTraceEntryNodeId();\n const node = makeEmptyTraceEntryNode(event, nodeId);\n\n // If the parent stack is empty, then the current event is a root. Create a\n // node for it, mark it as a root, then proceed with the next event.\n if (stack.length === 0) {\n tree.nodes.set(nodeId, node);\n tree.roots.add(node);\n event.selfTime = Types.Timing.MicroSeconds(duration);\n stack.push(node);\n tree.maxDepth = Math.max(tree.maxDepth, stack.length);\n entryToNode.set(event, node);\n continue;\n }\n\n const parentNode = stack.at(-1);\n if (parentNode === undefined) {\n throw new Error('Impossible: no parent node found in the stack');\n }\n\n const parentEvent = parentNode.entry;\n\n const begin = event.ts;\n const parentBegin = parentEvent.ts;\n const parentDuration = parentEvent.dur || 0;\n const end = begin + duration;\n const parentEnd = parentBegin + parentDuration;\n // Check the relationship between the parent event at the top of the stack,\n // and the current event being processed. There are only 4 distinct\n // possiblities, only 2 of them actually valid, given the assumed sorting:\n // 1. Current event starts before the parent event, ends whenever. (invalid)\n // 2. Current event starts after the parent event, ends whenever. (valid)\n // 3. Current event starts during the parent event, ends after. (invalid)\n // 4. Current event starts and ends during the parent event. (valid)\n\n // 1. If the current event starts before the parent event, then the data is\n // not sorted properly, messed up some way, or this logic is incomplete.\n const startsBeforeParent = begin < parentBegin;\n if (startsBeforeParent) {\n throw new Error('Impossible: current event starts before the parent event');\n }\n\n // 2. If the current event starts after the parent event, then it's a new\n // parent. Pop, then handle current event again.\n const startsAfterParent = begin >= parentEnd;\n if (startsAfterParent) {\n stack.pop();\n i--;\n // The last created node has been discarded, so discard this id.\n nodeIdCount--;\n continue;\n }\n // 3. If the current event starts during the parent event, but ends\n // after it, then the data is messed up some way, for example a\n // profile call was sampled too late after its start, ignore the\n // problematic event.\n const endsAfterParent = end > parentEnd;\n if (endsAfterParent) {\n continue;\n }\n\n // 4. The only remaining case is the common case, where the current event is\n // contained within the parent event. Create a node for the current\n // event, establish the parent/child relationship, then proceed with the\n // next event.\n tree.nodes.set(nodeId, node);\n node.depth = stack.length;\n node.parentId = parentNode.id;\n parentNode.children.add(node);\n event.selfTime = Types.Timing.MicroSeconds(duration);\n if (parentEvent.selfTime !== undefined) {\n parentEvent.selfTime = Types.Timing.MicroSeconds(parentEvent.selfTime - (event.dur || 0));\n }\n stack.push(node);\n tree.maxDepth = Math.max(tree.maxDepth, stack.length);\n entryToNode.set(event, node);\n }\n return {tree, entryToNode};\n}\n\n/**\n * Iterates events in a tree hierarchically, from top to bottom,\n * calling back on every event's start and end in the order\n * as it traverses down and then up the tree.\n *\n * For example, given this tree, the following callbacks\n * are expected to be made in the following order\n * |---------------A---------------|\n * |------B------||-------D------|\n * |---C---|\n *\n * 1. Start A\n * 3. Start B\n * 4. Start C\n * 5. End C\n * 6. End B\n * 7. Start D\n * 8. End D\n * 9. End A\n *\n */\nexport function walkTreeFromEntry(\n entryToNode: Map<Types.TraceEvents.TraceEntry, TraceEntryNode>,\n rootEntry: Types.TraceEvents.TraceEntry,\n onEntryStart: (entry: Types.TraceEvents.TraceEntry) => void,\n onEntryEnd: (entry: Types.TraceEvents.TraceEntry) => void,\n ): void {\n const startNode = entryToNode.get(rootEntry);\n if (!startNode) {\n return;\n }\n walkTreeByNode(entryToNode, startNode, onEntryStart, onEntryEnd);\n}\n\n/**\n * Given a Helpers.TreeHelpers.RendererTree, this will iterates events in hierarchically, visiting\n * each root node and working from top to bottom, calling back on every event's\n * start and end in the order as it traverses down and then up the tree.\n *\n * For example, given this tree, the following callbacks\n * are expected to be made in the following order\n * |------------- Task A -------------||-- Task E --|\n * |-- Task B --||-- Task D --|\n * |- Task C -|\n *\n * 1. Start A\n * 3. Start B\n * 4. Start C\n * 5. End C\n * 6. End B\n * 7. Start D\n * 8. End D\n * 9. End A\n * 10. Start E\n * 11. End E\n *\n */\nexport function walkEntireTree(\n entryToNode: Map<Types.TraceEvents.TraceEntry, TraceEntryNode>,\n tree: TraceEntryTree,\n onEntryStart: (entry: Types.TraceEvents.TraceEntry) => void,\n onEntryEnd: (entry: Types.TraceEvents.TraceEntry) => void,\n ): void {\n for (const rootNode of tree.roots) {\n walkTreeByNode(entryToNode, rootNode, onEntryStart, onEntryEnd);\n }\n}\n\nfunction walkTreeByNode(\n entryToNode: Map<Types.TraceEvents.TraceEntry, TraceEntryNode>,\n rootNode: TraceEntryNode,\n onEntryStart: (entry: Types.TraceEvents.TraceEntry) => void,\n onEntryEnd: (entry: Types.TraceEvents.TraceEntry) => void,\n ): void {\n onEntryStart(rootNode.entry);\n for (const child of rootNode.children) {\n walkTreeByNode(entryToNode, child, onEntryStart, onEntryEnd);\n }\n onEntryEnd(rootNode.entry);\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\n\nimport {type TraceEventHandlerName, HandlerState} from './types.js';\n\nimport {ScoreClassification} from './PageLoadMetricsHandler.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport {data as screenshotsHandlerData} from './ScreenshotsHandler.js';\nimport * as Platform from '../../../core/platform/platform.js';\n\nimport * as Types from '../types/types.js';\n\n// We start with a score of zero and step through all Layout Shift records from\n// all renderers. Each record not only tells us which renderer it is, but also\n// the unweighted and weighted scores. The unweighted score is the score we would\n// get if the renderer were the only one in the viewport. The weighted score, on\n// the other hand, accounts for how much of the viewport that particular render\n// takes up when the shift happened. An ad frame in the corner of the viewport\n// that shifts is considered less disruptive, therefore, than if it were taking\n// up the whole viewport.\n//\n// Next, we step through all the records from all renderers and add the weighted\n// score to a running total across all of the renderers. We create a new \"cluster\"\n// and reset the running total when:\n//\n// 1. We observe a outermost frame navigation, or\n// 2. When there's a gap between records of > 1s, or\n// 3. When there's more than 5 seconds of continuous layout shifting.\n//\n// Note that for it to be Cumulative Layout Shift in the sense described in the\n// documentation we would need to guarantee that we are tracking from navigation\n// to unload. However, we don't make any such guarantees here (since a developer\n// can record and stop when they please), so we support the cluster approach,\n// and we can give them a score, but it is effectively a \"session\" score, a\n// score for the given recording, and almost certainly not the\n// navigation-to-unload CLS score.\n\ninterface LayoutShifts {\n clusters: LayoutShiftCluster[];\n sessionMaxScore: number;\n // The session window which contains the SessionMaxScore\n clsWindowID: number;\n // We use these to calculate root causes for a given LayoutShift\n prePaintEvents: Types.TraceEvents.TraceEventPrePaint[];\n layoutInvalidationEvents: Types.TraceEvents.TraceEventLayoutInvalidation[];\n styleRecalcInvalidationEvents: Types.TraceEvents.TraceEventStyleRecalcInvalidation[];\n scoreRecords: ScoreRecord[];\n}\n\n// This represents the maximum #time we will allow a cluster to go before we\n// reset it.\nexport const MAX_CLUSTER_DURATION = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(5000));\n\n// This represents the maximum #time we will allow between layout shift events\n// before considering it to be the start of a new cluster.\nexport const MAX_SHIFT_TIME_DELTA = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(1000));\n\n// Layout shifts are reported globally to the developer, irrespective of which\n// frame they originated in. However, each process does have its own individual\n// CLS score, so we need to segment by process. This means Layout Shifts from\n// sites with one process (no subframes, or subframes from the same origin)\n// will be reported together. In the case of multiple renderers (frames across\n// different origins), we offer the developer the ability to switch renderer in\n// the UI.\nconst layoutShiftEvents: Types.TraceEvents.TraceEventLayoutShift[] = [];\n\n// These events denote potential node resizings. We store them to link captured\n// layout shifts to the resizing of unsized elements.\nconst layoutInvalidationEvents: Types.TraceEvents.TraceEventLayoutInvalidation[] = [];\nconst styleRecalcInvalidationEvents: Types.TraceEvents.TraceEventStyleRecalcInvalidation[] = [];\n\n// Layout shifts happen during PrePaint as part of the rendering lifecycle.\n// We determine if a LayoutInvalidation event is a potential root cause of a layout\n// shift if the next PrePaint after the LayoutInvalidation is the parent\n// node of such shift.\nconst prePaintEvents: Types.TraceEvents.TraceEventPrePaint[] = [];\n\nlet sessionMaxScore = 0;\n\nlet clsWindowID = -1;\n\nconst clusters: LayoutShiftCluster[] = [];\n\n// Represents a point in time in which a LS score change\n// was recorded.\ntype ScoreRecord = {\n ts: number,\n score: number,\n};\n\n// The complete timeline of LS score changes in a trace.\n// Includes drops to 0 when session windows end.\nconst scoreRecords: ScoreRecord[] = [];\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('LayoutShifts Handler was not reset');\n }\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function reset(): void {\n handlerState = HandlerState.UNINITIALIZED;\n layoutShiftEvents.length = 0;\n layoutInvalidationEvents.length = 0;\n prePaintEvents.length = 0;\n clusters.length = 0;\n sessionMaxScore = 0;\n scoreRecords.length = 0;\n clsWindowID = -1;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Handler is not initialized');\n }\n\n if (Types.TraceEvents.isTraceEventLayoutShift(event) && !event.args.data?.had_recent_input) {\n layoutShiftEvents.push(event);\n return;\n }\n if (Types.TraceEvents.isTraceEventLayoutInvalidation(event)) {\n layoutInvalidationEvents.push(event);\n return;\n }\n if (Types.TraceEvents.isTraceEventStyleRecalcInvalidation(event)) {\n styleRecalcInvalidationEvents.push(event);\n }\n if (Types.TraceEvents.isTraceEventPrePaint(event)) {\n prePaintEvents.push(event);\n return;\n }\n}\n\nfunction traceWindowFromTime(time: Types.Timing.MicroSeconds): Types.Timing.TraceWindow {\n return {\n min: time,\n max: time,\n range: Types.Timing.MicroSeconds(0),\n };\n}\n\nfunction updateTraceWindowMax(traceWindow: Types.Timing.TraceWindow, newMax: Types.Timing.MicroSeconds): void {\n traceWindow.max = newMax;\n traceWindow.range = Types.Timing.MicroSeconds(traceWindow.max - traceWindow.min);\n}\n\nfunction findNextScreenshotSource(timestamp: Types.Timing.MicroSeconds): string|undefined {\n const screenshots = screenshotsHandlerData();\n const screenshotIndex = findNextScreenshotEventIndex(screenshots, timestamp);\n if (!screenshotIndex) {\n return undefined;\n }\n return `data:img/png;base64,${screenshots[screenshotIndex].args.snapshot}`;\n}\n\nexport function findNextScreenshotEventIndex(\n screenshots: Types.TraceEvents.TraceEventSnapshot[], timestamp: Types.Timing.MicroSeconds): number|null {\n return Platform.ArrayUtilities.nearestIndexFromBeginning(screenshots, frame => frame.ts > timestamp);\n}\n\nfunction buildScoreRecords(): void {\n const {traceBounds} = metaHandlerData();\n scoreRecords.push({ts: traceBounds.min, score: 0});\n\n for (const cluster of clusters) {\n let clusterScore = 0;\n if (cluster.events[0].args.data) {\n scoreRecords.push({ts: cluster.clusterWindow.min, score: cluster.events[0].args.data.weighted_score_delta});\n }\n for (let i = 0; i < cluster.events.length; i++) {\n const event = cluster.events[i];\n if (!event.args.data) {\n continue;\n }\n clusterScore += event.args.data.weighted_score_delta;\n scoreRecords.push({ts: event.ts, score: clusterScore});\n }\n scoreRecords.push({ts: cluster.clusterWindow.max, score: 0});\n }\n}\n\nexport async function finalize(): Promise<void> {\n // Ensure the events are sorted by #time ascending.\n layoutShiftEvents.sort((a, b) => a.ts - b.ts);\n prePaintEvents.sort((a, b) => a.ts - b.ts);\n layoutInvalidationEvents.sort((a, b) => a.ts - b.ts);\n\n // Each function transforms the data used by the next, as such the invoke order\n // is important.\n await buildLayoutShiftsClusters();\n buildScoreRecords();\n handlerState = HandlerState.FINALIZED;\n}\nasync function buildLayoutShiftsClusters(): Promise<void> {\n const {navigationsByFrameId, mainFrameId, traceBounds} = metaHandlerData();\n const navigations = navigationsByFrameId.get(mainFrameId) || [];\n if (layoutShiftEvents.length === 0) {\n return;\n }\n let firstShiftTime = layoutShiftEvents[0].ts;\n let lastShiftTime = layoutShiftEvents[0].ts;\n let lastShiftNavigation = null;\n // Now step through each and create clusters.\n // A cluster is equivalent to a session window (see https://web.dev/cls/#what-is-cls).\n // To make the line chart clear, we explicitly demark the limits of each session window\n // by starting the cumulative score of the window at the time of the first layout shift\n // and ending it (dropping the line back to 0) when the window ends according to the\n // thresholds (MAX_CLUSTER_DURATION, MAX_SHIFT_TIME_DELTA).\n for (const event of layoutShiftEvents) {\n // First detect if either the cluster duration or the #time between this and\n // the last shift has been exceeded.\n const clusterDurationExceeded = event.ts - firstShiftTime > MAX_CLUSTER_DURATION;\n const maxTimeDeltaSinceLastShiftExceeded = event.ts - lastShiftTime > MAX_SHIFT_TIME_DELTA;\n\n // Next take a look at navigations. If between this and the last shift we have navigated,\n // note it.\n const currentShiftNavigation = Platform.ArrayUtilities.nearestIndexFromEnd(navigations, nav => nav.ts < event.ts);\n const hasNavigated = lastShiftNavigation !== currentShiftNavigation && currentShiftNavigation !== null;\n\n // If any of the above criteria are met or if we don't have any cluster yet we should\n // start a new one.\n if (clusterDurationExceeded || maxTimeDeltaSinceLastShiftExceeded || hasNavigated || !clusters.length) {\n // The cluster starts #time should be the timestamp of the first layout shift in it.\n const clusterStartTime = event.ts;\n\n // If the last session window ended because the max delta time between shifts\n // was exceeded set the endtime to MAX_SHIFT_TIME_DELTA microseconds after the\n // last shift in the session.\n const endTimeByMaxSessionDuration = clusterDurationExceeded ? firstShiftTime + MAX_CLUSTER_DURATION : Infinity;\n\n // If the last session window ended because the max session duration was\n // surpassed, set the endtime so that the window length = MAX_CLUSTER_DURATION;\n const endTimeByMaxShiftGap = maxTimeDeltaSinceLastShiftExceeded ? lastShiftTime + MAX_SHIFT_TIME_DELTA : Infinity;\n\n // If there was a navigation during the last window, close it at the time\n // of the navigation.\n const endTimeByNavigation = hasNavigated ? navigations[currentShiftNavigation].ts : Infinity;\n\n // End the previous cluster at the time of the first of the criteria above that was met.\n const previousClusterEndTime = Math.min(endTimeByMaxSessionDuration, endTimeByMaxShiftGap, endTimeByNavigation);\n\n // If there is an existing cluster update its closing time.\n if (clusters.length > 0) {\n const currentCluster = clusters[clusters.length - 1];\n updateTraceWindowMax(currentCluster.clusterWindow, Types.Timing.MicroSeconds(previousClusterEndTime));\n }\n\n clusters.push({\n events: [],\n clusterWindow: traceWindowFromTime(clusterStartTime),\n clusterCumulativeScore: 0,\n scoreWindows: {\n good: traceWindowFromTime(clusterStartTime),\n needsImprovement: null,\n bad: null,\n },\n });\n\n firstShiftTime = clusterStartTime;\n }\n\n // Given the above we should have a cluster available, so pick the most\n // recent one and append the shift, bump its score and window values accordingly.\n const currentCluster = clusters[clusters.length - 1];\n const timeFromNavigation = currentShiftNavigation !== null ?\n Types.Timing.MicroSeconds(event.ts - navigations[currentShiftNavigation].ts) :\n undefined;\n\n currentCluster.clusterCumulativeScore += event.args.data ? event.args.data.weighted_score_delta : 0;\n if (!event.args.data) {\n continue;\n }\n const shift: Types.TraceEvents.SyntheticLayoutShift = {\n ...event,\n args: {\n frame: event.args.frame,\n data: {\n ...event.args.data,\n rawEvent: event,\n },\n },\n parsedData: {\n screenshotSource: findNextScreenshotSource(event.ts),\n timeFromNavigation,\n cumulativeWeightedScoreInWindow: currentCluster.clusterCumulativeScore,\n // The score of the session window is temporarily set to 0 just\n // to initialize it. Since we need to get the score of all shifts\n // in the session window to determine its value, its definite\n // value is set when stepping through the built clusters.\n sessionWindowData: {cumulativeWindowScore: 0, id: clusters.length},\n },\n };\n currentCluster.events.push(shift);\n updateTraceWindowMax(currentCluster.clusterWindow, event.ts);\n\n lastShiftTime = event.ts;\n lastShiftNavigation = currentShiftNavigation;\n }\n\n // Now step through each cluster and set up the times at which the value\n // goes from Good, to needs improvement, to Bad. Note that if there is a\n // large jump we may go from Good to Bad without ever creating a Needs\n // Improvement window at all.\n for (const cluster of clusters) {\n let weightedScore = 0;\n let windowID = -1;\n // If this is the last cluster update its window. The cluster duration is determined\n // by the minimum between: time to next navigation, trace end time, time to maximum\n // cluster duration and time to maximum gap between layout shifts.\n if (cluster === clusters[clusters.length - 1]) {\n const clusterEndByMaxDuration = MAX_CLUSTER_DURATION + cluster.clusterWindow.min;\n const clusterEndByMaxGap = cluster.clusterWindow.max + MAX_SHIFT_TIME_DELTA;\n const nextNavigationIndex =\n Platform.ArrayUtilities.nearestIndexFromBeginning(navigations, nav => nav.ts > cluster.clusterWindow.max);\n const nextNavigationTime = nextNavigationIndex ? navigations[nextNavigationIndex].ts : Infinity;\n const clusterEnd = Math.min(clusterEndByMaxDuration, clusterEndByMaxGap, traceBounds.max, nextNavigationTime);\n updateTraceWindowMax(cluster.clusterWindow, Types.Timing.MicroSeconds(clusterEnd));\n }\n for (const shift of cluster.events) {\n weightedScore += shift.args.data ? shift.args.data.weighted_score_delta : 0;\n windowID = shift.parsedData.sessionWindowData.id;\n const ts = shift.ts;\n // Update the the CLS score of this shift's session window now that\n // we have it.\n shift.parsedData.sessionWindowData.cumulativeWindowScore = cluster.clusterCumulativeScore;\n if (weightedScore < LayoutShiftsThreshold.NEEDS_IMPROVEMENT) {\n // Expand the Good window.\n updateTraceWindowMax(cluster.scoreWindows.good, ts);\n } else if (\n weightedScore >= LayoutShiftsThreshold.NEEDS_IMPROVEMENT && weightedScore < LayoutShiftsThreshold.BAD) {\n if (!cluster.scoreWindows.needsImprovement) {\n // Close the Good window, and open the needs improvement window.\n updateTraceWindowMax(cluster.scoreWindows.good, Types.Timing.MicroSeconds(ts - 1));\n cluster.scoreWindows.needsImprovement = traceWindowFromTime(ts);\n }\n\n // Expand the needs improvement window.\n updateTraceWindowMax(cluster.scoreWindows.needsImprovement, ts);\n } else if (weightedScore >= LayoutShiftsThreshold.BAD) {\n if (!cluster.scoreWindows.bad) {\n // We may jump from Good to Bad here, so update whichever window is open.\n if (cluster.scoreWindows.needsImprovement) {\n updateTraceWindowMax(cluster.scoreWindows.needsImprovement, Types.Timing.MicroSeconds(ts - 1));\n } else {\n updateTraceWindowMax(cluster.scoreWindows.good, Types.Timing.MicroSeconds(ts - 1));\n }\n\n cluster.scoreWindows.bad = traceWindowFromTime(shift.ts);\n }\n\n // Expand the Bad window.\n updateTraceWindowMax(cluster.scoreWindows.bad, ts);\n }\n\n // At this point the windows are set by the timestamps of the events, but the\n // next cluster begins at the timestamp of its first event. As such we now\n // need to expand the score window to the end of the cluster, and we do so\n // by using the Bad widow if it's there, or the NI window, or finally the\n // Good window.\n if (cluster.scoreWindows.bad) {\n updateTraceWindowMax(cluster.scoreWindows.bad, cluster.clusterWindow.max);\n } else if (cluster.scoreWindows.needsImprovement) {\n updateTraceWindowMax(cluster.scoreWindows.needsImprovement, cluster.clusterWindow.max);\n } else {\n updateTraceWindowMax(cluster.scoreWindows.good, cluster.clusterWindow.max);\n }\n }\n if (weightedScore > sessionMaxScore) {\n clsWindowID = windowID;\n sessionMaxScore = weightedScore;\n }\n }\n}\n\nexport function data(): LayoutShifts {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Layout Shifts Handler is not finalized');\n }\n\n return {\n clusters: [...clusters],\n sessionMaxScore: sessionMaxScore,\n clsWindowID,\n prePaintEvents: [...prePaintEvents],\n layoutInvalidationEvents: [...layoutInvalidationEvents],\n styleRecalcInvalidationEvents: [],\n scoreRecords: [...scoreRecords],\n };\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Screenshots', 'Meta'];\n}\n\nexport function stateForLayoutShiftScore(score: number): ScoreClassification {\n let state = ScoreClassification.GOOD;\n if (score >= LayoutShiftsThreshold.NEEDS_IMPROVEMENT) {\n state = ScoreClassification.OK;\n }\n\n if (score >= LayoutShiftsThreshold.BAD) {\n state = ScoreClassification.BAD;\n }\n\n return state;\n}\n\nexport interface LayoutShiftCluster {\n clusterWindow: Types.Timing.TraceWindow;\n clusterCumulativeScore: number;\n events: Types.TraceEvents.SyntheticLayoutShift[];\n // For convenience we split apart the cluster into good, NI, and bad windows.\n // Since a cluster may remain in the good window, we mark NI and bad as being\n // possibly null.\n scoreWindows: {\n good: Types.Timing.TraceWindow,\n needsImprovement: Types.Timing.TraceWindow|null,\n bad: Types.Timing.TraceWindow|null,\n };\n}\n\n// Based on https://web.dev/cls/\nexport const enum LayoutShiftsThreshold {\n GOOD = 0,\n NEEDS_IMPROVEMENT = 0.1,\n BAD = 0.25,\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * This handler stores page load metrics, including web vitals,\n * and exports them in the shape of a map with the following shape:\n * Map(FrameId -> Map(navigationID -> metrics) )\n *\n * It also exports all markers in a trace in an array.\n *\n * Some metrics are taken directly from a page load events (AKA markers) like DCL.\n * Others require processing multiple events to be determined, like CLS and TBT.\n */\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\n\nimport {type TraceEventHandlerName} from './types.js';\n\nimport * as Types from '../types/types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\n\n/**\n * This represents the metric scores for all navigations, for all frames in a trace.\n * Given a frame id, the map points to another map from navigation id to metric scores.\n * The metric scores include the event related to the metric as well as the data regarding\n * the score itself.\n */\nconst metricScoresByFrameId =\n new Map</* Frame id */ string, Map</* navigation id */ string, Map<MetricName, MetricScore>>>();\n\n/**\n * Page load events with no associated duration that happened in the\n * main frame.\n */\nlet allMarkerEvents: Types.TraceEvents.PageLoadEvent[] = [];\n\nexport function reset(): void {\n metricScoresByFrameId.clear();\n pageLoadEventsArray = [];\n allMarkerEvents = [];\n selectedLCPCandidateEvents.clear();\n}\n\nlet pageLoadEventsArray: Types.TraceEvents.PageLoadEvent[] = [];\n\n// Once we've found the LCP events in the trace we want to fetch their DOM Node\n// from the backend. We could do this by parsing through our Map of frame =>\n// navigation => metric, but it's easier to keep a set of LCP events. As we\n// parse the trace, any time we store an LCP candidate as the potential LCP\n// event, we store the event here. If we later find a new candidate in the\n// trace, we store that and delete the prior event. When we've parsed the\n// entire trace this set will contain all the LCP events that were used - e.g.\n// the candidates that were the actual LCP events.\nconst selectedLCPCandidateEvents = new Set<Types.TraceEvents.TraceEventLargestContentfulPaintCandidate>();\n\nexport const MarkerName =\n ['MarkDOMContent', 'MarkLoad', 'firstPaint', 'firstContentfulPaint', 'largestContentfulPaint::Candidate'] as const;\n\nconst markerTypeGuards = [\n Types.TraceEvents.isTraceEventMarkDOMContent,\n Types.TraceEvents.isTraceEventMarkLoad,\n Types.TraceEvents.isTraceEventFirstPaint,\n Types.TraceEvents.isTraceEventFirstContentfulPaint,\n Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate,\n Types.TraceEvents.isTraceEventNavigationStart,\n];\n\ninterface MakerEvent extends Types.TraceEvents.TraceEventData {\n name: typeof MarkerName[number];\n}\n\nexport function isTraceEventMarkerEvent(event: Types.TraceEvents.TraceEventData): event is MakerEvent {\n return markerTypeGuards.some(fn => fn(event));\n}\n\nconst pageLoadEventTypeGuards = [\n ...markerTypeGuards,\n Types.TraceEvents.isTraceEventInteractiveTime,\n];\n\nexport function eventIsPageLoadEvent(event: Types.TraceEvents.TraceEventData):\n event is Types.TraceEvents.PageLoadEvent {\n return pageLoadEventTypeGuards.some(fn => fn(event));\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (!eventIsPageLoadEvent(event)) {\n return;\n }\n pageLoadEventsArray.push(event);\n}\n\nfunction storePageLoadMetricAgainstNavigationId(\n navigation: Types.TraceEvents.TraceEventNavigationStart, event: Types.TraceEvents.PageLoadEvent): void {\n const navigationId = navigation.args.data?.navigationId;\n if (!navigationId) {\n throw new Error('Navigation event unexpectedly had no navigation ID.');\n }\n const frameId = getFrameIdForPageLoadEvent(event);\n const {rendererProcessesByFrame} = metaHandlerData();\n\n // If either of these pieces of data do not exist, the most likely\n // explanation is that the page load metric we found is for a frame/process\n // combo that the MetaHandler discarded. This typically happens if we get a\n // navigation event with an empty URL. Therefore, we will silently return and\n // drop this metric. If we didn't care about the navigation, we certainly do\n // not need to care about metrics for that navigation.\n const rendererProcessesInFrame = rendererProcessesByFrame.get(frameId);\n if (!rendererProcessesInFrame) {\n return;\n }\n const processData = rendererProcessesInFrame.get(event.pid);\n if (!processData) {\n return;\n }\n\n if (Types.TraceEvents.isTraceEventNavigationStart(event)) {\n return;\n }\n\n if (Types.TraceEvents.isTraceEventFirstContentfulPaint(event)) {\n const fcpTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const score = Helpers.Timing.formatMicrosecondsTime(fcpTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const classification = scoreClassificationForFirstContentfulPaint(fcpTime);\n const metricScore = {event, score, metricName: MetricName.FCP, classification, navigation};\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventFirstPaint(event)) {\n const paintTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const score = Helpers.Timing.formatMicrosecondsTime(paintTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const classification = ScoreClassification.UNCLASSIFIED;\n const metricScore = {event, score, metricName: MetricName.FP, classification, navigation};\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventMarkDOMContent(event)) {\n const dclTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const score = Helpers.Timing.formatMicrosecondsTime(dclTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const metricScore = {\n event,\n score,\n metricName: MetricName.DCL,\n classification: scoreClassificationForDOMContentLoaded(dclTime),\n navigation,\n };\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventInteractiveTime(event)) {\n const ttiValue = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const ttiScore = Helpers.Timing.formatMicrosecondsTime(ttiValue, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const tti = {\n event,\n score: ttiScore,\n metricName: MetricName.TTI,\n classification: scoreClassificationForTimeToInteractive(ttiValue),\n navigation,\n };\n storeMetricScore(frameId, navigationId, tti);\n\n const tbtValue =\n Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(event.args.args.total_blocking_time_ms));\n const tbtScore = Helpers.Timing.formatMicrosecondsTime(tbtValue, {\n format: Types.Timing.TimeUnit.MILLISECONDS,\n maximumFractionDigits: 2,\n });\n const tbt = {\n event,\n score: tbtScore,\n metricName: MetricName.TBT,\n classification: scoreClassificationForTotalBlockingTime(tbtValue),\n navigation,\n };\n storeMetricScore(frameId, navigationId, tbt);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventMarkLoad(event)) {\n const loadTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const score = Helpers.Timing.formatMicrosecondsTime(loadTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const metricScore = {\n event,\n score,\n metricName: MetricName.L,\n classification: ScoreClassification.UNCLASSIFIED,\n navigation,\n };\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(event)) {\n const candidateIndex = event.args.data?.candidateIndex;\n if (!candidateIndex) {\n throw new Error('Largest Contenful Paint unexpectedly had no candidateIndex.');\n }\n const lcpTime = Types.Timing.MicroSeconds(event.ts - navigation.ts);\n const lcpScore = Helpers.Timing.formatMicrosecondsTime(lcpTime, {\n format: Types.Timing.TimeUnit.SECONDS,\n maximumFractionDigits: 2,\n });\n const lcp = {\n event,\n score: lcpScore,\n metricName: MetricName.LCP,\n classification: scoreClassificationForLargestContentfulPaint(lcpTime),\n navigation,\n };\n const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());\n const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());\n const lastLCPCandidate = metrics.get(MetricName.LCP);\n if (lastLCPCandidate === undefined) {\n selectedLCPCandidateEvents.add(lcp.event);\n storeMetricScore(frameId, navigationId, lcp);\n return;\n }\n const lastLCPCandidateEvent = lastLCPCandidate.event;\n\n if (!Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {\n return;\n }\n const lastCandidateIndex = lastLCPCandidateEvent.args.data?.candidateIndex;\n if (!lastCandidateIndex) {\n // lastCandidateIndex cannot be undefined because we don't store candidates with\n // with an undefined candidateIndex value. This check is only to make TypeScript\n // treat the field as not undefined below.\n return;\n }\n if (lastCandidateIndex < candidateIndex) {\n selectedLCPCandidateEvents.delete(lastLCPCandidateEvent);\n selectedLCPCandidateEvents.add(lcp.event);\n storeMetricScore(frameId, navigationId, lcp);\n }\n return;\n }\n if (Types.TraceEvents.isTraceEventLayoutShift(event)) {\n return;\n }\n return Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\nfunction storeMetricScore(frameId: string, navigationId: string, metricScore: MetricScore): void {\n const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());\n const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());\n // If an entry with that metric name is present, delete it so that the new entry that\n // will replace it is added at the end of the map. This way we guarantee the map entries\n // are ordered in ASC manner by timestamp.\n metrics.delete(metricScore.metricName);\n metrics.set(metricScore.metricName, metricScore);\n}\n\nexport function getFrameIdForPageLoadEvent(event: Types.TraceEvents.PageLoadEvent): string {\n if (Types.TraceEvents.isTraceEventFirstContentfulPaint(event) ||\n Types.TraceEvents.isTraceEventInteractiveTime(event) ||\n Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(event) ||\n Types.TraceEvents.isTraceEventNavigationStart(event) || Types.TraceEvents.isTraceEventLayoutShift(event) ||\n Types.TraceEvents.isTraceEventFirstPaint(event)) {\n return event.args.frame;\n }\n if (Types.TraceEvents.isTraceEventMarkDOMContent(event) || Types.TraceEvents.isTraceEventMarkLoad(event)) {\n const frameId = event.args.data?.frame;\n if (!frameId) {\n throw new Error('MarkDOMContent unexpectedly had no frame ID.');\n }\n return frameId;\n }\n Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\nfunction getNavigationForPageLoadEvent(event: Types.TraceEvents.PageLoadEvent):\n Types.TraceEvents.TraceEventNavigationStart|null {\n if (Types.TraceEvents.isTraceEventFirstContentfulPaint(event) ||\n Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(event) ||\n Types.TraceEvents.isTraceEventFirstPaint(event)) {\n const navigationId = event.args.data?.navigationId;\n if (!navigationId) {\n throw new Error('Trace event unexpectedly had no navigation ID.');\n }\n const {navigationsByNavigationId} = metaHandlerData();\n const navigation = navigationsByNavigationId.get(navigationId);\n\n if (!navigation) {\n // This event's navigation has been filtered out by the meta handler as a noise event.\n return null;\n }\n return navigation;\n }\n\n if (Types.TraceEvents.isTraceEventMarkDOMContent(event) || Types.TraceEvents.isTraceEventInteractiveTime(event) ||\n Types.TraceEvents.isTraceEventLayoutShift(event) || Types.TraceEvents.isTraceEventMarkLoad(event)) {\n const frameId = getFrameIdForPageLoadEvent(event);\n const {navigationsByFrameId} = metaHandlerData();\n return Helpers.Trace.getNavigationForTraceEvent(event, frameId, navigationsByFrameId);\n }\n\n if (Types.TraceEvents.isTraceEventNavigationStart(event)) {\n // We don't want to compute metrics of the navigation relative to itself, so we'll avoid avoid all that.\n return null;\n }\n\n return Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/fcp/\n */\nexport function scoreClassificationForFirstContentfulPaint(fcpScoreInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n const FCP_GOOD_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(1.8));\n const FCP_MEDIUM_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(3.0));\n let scoreClassification = ScoreClassification.BAD;\n if (fcpScoreInMicroseconds <= FCP_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (fcpScoreInMicroseconds <= FCP_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/interactive/#how-lighthouse-determines-your-tti-score\n */\n\nexport function scoreClassificationForTimeToInteractive(ttiTimeInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n const TTI_GOOD_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(3.8));\n const TTI_MEDIUM_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(7.3));\n let scoreClassification = ScoreClassification.BAD;\n if (ttiTimeInMicroseconds <= TTI_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (ttiTimeInMicroseconds <= TTI_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/lcp/#what-is-lcp\n */\n\nexport function scoreClassificationForLargestContentfulPaint(lcpTimeInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n const LCP_GOOD_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(2.5));\n const LCP_MEDIUM_TIMING = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(4));\n let scoreClassification = ScoreClassification.BAD;\n if (lcpTimeInMicroseconds <= LCP_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (lcpTimeInMicroseconds <= LCP_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * DCL does not have a classification.\n */\nexport function scoreClassificationForDOMContentLoaded(_dclTimeInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n return ScoreClassification.UNCLASSIFIED;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/lighthouse-total-blocking-#time/\n */\n\nexport function scoreClassificationForTotalBlockingTime(tbtTimeInMicroseconds: Types.Timing.MicroSeconds):\n ScoreClassification {\n const TBT_GOOD_TIMING = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(200));\n const TBT_MEDIUM_TIMING = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(600));\n let scoreClassification = ScoreClassification.BAD;\n if (tbtTimeInMicroseconds <= TBT_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (tbtTimeInMicroseconds <= TBT_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Gets all the Largest Contentful Paint scores of all the frames in the\n * trace.\n */\nfunction gatherFinalLCPEvents(): Types.TraceEvents.PageLoadEvent[] {\n const allFinalLCPEvents: Types.TraceEvents.PageLoadEvent[] = [];\n const dataForAllFrames = [...metricScoresByFrameId.values()];\n const dataForAllNavigations = dataForAllFrames.flatMap(frameData => [...frameData.values()]);\n for (let i = 0; i < dataForAllNavigations.length; i++) {\n const navigationData = dataForAllNavigations[i];\n const lcpInNavigation = navigationData.get(MetricName.LCP);\n if (!lcpInNavigation || !lcpInNavigation.event) {\n continue;\n }\n\n allFinalLCPEvents.push(lcpInNavigation.event);\n }\n return allFinalLCPEvents;\n}\n\nexport async function finalize(): Promise<void> {\n pageLoadEventsArray.sort((a, b) => a.ts - b.ts);\n\n for (const pageLoadEvent of pageLoadEventsArray) {\n const navigation = getNavigationForPageLoadEvent(pageLoadEvent);\n if (navigation) {\n // Event's navigation was not filtered out as noise.\n storePageLoadMetricAgainstNavigationId(navigation, pageLoadEvent);\n }\n }\n // NOTE: if you are looking for the TBT calculation, it has temporarily been\n // removed. See crbug.com/1424335 for details.\n const allFinalLCPEvents = gatherFinalLCPEvents();\n const mainFrame = metaHandlerData().mainFrameId;\n // Filter out LCP candidates to use only definitive LCP values\n const allEventsButLCP =\n pageLoadEventsArray.filter(event => !Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(event));\n const markerEvents = [...allFinalLCPEvents, ...allEventsButLCP].filter(isTraceEventMarkerEvent);\n // Filter by main frame and sort.\n allMarkerEvents =\n markerEvents.filter(event => getFrameIdForPageLoadEvent(event) === mainFrame).sort((a, b) => a.ts - b.ts);\n}\n\nexport type PageLoadMetricsData = {\n metricScoresByFrameId: Map<string, Map<string, Map<MetricName, MetricScore>>>,\n allMarkerEvents: Types.TraceEvents.PageLoadEvent[],\n};\n\nexport function data(): PageLoadMetricsData {\n return {\n /**\n * This represents the metric scores for all navigations, for all frames in a trace.\n * Given a frame id, the map points to another map from navigation id to metric scores.\n * The metric scores include the event related to the metric as well as the data regarding\n * the score itself.\n */\n metricScoresByFrameId: new Map(metricScoresByFrameId),\n\n /**\n * Page load events with no associated duration that happened in the\n * main frame.\n */\n allMarkerEvents: [...allMarkerEvents],\n };\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta'];\n}\n\nexport const enum ScoreClassification {\n GOOD = 'good',\n OK = 'ok',\n BAD = 'bad',\n // Some metrics (such as DOMContentLoaded) don't have a Good/OK/Bad classification, hence this additional entry.\n UNCLASSIFIED = 'unclassified',\n}\n\nexport const enum MetricName {\n // First Contentful Paint\n FCP = 'FCP',\n // First Paint\n FP = 'FP',\n // MarkLoad\n L = 'L',\n LCP = 'LCP',\n // Mark DOM Content\n DCL = 'DCL',\n // Time To Interactive\n TTI = 'TTI',\n // Total Blocking Time\n TBT = 'TBT',\n // Cumulative Layout Shift\n CLS = 'CLS',\n}\n\nexport interface MetricScore {\n score: string;\n metricName: MetricName;\n classification: ScoreClassification;\n event?: Types.TraceEvents.PageLoadEvent;\n // The last navigation that occured before this metric score.\n navigation?: Types.TraceEvents.TraceEventNavigationStart;\n estimated?: boolean;\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport {type TraceEventHandlerName} from './types.js';\n\n// Each thread contains events. Events indicate the thread and process IDs, which are\n// used to store the event in the correct process thread entry below.\nconst eventsInProcessThread =\n new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventSnapshot[]>>();\n\nlet snapshots: Types.TraceEvents.TraceEventSnapshot[] = [];\nexport function reset(): void {\n eventsInProcessThread.clear();\n snapshots.length = 0;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (event.name !== 'Screenshot') {\n return;\n }\n\n Helpers.Trace.addEventToProcessThread(event, eventsInProcessThread);\n}\n\nexport async function finalize(): Promise<void> {\n const {browserProcessId, browserThreadId} = metaHandlerData();\n const browserThreads = eventsInProcessThread.get(browserProcessId);\n if (browserThreads) {\n snapshots = browserThreads.get(browserThreadId) || [];\n }\n}\n\nexport function data(): Types.TraceEvents.TraceEventSnapshot[] {\n return [...snapshots];\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta'];\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Types from '../types/types.js';\n\nexport interface MemoryData {\n updateCountersByProcess: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventUpdateCounters[]>;\n}\n\nconst updateCountersByProcess: MemoryData['updateCountersByProcess'] = new Map();\n\nexport function reset(): void {\n updateCountersByProcess.clear();\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (Types.TraceEvents.isTraceEventUpdateCounters(event)) {\n const countersForProcess = Platform.MapUtilities.getWithDefault(updateCountersByProcess, event.pid, () => []);\n countersForProcess.push(event);\n updateCountersByProcess.set(event.pid, countersForProcess);\n }\n}\n\nexport function data(): MemoryData {\n return {updateCountersByProcess: new Map(updateCountersByProcess)};\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport {type TraceEventHandlerName, HandlerState} from './types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport * as Helpers from '../helpers/helpers.js';\n\nimport * as Types from '../types/types.js';\n\nconst MILLISECONDS_TO_MICROSECONDS = 1000;\nconst SECONDS_TO_MICROSECONDS = 1000000;\n\n// Network requests from traces are actually formed of 5 trace records.\n// This handler tracks all trace records based on the request ID, and\n// then creates a new synthetic trace event for those network requests.\n//\n// This interface, then, defines the shape of the object we intend to\n// keep for each request in the trace. In the finalize we will convert\n// these 5 types of trace records to a synthetic complete event that\n// represents a composite of these trace records.\ninterface TraceEventsForNetworkRequest {\n changePriority?: Types.TraceEvents.TraceEventResourceChangePriority;\n willSendRequests?: Types.TraceEvents.TraceEventResourceWillSendRequest[];\n sendRequests?: Types.TraceEvents.TraceEventResourceSendRequest[];\n receiveResponse?: Types.TraceEvents.TraceEventResourceReceiveResponse;\n resourceFinish?: Types.TraceEvents.TraceEventResourceFinish;\n receivedData?: Types.TraceEvents.TraceEventResourceReceivedData[];\n resourceMarkAsCached?: Types.TraceEvents.TraceEventResourceMarkAsCached;\n}\n\ninterface NetworkRequestData {\n byOrigin: Map<string, {\n renderBlocking: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n nonRenderBlocking: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n all: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n }>;\n byTime: Types.TraceEvents.TraceEventSyntheticNetworkRequest[];\n}\n\nconst requestMap = new Map<string, TraceEventsForNetworkRequest>();\nconst requestsByOrigin = new Map<string, {\n renderBlocking: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n nonRenderBlocking: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n all: Types.TraceEvents.TraceEventSyntheticNetworkRequest[],\n}>();\nconst requestsByTime: Types.TraceEvents.TraceEventSyntheticNetworkRequest[] = [];\n\nfunction storeTraceEventWithRequestId<K extends keyof TraceEventsForNetworkRequest>(\n requestId: string, key: K, value: TraceEventsForNetworkRequest[K]): void {\n if (!requestMap.has(requestId)) {\n requestMap.set(requestId, {});\n }\n\n const traceEvents = requestMap.get(requestId);\n if (!traceEvents) {\n throw new Error(`Unable to locate trace events for request ID ${requestId}`);\n }\n\n if (Array.isArray(traceEvents[key])) {\n const target = traceEvents[key] as Types.TraceEvents.TraceEventData[];\n const values = value as Types.TraceEvents.TraceEventData[];\n target.push(...values);\n } else {\n traceEvents[key] = value;\n }\n}\n\nfunction firstPositiveValueInList(entries: number[]): number {\n for (const entry of entries) {\n if (entry > 0) {\n return entry;\n }\n }\n\n // In the event we don't find a positive value, we return 0 so as to\n // be a mathematical noop. It's typically not correct to return \u2013 say \u2013\n // a -1 here because it would affect the calculation of stats below.\n return 0;\n}\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function reset(): void {\n requestsByOrigin.clear();\n requestMap.clear();\n requestsByTime.length = 0;\n\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Network Request handler is not initialized');\n }\n\n if (Types.TraceEvents.isTraceEventResourceChangePriority(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'changePriority', event);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceWillSendRequest(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'willSendRequests', [event]);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceSendRequest(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'sendRequests', [event]);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceReceiveResponse(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'receiveResponse', event);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceReceivedData(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'receivedData', [event]);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceFinish(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'resourceFinish', event);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventResourceMarkAsCached(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'resourceMarkAsCached', event);\n return;\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Network Request handler is not initialized');\n }\n\n const {rendererProcessesByFrame} = metaHandlerData();\n for (const [requestId, request] of requestMap.entries()) {\n // If we have an incomplete set of events here, we choose to drop the network\n // request rather than attempt to synthesize the missing data.\n if (!request.sendRequests || !request.receiveResponse) {\n continue;\n }\n\n // In the data we may get multiple willSendRequests and sendRequests, which\n // will indicate that there are redirects for a given (sub)resource. In the\n // case of a navigation, e.g., example.com/ we will get willSendRequests,\n // and we should use these to calculate time spent in redirects.\n // In the case of sub-resources, however, e.g., example.com/foo.js we will\n // *only* get sendRequests, and we use these instead of willSendRequests\n // to detect the time in redirects. We always use the sendRequest for the\n // url, priority etc since it contains those values, but we use the\n // willSendRequest (if it exists) to calculate the timestamp and durations\n // of redirects.\n const redirects: Types.TraceEvents.TraceEventSyntheticNetworkRedirect[] = [];\n for (let i = 0; i < request.sendRequests.length - 1; i++) {\n const sendRequest = request.sendRequests[i];\n const nextSendRequest = request.sendRequests[i + 1];\n\n // Use the willSendRequests as the source for redirects if possible.\n // We default to those of the sendRequests, however, since willSendRequest\n // is not guaranteed to be present in the data for every request.\n let ts = sendRequest.ts;\n let dur = Types.Timing.MicroSeconds(nextSendRequest.ts - sendRequest.ts);\n if (request.willSendRequests && request.willSendRequests[i] && request.willSendRequests[i + 1]) {\n const willSendRequest = request.willSendRequests[i];\n const nextWillSendRequest = request.willSendRequests[i + 1];\n ts = willSendRequest.ts;\n dur = Types.Timing.MicroSeconds(nextWillSendRequest.ts - willSendRequest.ts);\n }\n\n redirects.push({\n url: sendRequest.args.data.url,\n priority: sendRequest.args.data.priority,\n requestMethod: sendRequest.args.data.requestMethod,\n ts,\n dur,\n });\n }\n\n // If a ResourceFinish event with an encoded data length is received,\n // then the resource was not cached; it was fetched before it was\n // requested, e.g. because it was pushed in this navigation.\n const isPushedResource = request.resourceFinish?.args.data.encodedDataLength !== 0;\n // This works around crbug.com/998397, which reports pushed resources, and resources served by a service worker as disk cached.\n const isDiskCached = request.receiveResponse.args.data.fromCache &&\n !request.receiveResponse.args.data.fromServiceWorker && !isPushedResource;\n // If the request contains a resourceMarkAsCached event, it was served from memory cache.\n const isMemoryCached = request.resourceMarkAsCached !== undefined;\n\n // The timing data returned is from the original (uncached) request, which\n // means that if we leave the above network record data as-is when the\n // request came from either the disk cache or memory cache, our calculations\n // will be incorrect.\n //\n // Here we add a flag so when we calculate the timestamps of the various\n // events, we can overwrite them.\n // These timestamps may not be perfect (indeed they don't always match\n // the Network CDP domain exactly, which is likely an artifact of the way\n // the data is routed on the backend), but they're the closest we have.\n const isCached = isMemoryCached || isDiskCached;\n\n const timing = request.receiveResponse.args.data.timing;\n // If a non-cached request has no |timing| indicates data URLs, we ignore it.\n if (!timing && !isCached) {\n continue;\n }\n\n const firstSendRequest = request.sendRequests[0];\n const finalSendRequest = request.sendRequests[request.sendRequests.length - 1];\n\n const initialPriority = finalSendRequest.args.data.priority;\n let finalPriority = initialPriority;\n if (request.changePriority) {\n finalPriority = request.changePriority.args.data.priority;\n }\n\n // Start time\n // =======================\n // The time where the request started, which is either the first willSendRequest\n // event if there is one, or, if there is not, the sendRequest.\n const startTime = (request.willSendRequests && request.willSendRequests.length) ?\n Types.Timing.MicroSeconds(request.willSendRequests[0].ts) :\n Types.Timing.MicroSeconds(firstSendRequest.ts);\n\n // End redirect time\n // =======================\n // It's possible that when we start requesting data we will receive redirections.\n // Here we note the time of the *last* willSendRequest / sendRequest event,\n // which is used later on in the calculations for time queueing etc.\n const endRedirectTime = (request.willSendRequests && request.willSendRequests.length) ?\n Types.Timing.MicroSeconds(request.willSendRequests[request.willSendRequests.length - 1].ts) :\n Types.Timing.MicroSeconds(finalSendRequest.ts);\n\n // Finish time and end time\n // =======================\n // The finish time and the end time are subtly different.\n // - Finish time: records the point at which the network stack stopped receiving the data\n // - End time: the timestamp of the finish event itself (if one exists)\n //\n // The end time, then, will be slightly after the finish time.\n const endTime = request.resourceFinish ? request.resourceFinish.ts : endRedirectTime;\n const finishTime = request.resourceFinish?.args.data.finishTime ?\n Types.Timing.MicroSeconds(request.resourceFinish.args.data.finishTime * SECONDS_TO_MICROSECONDS) :\n Types.Timing.MicroSeconds(endTime);\n\n // Network duration\n // =======================\n // Time spent on the network.\n const networkDuration = isCached ? Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((finishTime || endRedirectTime) - endRedirectTime);\n\n // Processing duration\n // =======================\n // Time spent from start to end.\n const processingDuration = Types.Timing.MicroSeconds(endTime - (finishTime || endTime));\n\n // Redirection duration\n // =======================\n // Time between the first willSendRequest / sendRequest and last. This we place in *front* of the\n // queueing, since the queueing time that we know about from the trace data is only the last request,\n // i.e., the one that occurs after all the redirects.\n const redirectionDuration = Types.Timing.MicroSeconds(endRedirectTime - startTime);\n\n // Queueing\n // =======================\n // The amount of time queueing is the time between the request's start time to the requestTime\n // arg recorded in the receiveResponse event. In the cases where the recorded start time is larger\n // that the requestTime we set queueing time to zero.\n const queueing = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds(Platform.NumberUtilities.clamp(\n (timing.requestTime * SECONDS_TO_MICROSECONDS - endRedirectTime), 0, Number.MAX_VALUE));\n\n // Stalled\n // =======================\n // If the request is cached, the amount of time stalled is the time between the start time and\n // receiving a response.\n // Otherwise it is whichever positive number comes first from the following timing info:\n // DNS start, Connection start, Send Start, or the time duration between our start time and\n // receiving a response.\n const stalled = isCached ? Types.Timing.MicroSeconds(request.receiveResponse.ts - startTime) :\n Types.Timing.MicroSeconds(firstPositiveValueInList([\n timing.dnsStart * MILLISECONDS_TO_MICROSECONDS,\n timing.connectStart * MILLISECONDS_TO_MICROSECONDS,\n timing.sendStart * MILLISECONDS_TO_MICROSECONDS,\n (request.receiveResponse.ts - endRedirectTime),\n ]));\n\n // Sending HTTP request\n // =======================\n // Time when the HTTP request is sent.\n const sendStartTime = isCached ?\n startTime :\n Types.Timing.MicroSeconds(\n timing.requestTime * SECONDS_TO_MICROSECONDS + timing.sendStart * MILLISECONDS_TO_MICROSECONDS);\n\n // Waiting\n // =======================\n // Time from when the send finished going to when the headers were received.\n const waiting = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.receiveHeadersEnd - timing.sendEnd) * MILLISECONDS_TO_MICROSECONDS);\n\n // Download\n // =======================\n // Time from receipt of headers to the finish time.\n const downloadStart = isCached ?\n startTime :\n Types.Timing.MicroSeconds(\n timing.requestTime * SECONDS_TO_MICROSECONDS + timing.receiveHeadersEnd * MILLISECONDS_TO_MICROSECONDS);\n const download = isCached ? Types.Timing.MicroSeconds(endTime - request.receiveResponse.ts) :\n Types.Timing.MicroSeconds(((finishTime || downloadStart) - downloadStart));\n\n const totalTime = Types.Timing.MicroSeconds(networkDuration + processingDuration);\n\n // Collect a few values from the timing info.\n // If the Network request is cached, we zero out them.\n const dnsLookup = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.dnsEnd - timing.dnsStart) * MILLISECONDS_TO_MICROSECONDS);\n const ssl = isCached ? Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.sslEnd - timing.sslStart) * MILLISECONDS_TO_MICROSECONDS);\n const proxyNegotiation = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.proxyEnd - timing.proxyStart) * MILLISECONDS_TO_MICROSECONDS);\n const requestSent = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.sendEnd - timing.sendStart) * MILLISECONDS_TO_MICROSECONDS);\n const initialConnection = isCached ?\n Types.Timing.MicroSeconds(0) :\n Types.Timing.MicroSeconds((timing.connectEnd - timing.connectStart) * MILLISECONDS_TO_MICROSECONDS);\n\n // Finally get some of the general data from the trace events.\n const {frame, url, renderBlocking} = finalSendRequest.args.data;\n const {encodedDataLength, decodedBodyLength} =\n request.resourceFinish ? request.resourceFinish.args.data : {encodedDataLength: 0, decodedBodyLength: 0};\n const {host, protocol, pathname, search} = new URL(url);\n const isHttps = protocol === 'https:';\n const requestingFrameUrl =\n Helpers.Trace.activeURLForFrameAtTime(frame, finalSendRequest.ts, rendererProcessesByFrame) || '';\n\n // Construct a synthetic trace event for this network request.\n const networkEvent: Types.TraceEvents.TraceEventSyntheticNetworkRequest = {\n args: {\n data: {\n // All data we create from trace events should be added to |syntheticData|.\n syntheticData: {\n dnsLookup,\n download,\n downloadStart,\n finishTime,\n initialConnection,\n isDiskCached,\n isHttps,\n isMemoryCached,\n isPushedResource,\n networkDuration,\n processingDuration,\n proxyNegotiation,\n queueing,\n redirectionDuration,\n requestSent,\n sendStartTime,\n ssl,\n stalled,\n totalTime,\n waiting,\n },\n // All fields below are from TraceEventsForNetworkRequest.\n decodedBodyLength,\n encodedDataLength,\n frame,\n fromServiceWorker: request.receiveResponse.args.data.fromServiceWorker,\n host,\n mimeType: request.receiveResponse.args.data.mimeType,\n pathname,\n priority: finalPriority,\n initialPriority,\n protocol,\n redirects,\n // In the event the property isn't set, assume non-blocking.\n renderBlocking: renderBlocking ? renderBlocking : 'non_blocking',\n requestId,\n requestingFrameUrl,\n requestMethod: finalSendRequest.args.data.requestMethod,\n search,\n statusCode: request.receiveResponse.args.data.statusCode,\n stackTrace: finalSendRequest.args.data.stackTrace,\n timing,\n url,\n },\n },\n cat: 'loading',\n name: 'SyntheticNetworkRequest',\n ph: Types.TraceEvents.Phase.COMPLETE,\n dur: Types.Timing.MicroSeconds(endTime - startTime),\n tdur: Types.Timing.MicroSeconds(endTime - startTime),\n ts: Types.Timing.MicroSeconds(startTime),\n tts: Types.Timing.MicroSeconds(startTime),\n pid: finalSendRequest.pid,\n tid: finalSendRequest.tid,\n };\n\n const requests = Platform.MapUtilities.getWithDefault(requestsByOrigin, host, () => {\n return {\n renderBlocking: [],\n nonRenderBlocking: [],\n all: [],\n };\n });\n\n // For ease of rendering we sometimes want to differentiate between\n // render-blocking and non-render-blocking, so we divide the data here.\n if (networkEvent.args.data.renderBlocking === 'non_blocking') {\n requests.nonRenderBlocking.push(networkEvent);\n } else {\n requests.renderBlocking.push(networkEvent);\n }\n\n // However, there are also times where we just want to loop through all\n // the captured requests, so here we store all of them together.\n requests.all.push(networkEvent);\n requestsByTime.push(networkEvent);\n }\n\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): NetworkRequestData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Network Request handler is not finalized');\n }\n\n return {\n byOrigin: new Map(requestsByOrigin),\n byTime: [...requestsByTime],\n };\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta'];\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\n// This handler serves two purposes. It generates a list of events that are\n// used to show user clicks in the timeline. It is also used to gather\n// EventTimings into Interactions, which we use to show interactions and\n// highlight long interactions to the user, along with INP.\n\n// We don't need to know which process / thread these events occurred in,\n// because they are effectively global, so we just track all that we find.\nconst allEvents: Types.TraceEvents.TraceEventEventTiming[] = [];\n\nexport const LONG_INTERACTION_THRESHOLD = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(200));\n\nexport interface UserInteractionsData {\n /** All the user events we found in the trace */\n allEvents: readonly Types.TraceEvents.TraceEventEventTiming[];\n /** All the interaction events we found in the trace that had an\n * interactionId and a duration > 0\n **/\n interactionEvents: readonly Types.TraceEvents.SyntheticInteractionEvent[];\n /** If the user rapidly generates interaction events (think typing into a\n * text box), in the UI we only really want to show the user the longest\n * interaction in that set.\n * For example picture interactions like this:\n * ===[interaction A]==========\n * =[interaction B]======\n * =[interaction C]=\n *\n * These events all end at the same time, and so in this instance we only want\n * to show the first interaction A on the timeline, as that is the longest one\n * and the one the developer should be focusing on. So this array of events is\n * all the interaction events filtered down, removing any nested interactions\n * entirely.\n **/\n interactionEventsWithNoNesting: readonly Types.TraceEvents.SyntheticInteractionEvent[];\n // The longest duration interaction event. Can be null if the trace has no interaction events.\n longestInteractionEvent: Readonly<Types.TraceEvents.SyntheticInteractionEvent>|null;\n // All interactions that went over the interaction threshold (200ms, see https://web.dev/inp/)\n interactionsOverThreshold: Readonly<Set<Types.TraceEvents.SyntheticInteractionEvent>>;\n}\n\nlet longestInteractionEvent: Types.TraceEvents.SyntheticInteractionEvent|null = null;\n\nconst interactionEvents: Types.TraceEvents.SyntheticInteractionEvent[] = [];\nconst interactionEventsWithNoNesting: Types.TraceEvents.SyntheticInteractionEvent[] = [];\nconst eventTimingEndEventsById = new Map<string, Types.TraceEvents.TraceEventEventTimingEnd>();\nconst eventTimingStartEventsForInteractions: Types.TraceEvents.TraceEventEventTimingBegin[] = [];\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function reset(): void {\n allEvents.length = 0;\n interactionEvents.length = 0;\n eventTimingStartEventsForInteractions.length = 0;\n eventTimingEndEventsById.clear();\n interactionEventsWithNoNesting.length = 0;\n longestInteractionEvent = null;\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Handler is not initialized');\n }\n\n if (!Types.TraceEvents.isTraceEventEventTiming(event)) {\n return;\n }\n\n if (Types.TraceEvents.isTraceEventEventTimingEnd(event)) {\n // Store the end event; for each start event that is an interaction, we need the matching end event to calculate the duration correctly.\n eventTimingEndEventsById.set(event.id, event);\n }\n\n allEvents.push(event);\n\n // From this point on we want to find events that represent interactions.\n // These events are always start events - those are the ones that contain all\n // the metadata about the interaction.\n if (!event.args.data || !Types.TraceEvents.isTraceEventEventTimingStart(event)) {\n return;\n }\n const {duration, interactionId} = event.args.data;\n // We exclude events for the sake of interactions if:\n // 1. They have no duration.\n // 2. They have no interactionId\n // 3. They have an interactionId of 0: this indicates that it's not an\n // interaction that we care about because it hasn't had its own interactionId\n // set (0 is the default on the backend).\n // See: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/timing/responsiveness_metrics.cc;l=133;drc=40c209a9c365ebb9f16fb99dfe78c7fe768b9594\n\n if (duration < 1 || interactionId === undefined || interactionId === 0) {\n return;\n }\n\n // Store the start event. In the finalize() function we will pair this with\n // its end event and create the synthetic interaction event.\n eventTimingStartEventsForInteractions.push(event);\n}\n\n/**\n * See https://web.dev/better-responsiveness-metric/#interaction-types for the\n * table that defines these sets.\n **/\nconst pointerEventTypes = new Set([\n 'pointerdown',\n 'touchstart',\n 'pointerup',\n 'touchend',\n 'mousedown',\n 'mouseup',\n 'click',\n]);\n\nconst keyboardEventTypes = new Set([\n 'keydown',\n 'keypress',\n 'keyup',\n]);\n\nexport type InteractionCategory = 'KEYBOARD'|'POINTER'|'OTHER';\nexport function categoryOfInteraction(interaction: Types.TraceEvents.SyntheticInteractionEvent): InteractionCategory {\n if (pointerEventTypes.has(interaction.type)) {\n return 'POINTER';\n }\n if (keyboardEventTypes.has(interaction.type)) {\n return 'KEYBOARD';\n }\n\n return 'OTHER';\n}\n\n/**\n * We define a set of interactions as nested where:\n * 1. Their end times align.\n * 2. The longest interaction's start time is earlier than all other\n * interactions with the same end time.\n * 3. The interactions are of the same category [each interaction is either\n * categorised as keyboard, or pointer.]\n *\n * =============A=[pointerup]=\n * ====B=[pointerdown]=\n * ===C=[pointerdown]==\n * ===D=[pointerup]===\n *\n * In this example, B, C and D are all nested and therefore should not be\n * returned from this function.\n *\n * However, in this example we would only consider B nested (under A) and D\n * nested (under C). A and C both stay because they are of different types.\n * ========A=[keydown]====\n * =======B=[keyup]=====\n * ====C=[pointerdown]=\n * =D=[pointerup]=\n **/\nexport function removeNestedInteractions(interactions: readonly Types.TraceEvents.SyntheticInteractionEvent[]):\n readonly Types.TraceEvents.SyntheticInteractionEvent[] {\n /**\n * Because we nest events only that are in the same category, we store the\n * longest event for a given end time by category.\n **/\n const earliestEventForEndTimePerCategory:\n Record<InteractionCategory, Map<Types.Timing.MicroSeconds, Types.TraceEvents.SyntheticInteractionEvent>> = {\n POINTER: new Map(),\n KEYBOARD: new Map(),\n OTHER: new Map(),\n };\n\n function storeEventIfEarliestForCategoryAndEndTime(interaction: Types.TraceEvents.SyntheticInteractionEvent): void {\n const category = categoryOfInteraction(interaction);\n const mapToUse = earliestEventForEndTimePerCategory[category];\n const endTime = Types.Timing.MicroSeconds(interaction.ts + interaction.dur);\n\n const earliestCurrentEvent = mapToUse.get(endTime);\n if (!earliestCurrentEvent) {\n mapToUse.set(endTime, interaction);\n return;\n }\n if (interaction.ts < earliestCurrentEvent.ts) {\n mapToUse.set(endTime, interaction);\n }\n }\n\n for (const interaction of interactions) {\n storeEventIfEarliestForCategoryAndEndTime(interaction);\n }\n\n // Combine all the events that we have kept from all the per-category event\n // maps back into an array and sort them by timestamp.\n const keptEvents = Object.values(earliestEventForEndTimePerCategory)\n .flatMap(eventsByEndTime => Array.from(eventsByEndTime.values()));\n keptEvents.sort((eventA, eventB) => {\n return eventA.ts - eventB.ts;\n });\n return keptEvents;\n}\n\nexport async function finalize(): Promise<void> {\n // For each interaction start event, find the async end event by the ID, and then create the Synthetic Interaction event.\n for (const interactionStartEvent of eventTimingStartEventsForInteractions) {\n const endEvent = eventTimingEndEventsById.get(interactionStartEvent.id);\n if (!endEvent) {\n // If we cannot find an end event, bail and drop this event.\n continue;\n }\n if (!interactionStartEvent.args.data?.type || !interactionStartEvent.args.data?.interactionId) {\n // A valid interaction event that we care about has to have a type (e.g.\n // pointerdown, keyup).\n //\n // We also need to ensure it has an interactionId. We already checked\n // this in the handleEvent() function, but we do it here also to satisfy\n // TypeScript.\n continue;\n }\n\n const interactionEvent: Types.TraceEvents.SyntheticInteractionEvent = {\n // Use the start event to define the common fields.\n cat: interactionStartEvent.cat,\n name: interactionStartEvent.name,\n pid: interactionStartEvent.pid,\n tid: interactionStartEvent.tid,\n ph: interactionStartEvent.ph,\n args: {\n data: {\n beginEvent: interactionStartEvent,\n endEvent: endEvent,\n },\n },\n ts: interactionStartEvent.ts,\n dur: Types.Timing.MicroSeconds(endEvent.ts - interactionStartEvent.ts),\n type: interactionStartEvent.args.data.type,\n interactionId: interactionStartEvent.args.data.interactionId,\n };\n if (!longestInteractionEvent || longestInteractionEvent.dur < interactionEvent.dur) {\n longestInteractionEvent = interactionEvent;\n }\n interactionEvents.push(interactionEvent);\n }\n\n handlerState = HandlerState.FINALIZED;\n interactionEventsWithNoNesting.push(...removeNestedInteractions(interactionEvents));\n}\n\nexport function data(): UserInteractionsData {\n return {\n allEvents: [...allEvents],\n interactionEvents: [...interactionEvents],\n interactionEventsWithNoNesting: [...interactionEventsWithNoNesting],\n longestInteractionEvent,\n interactionsOverThreshold: new Set(interactionEvents.filter(event => {\n return event.dur > LONG_INTERACTION_THRESHOLD;\n })),\n };\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\n/**\n * IMPORTANT!\n * See UserTimings.md in this directory for some handy documentation on\n * UserTimings and the trace events we parse currently.\n **/\nconst syntheticEvents: Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[] = [];\nconst performanceMeasureEvents: (Types.TraceEvents.TraceEventPerformanceMeasureBegin|\n Types.TraceEvents.TraceEventPerformanceMeasureEnd)[] = [];\nconst performanceMarkEvents: Types.TraceEvents.TraceEventPerformanceMark[] = [];\n\nconst consoleTimings: (Types.TraceEvents.TraceEventConsoleTimeBegin|Types.TraceEvents.TraceEventConsoleTimeEnd)[] = [];\n\nconst timestampEvents: Types.TraceEvents.TraceEventTimeStamp[] = [];\n\nexport interface UserTimingsData {\n /**\n * Events triggered with the performance.measure() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure\n */\n performanceMeasures: readonly Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[];\n /**\n * Events triggered with the performance.mark() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark\n */\n performanceMarks: readonly Types.TraceEvents.TraceEventPerformanceMark[];\n /**\n * Events triggered with the console.time(), console.timeEnd() and\n * console.timeLog() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/console/time\n */\n consoleTimings: readonly Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[];\n /**\n * Events triggered with the console.timeStamp() API\n * https://developer.mozilla.org/en-US/docs/Web/API/console/timeStamp\n */\n timestampEvents: readonly Types.TraceEvents.TraceEventTimeStamp[];\n}\nlet handlerState = HandlerState.UNINITIALIZED;\n\nexport function reset(): void {\n syntheticEvents.length = 0;\n performanceMeasureEvents.length = 0;\n performanceMarkEvents.length = 0;\n consoleTimings.length = 0;\n timestampEvents.length = 0;\n handlerState = HandlerState.INITIALIZED;\n}\n\nconst resourceTimingNames = [\n 'workerStart',\n 'redirectStart',\n 'redirectEnd',\n 'fetchStart',\n 'domainLookupStart',\n 'domainLookupEnd',\n 'connectStart',\n 'connectEnd',\n 'secureConnectionStart',\n 'requestStart',\n 'responseStart',\n 'responseEnd',\n];\nconst navTimingNames = [\n 'navigationStart',\n 'unloadEventStart',\n 'unloadEventEnd',\n 'redirectStart',\n 'redirectEnd',\n 'fetchStart',\n 'commitNavigationEnd',\n 'domainLookupStart',\n 'domainLookupEnd',\n 'connectStart',\n 'connectEnd',\n 'secureConnectionStart',\n 'requestStart',\n 'responseStart',\n 'responseEnd',\n 'domLoading',\n 'domInteractive',\n 'domContentLoadedEventStart',\n 'domContentLoadedEventEnd',\n 'domComplete',\n 'loadEventStart',\n 'loadEventEnd',\n];\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('UserTimings handler is not initialized');\n }\n\n // These are events dispatched under the blink.user_timing category\n // but that the user didn't add. Filter them out so that they do not\n // Appear in the timings track (they still appear in the main thread\n // flame chart).\n const ignoredNames = [...resourceTimingNames, ...navTimingNames];\n if (ignoredNames.includes(event.name)) {\n return;\n }\n\n if (Types.TraceEvents.isTraceEventPerformanceMeasure(event)) {\n performanceMeasureEvents.push(event);\n return;\n }\n if (Types.TraceEvents.isTraceEventPerformanceMark(event)) {\n performanceMarkEvents.push(event);\n }\n if (Types.TraceEvents.isTraceEventConsoleTime(event)) {\n consoleTimings.push(event);\n }\n if (Types.TraceEvents.isTraceEventTimeStamp(event)) {\n timestampEvents.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('UserTimings handler is not initialized');\n }\n\n const matchedEvents: Map<string, {\n begin: Types.TraceEvents.TraceEventNestableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventNestableAsyncEnd | null,\n }> = new Map();\n\n for (const event of [...performanceMeasureEvents, ...consoleTimings]) {\n const id = Helpers.Trace.extractId(event);\n if (id === undefined) {\n continue;\n }\n // Create a synthetic id to prevent collisions across categories.\n // Console timings can be dispatched with the same id, so use the\n // event name as well to generate unique ids.\n const syntheticId = `${event.cat}:${id}:${event.name}`;\n const otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedEvents, syntheticId, () => {\n return {begin: null, end: null};\n });\n const isStartEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_START;\n const isEndEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_END;\n\n if (isStartEvent) {\n otherEventsWithID.begin = event;\n } else if (isEndEvent) {\n otherEventsWithID.end = event;\n }\n }\n\n for (const [id, eventsPair] of matchedEvents.entries()) {\n if (!eventsPair.begin || !eventsPair.end) {\n // This should never happen, the backend only creates the events once it\n // has them both, so we should never get into this state.\n // If we do, something is very wrong, so let's just drop that problematic event.\n continue;\n }\n\n const event: Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent = {\n cat: eventsPair.end.cat,\n ph: eventsPair.end.ph,\n pid: eventsPair.end.pid,\n tid: eventsPair.end.tid,\n id,\n // Both events have the same name, so it doesn't matter which we pick to\n // use as the description\n name: eventsPair.begin.name,\n dur: Types.Timing.MicroSeconds(eventsPair.end.ts - eventsPair.begin.ts),\n ts: eventsPair.begin.ts,\n args: {\n data: {\n beginEvent: eventsPair.begin,\n endEvent: eventsPair.end,\n },\n },\n };\n\n if (event.dur < 0) {\n // Avoid any pairs that have created a negative duration; this is bad\n // trace data and we should just ignore them.\n continue;\n }\n syntheticEvents.push(event);\n }\n syntheticEvents.sort((a, b) => a.ts - b.ts);\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): UserTimingsData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('UserTimings handler is not finalized');\n }\n\n return {\n performanceMeasures: syntheticEvents.filter(Types.TraceEvents.isTraceEventPerformanceMeasure),\n consoleTimings: syntheticEvents.filter(Types.TraceEvents.isTraceEventConsoleTime),\n performanceMarks: [...performanceMarkEvents],\n timestampEvents: [...timestampEvents],\n };\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nexport interface WarningsData {\n // Tracks warnings keyed by the event.\n perEvent: Map<Types.TraceEvents.TraceEventData, Warning[]>;\n // The same data in reverse: for each type of warning, track the events.\n // Useful if we need to enumerate issues by type of issue\n perWarning: Map<Warning, Types.TraceEvents.TraceEventData[]>;\n}\n\nexport type Warning = 'LONG_TASK'|'IDLE_CALLBACK_OVER_TIME'|'FORCED_LAYOUT'|'FORCED_STYLE';\n\nconst warningsPerEvent: WarningsData['perEvent'] = new Map();\nconst eventsPerWarning: WarningsData['perWarning'] = new Map();\n\nexport const FORCED_LAYOUT_AND_STYLES_THRESHOLD =\n Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(10));\n\nexport const LONG_MAIN_THREAD_TASK_THRESHOLD = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(50));\n\nexport function reset(): void {\n warningsPerEvent.clear();\n eventsPerWarning.clear();\n}\n\nfunction storeWarning(event: Types.TraceEvents.TraceEventData, warning: Warning): void {\n const existingWarnings = Platform.MapUtilities.getWithDefault(warningsPerEvent, event, () => []);\n existingWarnings.push(warning);\n warningsPerEvent.set(event, existingWarnings);\n\n const existingEvents = Platform.MapUtilities.getWithDefault(eventsPerWarning, warning, () => []);\n existingEvents.push(event);\n eventsPerWarning.set(warning, existingEvents);\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (event.name === Types.TraceEvents.KnownEventName.RunTask) {\n const {duration} = Helpers.Timing.eventTimingsMicroSeconds(event);\n if (duration > LONG_MAIN_THREAD_TASK_THRESHOLD) {\n storeWarning(event, 'LONG_TASK');\n }\n return;\n }\n\n if (Types.TraceEvents.isTraceEventFireIdleCallback(event)) {\n const {duration} = Helpers.Timing.eventTimingsMilliSeconds(event);\n if (duration > event.args.data.allottedMilliseconds) {\n storeWarning(event, 'IDLE_CALLBACK_OVER_TIME');\n }\n return;\n }\n\n if (event.name === Types.TraceEvents.KnownEventName.Layout) {\n if (event.dur && event.dur >= FORCED_LAYOUT_AND_STYLES_THRESHOLD) {\n storeWarning(event, 'FORCED_LAYOUT');\n }\n return;\n }\n\n if (event.name === Types.TraceEvents.KnownEventName.RecalculateStyles ||\n event.name === Types.TraceEvents.KnownEventName.UpdateLayoutTree) {\n if (event.dur && event.dur >= FORCED_LAYOUT_AND_STYLES_THRESHOLD) {\n storeWarning(event, 'FORCED_STYLE');\n }\n return;\n }\n}\n\nexport function data(): WarningsData {\n return {\n perEvent: new Map(warningsPerEvent),\n perWarning: new Map(eventsPerWarning),\n };\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\nexport interface WorkersData {\n workerSessionIdEvents: readonly Types.TraceEvents.TraceEventTracingSessionIdForWorker[];\n workerIdByThread: Map<Types.TraceEvents.ThreadID, Types.TraceEvents.WorkerId>;\n workerURLById: Map<Types.TraceEvents.WorkerId, string>;\n}\nlet handlerState = HandlerState.UNINITIALIZED;\n\nconst sessionIdEvents: Types.TraceEvents.TraceEventTracingSessionIdForWorker[] = [];\nconst workerIdByThread: Map<Types.TraceEvents.ThreadID, Types.TraceEvents.WorkerId> = new Map();\nconst workerURLById: Map<Types.TraceEvents.WorkerId, string> = new Map();\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('Workers Handler was not reset');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function reset(): void {\n sessionIdEvents.length = 0;\n workerIdByThread.clear();\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Workers Handler is not initialized');\n }\n if (Types.TraceEvents.isTraceEventTracingSessionIdForWorker(event)) {\n sessionIdEvents.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Handler is not initialized');\n }\n for (const sessionIdEvent of sessionIdEvents) {\n if (!sessionIdEvent.args.data) {\n continue;\n }\n workerIdByThread.set(sessionIdEvent.args.data.workerThreadId, sessionIdEvent.args.data.workerId);\n workerURLById.set(sessionIdEvent.args.data.workerId, sessionIdEvent.args.data.url);\n }\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): WorkersData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Workers Handler is not finalized');\n }\n\n return {\n workerSessionIdEvents: [...sessionIdEvents],\n workerIdByThread: new Map(workerIdByThread),\n workerURLById: new Map(workerURLById),\n };\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as Animations from './AnimationHandler.js';\nexport * as AuctionWorklets from './AuctionWorkletsHandler.js';\nexport * as GPU from './GPUHandler.js';\nexport * as LargestImagePaint from './LargestImagePaintHandler.js';\nexport * as LargestTextPaint from './LargestTextPaintHandler.js';\nexport * as LayoutShifts from './LayoutShiftsHandler.js';\nexport * as Memory from './MemoryHandler.js';\nexport * as Meta from './MetaHandler.js';\nexport * as NetworkRequests from './NetworkRequestsHandler.js';\nexport * as PageLoadMetrics from './PageLoadMetricsHandler.js';\nexport * as Renderer from './RendererHandler.js';\nexport * as Samples from './SamplesHandler.js';\nexport * as Screenshots from './ScreenshotsHandler.js';\nexport * as UserInteractions from './UserInteractionsHandler.js';\nexport * as UserTimings from './UserTimingsHandler.js';\nexport * as Warnings from './WarningsHandler.js';\nexport * as Workers from './WorkersHandler.js';\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Types from '../types/types.js';\nimport type * as Protocol from '../../../generated/protocol.js';\n/**\n * If the LCP resource was an image, and that image was fetched over the\n * network, we want to be able to find the network request in order to construct\n * the critical path for an LCP image.\n * Within the trace file there are `LargestImagePaint::Candidate` events.\n * Within their data object, they contain a `DOMNodeId` property, which maps to\n * the DOM Node ID for that image.\n *\n * This id maps exactly to the `data.nodeId` property that a\n * `LargestContentfulPaint::Candidate` will have. So, when we find an image\n * paint candidate, we can store it, keying it on the node ID.\n * Then, when it comes to finding the network request for an LCP image, we can\n *\n * use the nodeId from the LCP candidate to find the image candidate. That image\n * candidate also contains a `imageUrl` property, which will have the full URL\n * to the image.\n **/\nconst imageByDOMNodeId = new Map<Protocol.DOM.BackendNodeId, Types.TraceEvents.TraceEventLargestImagePaintCandidate>();\n\nexport function reset(): void {\n imageByDOMNodeId.clear();\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (!Types.TraceEvents.isTraceEventLargestImagePaintCandidate(event)) {\n return;\n }\n\n if (!event.args.data) {\n return;\n }\n\n imageByDOMNodeId.set(event.args.data.DOMNodeId, event);\n}\n\nexport function data(): Map<Protocol.DOM.BackendNodeId, Types.TraceEvents.TraceEventLargestImagePaintCandidate> {\n return new Map(imageByDOMNodeId);\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as Types from '../types/types.js';\n/**\n * A trace file will contain all the text paints that were candidates for the\n * LargestTextPaint. If an LCP event is text, it will point to one of these\n * candidates, so we store them by their DOM Node ID.\n **/\nconst textPaintByDOMNodeId =\n new Map<Protocol.DOM.BackendNodeId, Types.TraceEvents.TraceEventLargestTextPaintCandidate>();\n\nexport function reset(): void {\n textPaintByDOMNodeId.clear();\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (!Types.TraceEvents.isTraceEventLargestTextPaintCandidate(event)) {\n return;\n }\n\n if (!event.args.data) {\n return;\n }\n\n textPaintByDOMNodeId.set(event.args.data.DOMNodeId, event);\n}\n\nexport function data(): Map<Protocol.DOM.BackendNodeId, Types.TraceEvents.TraceEventLargestTextPaintCandidate> {\n return new Map(textPaintByDOMNodeId);\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as auctionWorkletsData} from './AuctionWorkletsHandler.js';\nimport {data as metaHandlerData, type FrameProcessData} from './MetaHandler.js';\nimport {data as samplesHandlerData} from './SamplesHandler.js';\nimport {HandlerState, type TraceEventHandlerName} from './types.js';\n\n/**\n * This handler builds the hierarchy of trace events and profile calls\n * on each thread on each process.\n *\n * Throughout the code, trace events and profile calls are referred to\n * as \"entries\", but note they are different types of data. Trace events\n * come directly from the backend and it's the type the engine commonly\n * refers to. Profile calls on the other hand are built in the frontend,\n * and, for compatibility purposes, typed as an extension to the trace\n * event type.\n */\n\nconst processes = new Map<Types.TraceEvents.ProcessID, RendererProcess>();\n\n// We track the compositor tile worker thread name events so that at the end we\n// can return these keyed by the process ID. These are used in the frontend to\n// show the user the rasterization thread(s) on the main frame as tracks.\nconst compositorTileWorkers = Array<{\n pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID,\n}>();\nconst entryToNode: Map<Types.TraceEvents.TraceEntry, Helpers.TreeHelpers.TraceEntryNode> = new Map();\nconst allRendererEvents: Types.TraceEvents.TraceEventRendererEvent[] = [];\n\nconst completeEventStack: (Types.TraceEvents.TraceEventSyntheticCompleteEvent)[] = [];\n\nlet handlerState = HandlerState.UNINITIALIZED;\nlet config: Types.Configuration.Configuration = Types.Configuration.DEFAULT;\n\nconst makeRendererProcess = (): RendererProcess => ({\n url: null,\n isOnMainFrame: false,\n threads: new Map(),\n});\n\nconst makeRendererThread = (): RendererThread => ({\n name: null,\n entries: [],\n});\n\nconst getOrCreateRendererProcess =\n (processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, pid: Types.TraceEvents.ProcessID):\n RendererProcess => {\n return Platform.MapUtilities.getWithDefault(processes, pid, makeRendererProcess);\n };\n\nconst getOrCreateRendererThread = (process: RendererProcess, tid: Types.TraceEvents.ThreadID): RendererThread => {\n return Platform.MapUtilities.getWithDefault(process.threads, tid, makeRendererThread);\n};\n\nexport function handleUserConfig(userConfig: Types.Configuration.Configuration): void {\n config = userConfig;\n}\n\nexport function reset(): void {\n processes.clear();\n entryToNode.clear();\n allRendererEvents.length = 0;\n completeEventStack.length = 0;\n compositorTileWorkers.length = 0;\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('Renderer Handler was not reset');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Renderer Handler is not initialized');\n }\n\n if (Types.TraceEvents.isThreadName(event) && event.args.name?.startsWith('CompositorTileWorker')) {\n compositorTileWorkers.push({\n pid: event.pid,\n tid: event.tid,\n });\n }\n\n if (Types.TraceEvents.isTraceEventBegin(event) || Types.TraceEvents.isTraceEventEnd(event)) {\n const process = getOrCreateRendererProcess(processes, event.pid);\n const thread = getOrCreateRendererThread(process, event.tid);\n const completeEvent = makeCompleteEvent(event);\n if (!completeEvent) {\n return;\n }\n thread.entries.push(completeEvent);\n allRendererEvents.push(completeEvent);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventInstant(event) || Types.TraceEvents.isTraceEventComplete(event)) {\n const process = getOrCreateRendererProcess(processes, event.pid);\n const thread = getOrCreateRendererThread(process, event.tid);\n thread.entries.push(event);\n allRendererEvents.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Renderer Handler is not initialized');\n }\n\n const {mainFrameId, rendererProcessesByFrame, threadsInProcess} = metaHandlerData();\n assignMeta(processes, mainFrameId, rendererProcessesByFrame, threadsInProcess);\n sanitizeProcesses(processes);\n buildHierarchy(processes);\n sanitizeThreads(processes);\n\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): RendererHandlerData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Renderer Handler is not finalized');\n }\n\n return {\n processes: new Map(processes),\n compositorTileWorkers: new Map(gatherCompositorThreads()),\n entryToNode: new Map(entryToNode),\n allRendererEvents: [...allRendererEvents],\n };\n}\n\nfunction gatherCompositorThreads(): Map<Types.TraceEvents.ProcessID, Types.TraceEvents.ThreadID[]> {\n const threadsByProcess = new Map<Types.TraceEvents.ProcessID, Types.TraceEvents.ThreadID[]>();\n for (const worker of compositorTileWorkers) {\n const byProcess = threadsByProcess.get(worker.pid) || [];\n byProcess.push(worker.tid);\n threadsByProcess.set(worker.pid, byProcess);\n }\n return threadsByProcess;\n}\n\n/**\n * Steps through all the renderer processes we've located so far in the meta\n * handler, obtaining their URL, checking whether they are the main frame, and\n * collecting each one of their threads' name. This meta handler's data is\n * assigned to the renderer handler's data.\n */\nexport function assignMeta(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, mainFrameId: string,\n rendererProcessesByFrame: FrameProcessData,\n threadsInProcess:\n Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventThreadName>>):\n void {\n assignOrigin(processes, rendererProcessesByFrame);\n assignIsMainFrame(processes, mainFrameId, rendererProcessesByFrame);\n assignThreadName(processes, rendererProcessesByFrame, threadsInProcess);\n}\n\n/**\n * Assigns origins to all threads in all processes.\n * @see assignMeta\n */\nexport function assignOrigin(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, rendererProcessesByFrame: FrameProcessData): void {\n for (const renderProcessesByPid of rendererProcessesByFrame.values()) {\n for (const [pid, processWindows] of renderProcessesByPid) {\n for (const processInfo of processWindows.flat()) {\n const process = getOrCreateRendererProcess(processes, pid);\n // Sometimes a single process is responsible with rendering multiple\n // frames at the same time. For example, see https://crbug.com/1334563.\n // When this happens, we'd still like to assign a single url per process\n // so: 1) use the first frame rendered by this process as the url source\n // and 2) if the last url is \"about:blank\", use the next frame's url,\n // data from about:blank is irrelevant.\n if (process.url === null || process.url === 'about:blank') {\n // If we are here, it's because we care about this process and the URL. But before we store\n // it, we check if it is a valid URL by trying to create a URL object. If it isn't, we won't\n // set it, and this process will be filtered out later.\n try {\n new URL(processInfo.frame.url);\n process.url = processInfo.frame.url;\n } catch (e) {\n process.url = null;\n }\n }\n }\n }\n }\n}\n\n/**\n * Assigns whether or not a thread is the main frame to all threads in all processes.\n * @see assignMeta\n */\nexport function assignIsMainFrame(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, mainFrameId: string,\n rendererProcessesByFrame: FrameProcessData): void {\n for (const [frameId, renderProcessesByPid] of rendererProcessesByFrame) {\n for (const [pid] of renderProcessesByPid) {\n const process = getOrCreateRendererProcess(processes, pid);\n // We have this go in one direction; once a renderer has been flagged as\n // being on the main frame, we don't unset it to false if were to show up\n // in a subframe. Equally, if we already saw this renderer in a subframe,\n // but it becomes the main frame, the flag would get updated.\n if (frameId === mainFrameId) {\n process.isOnMainFrame = true;\n }\n }\n }\n}\n\n/**\n * Assigns the thread name to all threads in all processes.\n * @see assignMeta\n */\nexport function assignThreadName(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>, rendererProcessesByFrame: FrameProcessData,\n threadsInProcess:\n Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventThreadName>>):\n void {\n for (const [, renderProcessesByPid] of rendererProcessesByFrame) {\n for (const [pid] of renderProcessesByPid) {\n const process = getOrCreateRendererProcess(processes, pid);\n for (const [tid, threadInfo] of threadsInProcess.get(pid) ?? []) {\n const thread = getOrCreateRendererThread(process, tid);\n thread.name = threadInfo?.args.name ?? `${tid}`;\n }\n }\n }\n}\n\n/**\n * Removes unneeded trace data opportunistically stored while handling events.\n * This currently does the following:\n * - Deletes processes with an unkonwn origin.\n */\nexport function sanitizeProcesses(processes: Map<Types.TraceEvents.ProcessID, RendererProcess>): void {\n const auctionWorklets = auctionWorkletsData().worklets;\n for (const [pid, process] of processes) {\n // If the process had no url, or if it had a malformed url that could not be\n // parsed for some reason, or if it's an \"about:\" origin, delete it.\n // This is done because we don't really care about processes for which we\n // can't provide actionable insights to the user (e.g. about:blank pages).\n //\n // There is one exception; AuctionWorklet processes get parsed in a\n // separate handler, so at this point we check to see if the process has\n // been found by the AuctionWorkletsHandler, and if so we update the URL.\n // This ensures that we keep this process around and do not drop it due to\n // the lack of a URL.\n if (process.url === null) {\n const maybeWorklet = auctionWorklets.get(pid);\n if (maybeWorklet) {\n process.url = maybeWorklet.host;\n } else {\n processes.delete(pid);\n }\n continue;\n }\n const asUrl = new URL(process.url);\n if (asUrl.protocol === 'about:') {\n processes.delete(pid);\n }\n }\n}\n\n/**\n * Removes unneeded trace data opportunistically stored while handling events.\n * This currently does the following:\n * - Deletes threads with no roots.\n */\nexport function sanitizeThreads(processes: Map<Types.TraceEvents.ProcessID, RendererProcess>): void {\n for (const [, process] of processes) {\n for (const [tid, thread] of process.threads) {\n // If the thread has no roots, delete it. Otherwise, there's going to\n // be space taken, even though nothing is rendered in the track manager.\n if (!thread.tree?.roots.size) {\n process.threads.delete(tid);\n }\n }\n }\n}\n\n/**\n * Creates a hierarchical structure from the trace events. Each thread in each\n * process will contribute to their own individual hierarchy.\n *\n * The trace data comes in as a contiguous array of events, against which we\n * make a couple of assumptions:\n *\n * 1. Events are temporally-ordered in terms of start time (though they're\n * not necessarily ordered as such in the data stream).\n * 2. If event B's start and end times are within event A's time boundaries\n * we assume that A is the parent of B.\n *\n * Therefore we expect to reformulate something like:\n *\n * [ Task A ][ Task B ][ Task C ][ Task D ][ Task E ]\n *\n * Into something hierarchically-arranged like below:\n *\n * |------------- Task A -------------||-- Task E --|\n * |-- Task B --||-- Task D --|\n * |- Task C -|\n */\nexport function buildHierarchy(\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>,\n options?: {filter: {has: (name: Types.TraceEvents.KnownEventName) => boolean}}): void {\n for (const [pid, process] of processes) {\n for (const [tid, thread] of process.threads) {\n if (!thread.entries.length) {\n thread.tree = Helpers.TreeHelpers.makeEmptyTraceEntryTree();\n continue;\n }\n // Step 1. Massage the data.\n Helpers.Trace.sortTraceEventsInPlace(thread.entries);\n // Step 2. Inject profile calls from samples\n const cpuProfile = samplesHandlerData().profilesInProcess.get(pid)?.get(tid)?.parsedProfile;\n const samplesIntegrator =\n cpuProfile && new Helpers.SamplesIntegrator.SamplesIntegrator(cpuProfile, pid, tid, config);\n const profileCalls = samplesIntegrator?.buildProfileCalls(thread.entries);\n if (profileCalls) {\n thread.entries = Helpers.Trace.mergeEventsInOrder(thread.entries, profileCalls);\n }\n // Step 3. Build the tree.\n const treeData = Helpers.TreeHelpers.treify(thread.entries, options);\n thread.tree = treeData.tree;\n // Update the entryToNode map with the entries from this thread\n for (const [entry, node] of treeData.entryToNode) {\n entryToNode.set(entry, node);\n }\n }\n }\n}\n\nexport function makeCompleteEvent(event: Types.TraceEvents.TraceEventBegin|Types.TraceEvents.TraceEventEnd):\n Types.TraceEvents.TraceEventSyntheticCompleteEvent|null {\n if (Types.TraceEvents.isTraceEventEnd(event)) {\n // Quietly ignore unbalanced close events, they're legit (we could\n // have missed start one).\n const beginEvent = completeEventStack.pop();\n if (!beginEvent) {\n return null;\n }\n if (beginEvent.name !== event.name || beginEvent.cat !== event.cat) {\n console.error(\n 'Begin/End events mismatch at ' + beginEvent.ts + ' (' + beginEvent.name + ') vs. ' + event.ts + ' (' +\n event.name + ')');\n return null;\n }\n // Update the begin event's duration using the timestamp of the end\n // event.\n beginEvent.dur = Types.Timing.MicroSeconds(event.ts - beginEvent.ts);\n return null;\n }\n\n // Create a synthetic event using the begin event, when we find the\n // matching end event later we will update its duration.\n const syntheticComplete: Types.TraceEvents.TraceEventSyntheticCompleteEvent = {\n ...event,\n ph: Types.TraceEvents.Phase.COMPLETE,\n dur: Types.Timing.MicroSeconds(0),\n };\n\n completeEventStack.push(syntheticComplete);\n return syntheticComplete;\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta', 'Samples', 'AuctionWorklets'];\n}\n\nexport interface RendererHandlerData {\n processes: Map<Types.TraceEvents.ProcessID, RendererProcess>;\n /**\n * A map of all compositor workers (which we show in the UI as Rasterizers)\n * by the process ID.\n */\n compositorTileWorkers: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.ThreadID[]>;\n entryToNode: Map<Types.TraceEvents.TraceEntry, Helpers.TreeHelpers.TraceEntryNode>;\n /**\n * All trace events and synthetic profile calls made from\n * samples.\n */\n allRendererEvents: Types.TraceEvents.TraceEventRendererEvent[];\n}\n\nexport interface RendererProcess {\n // In an ideal world this would be modelled as a URL, but URLs cannot be sent\n // between the main thread and workers, so we have to store it as a string.\n url: string|null;\n isOnMainFrame: boolean;\n threads: Map<Types.TraceEvents.ThreadID, RendererThread>;\n}\n\nexport interface RendererThread {\n name: string|null;\n /**\n * Contains trace events and synthetic profile calls made from\n * samples.\n */\n entries: Types.TraceEvents.TraceEntry[];\n tree?: Helpers.TreeHelpers.TraceEntryTree;\n}\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as CPUProfile from '../../cpu_profile/cpu_profile.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\nconst events =\n new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, Types.TraceEvents.TraceEventComplete[]>>();\n\nconst profilesInProcess = new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ThreadID, ProfileData>>();\nconst entryToNode = new Map<Types.TraceEvents.TraceEntry, Helpers.TreeHelpers.TraceEntryNode>();\n\n// The profile head, containing its metadata like its start\n// time, comes in a \"Profile\" event. The sample data comes in\n// \"ProfileChunk\" events. We match these ProfileChunks with their head\n// using process and profile ids. However, in order to integrate sample\n// data with trace data, we need the thread id that owns each profile.\n// This thread id is extracted from the head event.\n// For this reason, we have a preprocessed data structure, where events\n// are matched by profile id, which we then finish processing to export\n// events matched by thread id.\nconst preprocessedData = new Map<Types.TraceEvents.ProcessID, Map<Types.TraceEvents.ProfileID, PreprocessedData>>();\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\nfunction buildProfileCalls(): void {\n for (const [processId, profiles] of preprocessedData) {\n for (const [profileId, preProcessedData] of profiles) {\n const threadId = preProcessedData.threadId;\n if (!preProcessedData.rawProfile.nodes.length || threadId === undefined) {\n continue;\n }\n const indexStack: number[] = [];\n\n const profileModel = new CPUProfile.CPUProfileDataModel.CPUProfileDataModel(preProcessedData.rawProfile);\n const profileTree = Helpers.TreeHelpers.makeEmptyTraceEntryTree();\n profileTree.maxDepth = profileModel.maxDepth;\n\n const finalizedData: ProfileData =\n {rawProfile: preProcessedData.rawProfile, parsedProfile: profileModel, profileCalls: [], profileTree};\n\n const dataByThread = Platform.MapUtilities.getWithDefault(profilesInProcess, processId, () => new Map());\n profileModel.forEachFrame(openFrameCallback, closeFrameCallback);\n dataByThread.set(threadId, finalizedData);\n\n function openFrameCallback(\n depth: number, node: CPUProfile.ProfileTreeModel.ProfileNode, timeStampMs: number): void {\n if (threadId === undefined) {\n return;\n }\n const ts = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(timeStampMs));\n const nodeId = node.id as Helpers.TreeHelpers.TraceEntryNodeId;\n\n const profileCall = Helpers.Trace.makeProfileCall(node, ts, processId, threadId);\n finalizedData.profileCalls.push(profileCall);\n indexStack.push(finalizedData.profileCalls.length - 1);\n const traceEntryNode = Helpers.TreeHelpers.makeEmptyTraceEntryNode(profileCall, nodeId);\n finalizedData.profileTree?.nodes.set(nodeId, traceEntryNode);\n entryToNode.set(profileCall, traceEntryNode);\n traceEntryNode.depth = depth;\n if (indexStack.length === 1) {\n // First call in the stack is a root call.\n finalizedData.profileTree?.roots.add(traceEntryNode);\n }\n }\n function closeFrameCallback(\n _depth: number, node: CPUProfile.ProfileTreeModel.ProfileNode, _timeStamp: number, durMs: number,\n selfTimeMs: number): void {\n const profileCallIndex = indexStack.pop();\n const profileCall = profileCallIndex !== undefined && finalizedData.profileCalls[profileCallIndex];\n if (!profileCall) {\n return;\n }\n const {callFrame, ts, pid, tid} = profileCall;\n const traceEntryNode = entryToNode.get(profileCall);\n if (callFrame === undefined || ts === undefined || pid === undefined || profileId === undefined ||\n tid === undefined || traceEntryNode === undefined) {\n return;\n }\n const dur = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(durMs));\n const selfTime = Helpers.Timing.millisecondsToMicroseconds(Types.Timing.MilliSeconds(selfTimeMs));\n profileCall.dur = dur;\n profileCall.selfTime = selfTime;\n\n const parentIndex = indexStack.at(-1);\n const parent = parentIndex !== undefined && finalizedData.profileCalls.at(parentIndex);\n const parentNode = parent && entryToNode.get(parent);\n if (!parentNode) {\n return;\n }\n traceEntryNode.parentId = parentNode.id;\n parentNode.children.add(traceEntryNode);\n }\n }\n }\n}\n\nexport function reset(): void {\n events.clear();\n preprocessedData.clear();\n profilesInProcess.clear();\n entryToNode.clear();\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('Samples Handler was not reset');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Samples Handler is not initialized');\n }\n\n /**\n * A fake trace event created to support CDP.Profiler.Profiles in the\n * trace engine.\n */\n if (Types.TraceEvents.isSyntheticTraceEventCpuProfile(event)) {\n // At the moment we are attaching to a single node target so we\n // should only get a single CPU profile. The values of the process\n // id and thread id are not really important, so we use the data\n // in the fake event. Should multi-thread CPU profiling be supported\n // we could use these fields in the event to pass thread info.\n const pid = event.pid;\n const tid = event.tid;\n // Create an arbitrary profile id.\n const profileId = '0x1' as Types.TraceEvents.ProfileID;\n const profileData = getOrCreatePreProcessedData(pid, profileId);\n profileData.rawProfile = event.args.data.cpuProfile;\n profileData.threadId = tid;\n return;\n }\n\n if (Types.TraceEvents.isTraceEventProfile(event)) {\n // Do not use event.args.data.startTime as it is in CLOCK_MONOTONIC domain,\n // but use profileEvent.ts which has been translated to Perfetto's clock\n // domain. Also convert from ms to us.\n // Note: events are collected on a different thread than what's sampled.\n // The correct process and thread ids are specified by the profile.\n const profileData = getOrCreatePreProcessedData(event.pid, event.id);\n profileData.rawProfile.startTime = event.ts;\n profileData.threadId = event.tid;\n return;\n }\n if (Types.TraceEvents.isTraceEventProfileChunk(event)) {\n const profileData = getOrCreatePreProcessedData(event.pid, event.id);\n const cdpProfile = profileData.rawProfile;\n const nodesAndSamples: Types.TraceEvents.TraceEventPartialProfile|undefined =\n event.args?.data?.cpuProfile || {samples: []};\n const samples = nodesAndSamples?.samples || [];\n const nodes: CPUProfile.CPUProfileDataModel.ExtendedProfileNode[] = [];\n for (const n of nodesAndSamples?.nodes || []) {\n const lineNumber = typeof n.callFrame.lineNumber === 'undefined' ? -1 : n.callFrame.lineNumber;\n const columnNumber = typeof n.callFrame.columnNumber === 'undefined' ? -1 : n.callFrame.columnNumber;\n\n const scriptId = String(n.callFrame.scriptId) as Protocol.Runtime.ScriptId;\n const url = n.callFrame.url || '';\n const node = {\n ...n,\n callFrame: {\n ...n.callFrame,\n url,\n lineNumber,\n columnNumber,\n scriptId,\n },\n };\n nodes.push(node);\n }\n\n const timeDeltas = event.args.data?.timeDeltas || [];\n const lines = event.args.data?.lines || Array(samples.length).fill(0);\n cdpProfile.nodes.push(...nodes);\n cdpProfile.samples?.push(...samples);\n cdpProfile.timeDeltas?.push(...timeDeltas);\n cdpProfile.lines?.push(...lines);\n if (cdpProfile.samples && cdpProfile.timeDeltas && cdpProfile.samples.length !== cdpProfile.timeDeltas.length) {\n console.error('Failed to parse CPU profile.');\n return;\n }\n if (!cdpProfile.endTime && cdpProfile.timeDeltas) {\n const timeDeltas: number[] = cdpProfile.timeDeltas;\n cdpProfile.endTime = timeDeltas.reduce((x, y) => x + y, cdpProfile.startTime);\n }\n return;\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('Samples Handler is not initialized');\n }\n buildProfileCalls();\n\n handlerState = HandlerState.FINALIZED;\n}\n\nexport function data(): SamplesHandlerData {\n if (handlerState !== HandlerState.FINALIZED) {\n throw new Error('Samples Handler is not finalized');\n }\n\n return {\n profilesInProcess: new Map(profilesInProcess),\n entryToNode: new Map(entryToNode),\n };\n}\n\nfunction getOrCreatePreProcessedData(\n processId: Types.TraceEvents.ProcessID, profileId: Types.TraceEvents.ProfileID): PreprocessedData {\n const profileById = Platform.MapUtilities.getWithDefault(preprocessedData, processId, () => new Map());\n return Platform.MapUtilities.getWithDefault<Types.TraceEvents.ProfileID, PreprocessedData>(\n profileById, profileId, () => ({\n rawProfile: {\n startTime: 0,\n endTime: 0,\n nodes: [],\n samples: [],\n timeDeltas: [],\n lines: [],\n },\n profileId,\n }));\n}\n\nexport interface SamplesHandlerData {\n profilesInProcess: typeof profilesInProcess;\n entryToNode: typeof entryToNode;\n}\n\nexport type ProfileData = {\n rawProfile: CPUProfile.CPUProfileDataModel.ExtendedProfile,\n parsedProfile: CPUProfile.CPUProfileDataModel.CPUProfileDataModel,\n /**\n * Contains the calls built from the CPU profile samples.\n * Note: This doesn't contain real trace events coming from the\n * browser, only calls synthetically typed as trace events for\n * compatibility, as such it only makes sense to use them in pure CPU\n * profiles.\n *\n * If you need the profile calls from a CPU profile obtained from a\n * web trace, use the data exported by the RendererHandler instead.\n */\n profileCalls: Types.TraceEvents.TraceEventSyntheticProfileCall[],\n /**\n * Contains the call tree built from the CPU profile samples.\n * Similar to the profileCalls field, this tree does not contain nor\n * take into account trace events, as such it only makes sense to use\n * them in pure CPU profiles.\n */\n profileTree?: Helpers.TreeHelpers.TraceEntryTree,\n};\n\ntype PreprocessedData = {\n rawProfile: CPUProfile.CPUProfileDataModel.ExtendedProfile,\n threadId?: Types.TraceEvents.ThreadID, profileId: Types.TraceEvents.ProfileID,\n};\n\n/**\n * Returns the name of a function for a given synthetic profile call.\n * We first look to find the ProfileNode representing this call, and use its\n * function name. This is preferred (and should always exist) because if we\n * resolve sourcemaps, we will update this name. If that name is not present,\n * we fall back to the function name that was in the callframe that we got\n * when parsing the profile's trace data.\n */\nexport function getProfileCallFunctionName(\n data: SamplesHandlerData, entry: Types.TraceEvents.TraceEventSyntheticProfileCall): string {\n const profile = data.profilesInProcess.get(entry.pid)?.get(entry.tid);\n const node = profile?.parsedProfile.nodeById(entry.nodeId);\n if (node?.functionName) {\n return node.functionName;\n }\n return entry.callFrame.functionName;\n}\n", "// Copyright 2014 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../core/platform/platform.js';\nimport type * as Protocol from '../../generated/protocol.js';\n\nimport {ProfileNode, ProfileTreeModel} from './ProfileTreeModel.js';\n\nexport class CPUProfileNode extends ProfileNode {\n override id: number;\n override self: number;\n // Position ticks are available in profile nodes coming from CDP\n // profiles and not in those coming from tracing. They are used to\n // calculate the line level execution time shown in the Sources panel\n // after recording a profile. For trace CPU profiles we use the\n // `lines` array instead.\n positionTicks: Protocol.Profiler.PositionTickInfo[]|undefined;\n override deoptReason: string|null;\n\n constructor(node: Protocol.Profiler.ProfileNode, samplingInterval: number /* milliseconds */) {\n const callFrame = node.callFrame || ({\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n functionName: node['functionName'],\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n scriptId: node['scriptId'],\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n url: node['url'],\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n lineNumber: node['lineNumber'] - 1,\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // @ts-expect-error\n columnNumber: node['columnNumber'] - 1,\n } as Protocol.Runtime.CallFrame);\n super(callFrame);\n this.id = node.id;\n this.self = (node.hitCount || 0) * samplingInterval;\n this.positionTicks = node.positionTicks;\n // Compatibility: legacy backends could provide \"no reason\" for optimized functions.\n this.deoptReason = node.deoptReason && node.deoptReason !== 'no reason' ? node.deoptReason : null;\n }\n}\n\nexport class CPUProfileDataModel extends ProfileTreeModel {\n profileStartTime: number /* milliseconds */;\n profileEndTime: number /* milliseconds */;\n timestamps: number[];\n samples: number[]|undefined;\n lines?: number[];\n totalHitCount: number;\n profileHead: CPUProfileNode;\n /**\n * A cache for the nodes we have parsed.\n * Note: \"Parsed\" nodes are different from the \"Protocol\" nodes, the\n * latter being the raw data we receive from the backend.\n */\n #idToParsedNode!: Map<number, ProfileNode>;\n gcNode?: ProfileNode;\n programNode?: ProfileNode;\n idleNode?: ProfileNode;\n #stackStartTimes?: number[];\n #stackChildrenDuration?: number[];\n constructor(profile: ExtendedProfile) {\n super();\n // @ts-ignore Legacy types\n const isLegacyFormat = Boolean(profile['head']);\n if (isLegacyFormat) {\n // Legacy format contains raw timestamps and start/stop times are in seconds.\n this.profileStartTime = profile.startTime * 1000;\n this.profileEndTime = profile.endTime * 1000;\n // @ts-ignore Legacy types\n this.timestamps = profile.timestamps;\n this.compatibilityConversionHeadToNodes(profile);\n } else {\n // Current format encodes timestamps as deltas. Start/stop times are in microseconds.\n this.profileStartTime = profile.startTime / 1000;\n this.profileEndTime = profile.endTime / 1000;\n this.timestamps = this.convertTimeDeltas(profile);\n }\n this.samples = profile.samples;\n\n // Lines are available only in profiles coming from tracing.\n // Elements in the lines array have a 1 to 1 correspondance with\n // samples, by array position. They can be 1 or 0 and indicate if\n // there is line data for a given sample, i.e. if a given sample\n // needs to be included to calculate the line level execution time\n // data, which we show in the sources panel after recording a\n // profile.\n this.lines = profile.lines;\n this.totalHitCount = 0;\n this.profileHead = this.translateProfileTree(profile.nodes);\n this.initialize(this.profileHead);\n this.extractMetaNodes();\n if (this.samples) {\n this.sortSamples();\n this.normalizeTimestamps();\n this.fixMissingSamples();\n }\n }\n\n private compatibilityConversionHeadToNodes(profile: Protocol.Profiler.Profile): void {\n // @ts-ignore Legacy types\n if (!profile.head || profile.nodes) {\n return;\n }\n const nodes: Protocol.Profiler.ProfileNode[] = [];\n // @ts-ignore Legacy types\n convertNodesTree(profile.head);\n profile.nodes = nodes;\n // @ts-ignore Legacy types\n delete profile.head;\n function convertNodesTree(node: Protocol.Profiler.ProfileNode): number {\n nodes.push(node);\n // @ts-ignore Legacy types\n node.children = (node.children as Protocol.Profiler.ProfileNode[]).map(convertNodesTree);\n return node.id;\n }\n }\n\n /**\n * Calculate timestamps using timeDeltas. Some CPU profile formats,\n * like the ones contained in traces have timeDeltas instead of\n * timestamps.\n */\n private convertTimeDeltas(profile: Protocol.Profiler.Profile): number[] {\n if (!profile.timeDeltas) {\n return [];\n }\n let lastTimeMicroSec = profile.startTime;\n const timestamps = new Array(profile.timeDeltas.length);\n for (let i = 0; i < profile.timeDeltas.length; ++i) {\n lastTimeMicroSec += profile.timeDeltas[i];\n timestamps[i] = lastTimeMicroSec;\n }\n return timestamps;\n }\n\n /**\n * Creates a Tree of CPUProfileNodes using the Protocol.Profiler.ProfileNodes.\n * As the tree is built, samples of native code (prefixed with \"native \") are\n * filtered out. Samples of filtered nodes are replaced with the parent of the\n * node being filtered.\n *\n * This function supports legacy and new definitions of the CDP Profiler.Profile\n * type.\n */\n private translateProfileTree(nodes: Protocol.Profiler.ProfileNode[]): CPUProfileNode {\n function buildChildrenFromParents(nodes: Protocol.Profiler.ProfileNode[]): void {\n if (nodes[0].children) {\n return;\n }\n nodes[0].children = [];\n for (let i = 1; i < nodes.length; ++i) {\n const node = nodes[i];\n // @ts-ignore Legacy types\n const parentNode = protocolNodeById.get(node.parent);\n // @ts-ignore Legacy types\n if (parentNode.children) {\n // @ts-ignore Legacy types\n parentNode.children.push(node.id);\n } else {\n // @ts-ignore Legacy types\n parentNode.children = [node.id];\n }\n }\n }\n\n /**\n * Calculate how many times each node was sampled in the profile, if\n * not available in the profile data.\n */\n function buildHitCountFromSamples(nodes: Protocol.Profiler.ProfileNode[], samples: number[]|undefined): void {\n // If hit count is available, this profile has the new format, so\n // no need to continue.`\n if (typeof (nodes[0].hitCount) === 'number') {\n return;\n }\n if (!samples) {\n throw new Error('Error: Neither hitCount nor samples are present in profile.');\n }\n for (let i = 0; i < nodes.length; ++i) {\n nodes[i].hitCount = 0;\n }\n for (let i = 0; i < samples.length; ++i) {\n const node = protocolNodeById.get(samples[i]);\n if (!node || node.hitCount === undefined) {\n continue;\n }\n node.hitCount++;\n }\n }\n\n // A cache for the raw nodes received from the traces / CDP.\n const protocolNodeById = new Map<number, Protocol.Profiler.ProfileNode>();\n for (let i = 0; i < nodes.length; ++i) {\n const node = nodes[i];\n protocolNodeById.set(node.id, node);\n }\n\n buildHitCountFromSamples(nodes, this.samples);\n buildChildrenFromParents(nodes);\n this.totalHitCount = nodes.reduce((acc, node) => acc + (node.hitCount || 0), 0);\n const sampleTime = (this.profileEndTime - this.profileStartTime) / this.totalHitCount;\n const root = nodes[0];\n // If a node is filtered out, its samples are replaced with its parent,\n // so we keep track of the which id to use in the samples data.\n const idToUseForRemovedNode = new Map<number, number>([[root.id, root.id]]);\n this.#idToParsedNode = new Map();\n\n const resultRoot = new CPUProfileNode(root, sampleTime);\n this.#idToParsedNode.set(root.id, resultRoot);\n if (!root.children) {\n throw new Error('Missing children for root');\n }\n const parentNodeStack = root.children.map(() => resultRoot);\n const sourceNodeStack = root.children.map(id => protocolNodeById.get(id));\n while (sourceNodeStack.length) {\n let parentNode = parentNodeStack.pop();\n const sourceNode = sourceNodeStack.pop();\n if (!sourceNode || !parentNode) {\n continue;\n }\n if (!sourceNode.children) {\n sourceNode.children = [];\n }\n const targetNode = new CPUProfileNode(sourceNode, sampleTime);\n parentNode.children.push(targetNode);\n parentNode = targetNode;\n\n idToUseForRemovedNode.set(sourceNode.id, parentNode.id);\n parentNodeStack.push.apply(parentNodeStack, sourceNode.children.map(() => parentNode as CPUProfileNode));\n sourceNodeStack.push.apply(sourceNodeStack, sourceNode.children.map(id => protocolNodeById.get(id)));\n this.#idToParsedNode.set(sourceNode.id, targetNode);\n }\n if (this.samples) {\n this.samples = this.samples.map(id => idToUseForRemovedNode.get(id) as number);\n }\n return resultRoot;\n }\n\n /**\n * Sorts the samples array using the timestamps array (there is a one\n * to one matching by index between the two).\n */\n private sortSamples(): void {\n if (!this.timestamps || !this.samples) {\n return;\n }\n\n const timestamps = this.timestamps;\n const samples = this.samples;\n const orderedIndices = timestamps.map((_x, index) => index);\n orderedIndices.sort((a, b) => timestamps[a] - timestamps[b]);\n\n this.timestamps = [];\n this.samples = [];\n\n for (let i = 0; i < orderedIndices.length; i++) {\n const orderedIndex = orderedIndices[i];\n this.timestamps.push(timestamps[orderedIndex]);\n this.samples.push(samples[orderedIndex]);\n }\n }\n\n /**\n * Fills in timestamps and/or time deltas from legacy profiles where\n * they could be missing.\n */\n private normalizeTimestamps(): void {\n if (!this.samples) {\n return;\n }\n let timestamps: number[] = this.timestamps;\n if (!timestamps) {\n // Support loading CPU profiles that are missing timestamps and\n // timedeltas\n const profileStartTime = this.profileStartTime;\n const interval = (this.profileEndTime - profileStartTime) / this.samples.length;\n // Add an extra timestamp used to calculate the last sample duration.\n timestamps = new Array(this.samples.length + 1);\n for (let i = 0; i < timestamps.length; ++i) {\n timestamps[i] = profileStartTime + i * interval;\n }\n this.timestamps = timestamps;\n return;\n }\n\n // Convert samples from micro to milliseconds\n for (let i = 0; i < timestamps.length; ++i) {\n timestamps[i] /= 1000;\n }\n if (this.samples.length === timestamps.length) {\n // Add an extra timestamp used to calculate the last sample duration.\n const lastTimestamp = timestamps.at(-1) || 0;\n const averageIntervalTime = (lastTimestamp - timestamps[0]) / (timestamps.length - 1);\n this.timestamps.push(lastTimestamp + averageIntervalTime);\n }\n this.profileStartTime = timestamps.at(0) || this.profileStartTime;\n this.profileEndTime = timestamps.at(-1) || this.profileEndTime;\n }\n\n /**\n * Some nodes do not refer to JS samples but to V8 system tasks, AKA\n * \"meta\" nodes. This function extracts those nodes from the profile.\n */\n private extractMetaNodes(): void {\n const topLevelNodes = this.profileHead.children;\n for (let i = 0; i < topLevelNodes.length && !(this.gcNode && this.programNode && this.idleNode); i++) {\n const node = topLevelNodes[i];\n if (node.functionName === '(garbage collector)') {\n this.gcNode = node;\n } else if (node.functionName === '(program)') {\n this.programNode = node;\n } else if (node.functionName === '(idle)') {\n this.idleNode = node;\n }\n }\n }\n\n private fixMissingSamples(): void {\n // Sometimes the V8 sampler is not able to parse the JS stack and returns\n // a (program) sample instead. The issue leads to call frames being split\n // apart when they shouldn't.\n // Here's a workaround for that. When there's a single (program) sample\n // between two call stacks sharing the same bottom node, it is replaced\n // with the preceeding sample.\n const samples = this.samples;\n if (!samples) {\n return;\n }\n const samplesCount = samples.length;\n if (!this.programNode || samplesCount < 3) {\n return;\n }\n const idToNode = this.#idToParsedNode;\n const programNodeId = this.programNode.id;\n const gcNodeId = this.gcNode ? this.gcNode.id : -1;\n const idleNodeId = this.idleNode ? this.idleNode.id : -1;\n let prevNodeId: number = samples[0];\n let nodeId: number = samples[1];\n for (let sampleIndex = 1; sampleIndex < samplesCount - 1; sampleIndex++) {\n const nextNodeId = samples[sampleIndex + 1];\n const prevNode = idToNode.get(prevNodeId);\n const nextNode = idToNode.get(nextNodeId);\n if (prevNodeId === undefined || nextNodeId === undefined || !prevNode || !nextNode) {\n console.error(`Unexpectedly found undefined nodes: ${prevNodeId} ${nextNodeId}`);\n continue;\n }\n if (nodeId === programNodeId && !isSystemNode(prevNodeId) && !isSystemNode(nextNodeId) &&\n bottomNode(prevNode) === bottomNode(nextNode)) {\n samples[sampleIndex] = prevNodeId;\n }\n prevNodeId = nodeId;\n nodeId = nextNodeId;\n }\n function bottomNode(node: ProfileNode): ProfileNode {\n while (node.parent && node.parent.parent) {\n node = node.parent;\n }\n return node;\n }\n function isSystemNode(nodeId: number): boolean {\n return nodeId === programNodeId || nodeId === gcNodeId || nodeId === idleNodeId;\n }\n }\n\n /**\n * Traverses the call tree derived from the samples calling back when a call is opened\n * and when it's closed\n */\n forEachFrame(\n openFrameCallback: (depth: number, node: ProfileNode, timestamp: number) => void,\n closeFrameCallback: (depth: number, node: ProfileNode, timestamp: number, dur: number, selfTime: number) => void,\n startTime?: number, stopTime?: number): void {\n if (!this.profileHead || !this.samples) {\n return;\n }\n\n startTime = startTime || 0;\n stopTime = stopTime || Infinity;\n const samples = this.samples;\n const timestamps = this.timestamps;\n const idToNode = this.#idToParsedNode;\n const gcNode = this.gcNode;\n const samplesCount = samples.length;\n const startIndex =\n Platform.ArrayUtilities.lowerBound(timestamps, startTime, Platform.ArrayUtilities.DEFAULT_COMPARATOR);\n let stackTop = 0;\n const stackNodes: ProfileNode[] = [];\n let prevId: number = this.profileHead.id;\n let sampleTime;\n let gcParentNode: ProfileNode|null = null;\n\n // Extra slots for gc being put on top,\n // and one at the bottom to allow safe stackTop-1 access.\n const stackDepth = this.maxDepth + 3;\n if (!this.#stackStartTimes) {\n this.#stackStartTimes = new Array(stackDepth);\n }\n const stackStartTimes = this.#stackStartTimes;\n if (!this.#stackChildrenDuration) {\n this.#stackChildrenDuration = new Array(stackDepth);\n }\n const stackChildrenDuration = this.#stackChildrenDuration;\n\n let node;\n let sampleIndex;\n for (sampleIndex = startIndex; sampleIndex < samplesCount; sampleIndex++) {\n sampleTime = timestamps[sampleIndex];\n if (sampleTime >= stopTime) {\n break;\n }\n const id = samples[sampleIndex];\n if (id === prevId) {\n continue;\n }\n node = idToNode.get(id);\n let prevNode: ProfileNode|null = idToNode.get(prevId) || null;\n if (!prevNode) {\n continue;\n }\n\n if (gcNode && node === gcNode) {\n // GC samples have no stack, so we just put GC node on top of the last recorded sample.\n gcParentNode = prevNode;\n openFrameCallback(gcParentNode.depth + 1, gcNode, sampleTime);\n stackStartTimes[++stackTop] = sampleTime;\n stackChildrenDuration[stackTop] = 0;\n prevId = id;\n continue;\n }\n if (gcNode && prevNode === gcNode && gcParentNode) {\n // end of GC frame\n const start = stackStartTimes[stackTop];\n const duration = sampleTime - start;\n stackChildrenDuration[stackTop - 1] += duration;\n closeFrameCallback(gcParentNode.depth + 1, gcNode, start, duration, duration - stackChildrenDuration[stackTop]);\n --stackTop;\n prevNode = gcParentNode;\n prevId = prevNode.id;\n gcParentNode = null;\n }\n\n // If the depth of this node is greater than the depth of the\n // previous one, new calls happened in between and we need to open\n // them, so track all of them in stackNodes.\n while (node && node.depth > prevNode.depth) {\n stackNodes.push(node);\n node = node.parent;\n }\n\n // If `prevNode` differs from `node`, the current sample was taken\n // after a change in the call stack, meaning that frames in the\n // path of `prevNode` that differ from those in the path of `node`\n // can be closed. So go down to the lowest common ancestor and\n // close current intervals.\n //\n // For example:\n //\n // prevNode node\n // | |\n // v v\n // [---D--]\n // [---C--][--E--]\n // [------B------] <- LCA\n // [------A------]\n //\n // Because a sample was taken with A, B and E in the stack, it\n // means C and D finished and we can close them.\n while (prevNode && prevNode !== node) {\n const start = stackStartTimes[stackTop];\n const duration = sampleTime - start;\n stackChildrenDuration[stackTop - 1] += duration;\n closeFrameCallback(prevNode.depth, prevNode, start, duration, duration - stackChildrenDuration[stackTop]);\n --stackTop;\n // Track calls to open after previous calls were closed\n // In the example above, this would add E to the tracking stack.\n if (node && node.depth === prevNode.depth) {\n stackNodes.push(node);\n node = node.parent;\n }\n prevNode = prevNode.parent;\n }\n\n // Go up the nodes stack and open new intervals.\n while (stackNodes.length) {\n const currentNode = stackNodes.pop();\n if (!currentNode) {\n break;\n }\n node = currentNode;\n openFrameCallback(currentNode.depth, currentNode, sampleTime);\n stackStartTimes[++stackTop] = sampleTime;\n stackChildrenDuration[stackTop] = 0;\n }\n\n prevId = id;\n }\n\n // Close remaining intervals.\n sampleTime = timestamps[sampleIndex] || this.profileEndTime;\n if (node && gcParentNode && idToNode.get(prevId) === gcNode) {\n const start = stackStartTimes[stackTop];\n const duration = sampleTime - start;\n stackChildrenDuration[stackTop - 1] += duration;\n closeFrameCallback(gcParentNode.depth + 1, node, start, duration, duration - stackChildrenDuration[stackTop]);\n --stackTop;\n prevId = gcParentNode.id;\n }\n for (let node = idToNode.get(prevId); node && node.parent; node = node.parent) {\n const start = stackStartTimes[stackTop];\n const duration = sampleTime - start;\n stackChildrenDuration[stackTop - 1] += duration;\n closeFrameCallback(node.depth, node, start, duration, duration - stackChildrenDuration[stackTop]);\n --stackTop;\n }\n }\n /**\n * Returns the node that corresponds to a given index of a sample.\n */\n nodeByIndex(index: number): ProfileNode|null {\n return this.samples && this.#idToParsedNode.get(this.samples[index]) || null;\n }\n /**\n * Returns the node that corresponds to a given node id.\n */\n nodeById(nodeId: number): ProfileNode|null {\n return this.#idToParsedNode.get(nodeId) || null;\n }\n\n nodes(): ProfileNode[]|null {\n if (!this.#idToParsedNode) {\n return null;\n }\n return [...this.#idToParsedNode.values()];\n }\n}\n\n// Format used by profiles coming from traces.\nexport type ExtendedProfileNode = Protocol.Profiler.ProfileNode&{parent?: number};\nexport type ExtendedProfile =\n Protocol.Profiler.Profile&{nodes: Protocol.Profiler.ProfileNode[] | ExtendedProfileNode[], lines?: number[]};\n", "// Copyright 2016 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../generated/protocol.js';\nimport type * as Platform from '../../core/platform/platform.js';\n\nexport class ProfileNode {\n callFrame: Protocol.Runtime.CallFrame;\n callUID: string;\n self: number;\n total: number;\n id: number;\n parent: ProfileNode|null;\n children: ProfileNode[];\n functionName: string;\n depth!: number;\n deoptReason!: string|null;\n constructor(callFrame: Protocol.Runtime.CallFrame) {\n this.callFrame = callFrame;\n this.callUID = `${callFrame.functionName}@${callFrame.scriptId}:${callFrame.lineNumber}:${callFrame.columnNumber}`;\n this.self = 0;\n this.total = 0;\n this.id = 0;\n this.functionName = callFrame.functionName;\n this.parent = null;\n this.children = [];\n }\n\n get scriptId(): Protocol.Runtime.ScriptId {\n return String(this.callFrame.scriptId) as Protocol.Runtime.ScriptId;\n }\n\n get url(): Platform.DevToolsPath.UrlString {\n return this.callFrame.url as Platform.DevToolsPath.UrlString;\n }\n\n get lineNumber(): number {\n return this.callFrame.lineNumber;\n }\n\n get columnNumber(): number {\n return this.callFrame.columnNumber;\n }\n\n setFunctionName(name: string|null): void {\n if (name === null) {\n return;\n }\n this.functionName = name;\n }\n}\n\nexport class ProfileTreeModel {\n root!: ProfileNode;\n total!: number;\n maxDepth!: number;\n constructor() {\n }\n\n initialize(root: ProfileNode): void {\n this.root = root;\n this.assignDepthsAndParents();\n this.total = this.calculateTotals(this.root);\n }\n\n private assignDepthsAndParents(): void {\n const root = this.root;\n // TODO(crbug.com/1354548): start depth from 0 once profiler\n // panel dependencies are gone.\n root.depth = -1;\n root.parent = null;\n this.maxDepth = 0;\n const nodesToTraverse = [root];\n while (nodesToTraverse.length) {\n const parent = (nodesToTraverse.pop() as ProfileNode);\n const depth = parent.depth + 1;\n if (depth > this.maxDepth) {\n this.maxDepth = depth;\n }\n const children = parent.children;\n for (const child of children) {\n child.depth = depth;\n child.parent = parent;\n nodesToTraverse.push(child);\n }\n }\n }\n\n private calculateTotals(root: ProfileNode): number {\n const nodesToTraverse = [root];\n const dfsList = [];\n while (nodesToTraverse.length) {\n const node = (nodesToTraverse.pop() as ProfileNode);\n node.total = node.self;\n dfsList.push(node);\n nodesToTraverse.push(...node.children);\n }\n while (dfsList.length > 1) {\n const node = (dfsList.pop() as ProfileNode);\n if (node.parent) {\n node.parent.total += node.total;\n }\n }\n return root.total;\n }\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n//\nimport type * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {type PartialTraceData} from './Migration.js';\nimport type * as Renderer from './RendererHandler.js';\n\nexport interface ThreadData {\n pid: Types.TraceEvents.ProcessID;\n tid: Types.TraceEvents.ThreadID;\n entries: readonly Types.TraceEvents.TraceEntry[];\n tree: Helpers.TreeHelpers.TraceEntryTree;\n type: ThreadType;\n name: string|null;\n entryToNode: Map<Types.TraceEvents.TraceEntry, Helpers.TreeHelpers.TraceEntryNode>;\n}\n\nexport const enum ThreadType {\n MAIN_THREAD = 'MAIN_THREAD',\n WORKER = 'WORKER',\n RASTERIZER = 'RASTERIZER',\n AUCTION_WORKLET = 'AUCTION_WORKLET',\n OTHER = 'OTHER',\n CPU_PROFILE = 'CPU_PROFILE',\n}\n\nfunction getThreadTypeForRendererThread(\n traceParseData: PartialTraceData, pid: Types.TraceEvents.ProcessID, thread: Renderer.RendererThread): ThreadType {\n let threadType = ThreadType.OTHER;\n if (thread.name === 'CrRendererMain') {\n threadType = ThreadType.MAIN_THREAD;\n } else if (thread.name === 'DedicatedWorker thread') {\n threadType = ThreadType.WORKER;\n } else if (thread.name?.startsWith('CompositorTileWorker')) {\n threadType = ThreadType.RASTERIZER;\n } else if (traceParseData.AuctionWorklets.worklets.has(pid)) {\n threadType = ThreadType.AUCTION_WORKLET;\n }\n return threadType;\n}\n\n/**\n * Given trace parsed data, this helper will return a high level array of\n * ThreadData. This is useful because it allows you to get a list of threads\n * regardless of if the trace is a CPU Profile or a Tracing profile. Thus you\n * can use this helper to iterate over threads in confidence that it will work\n * for both trace types.\n */\nexport function threadsInTrace(traceParseData: PartialTraceData): readonly ThreadData[] {\n const foundThreads: ThreadData[] = [];\n // If we have Renderer threads, we prefer to use those. In the event that a\n // trace is a CPU Profile trace, we will never have Renderer threads, so we\n // know if there are no Renderer threads that we can fallback to using the\n // data from the SamplesHandler.\n if (traceParseData.Renderer && traceParseData.Renderer.processes.size) {\n for (const [pid, process] of traceParseData.Renderer.processes) {\n for (const [tid, thread] of process.threads) {\n const threadType = getThreadTypeForRendererThread(traceParseData, pid, thread);\n if (!thread.tree) {\n // Drop threads where we could not create the tree; this indicates\n // unexpected data and we won't be able to support all the UI\n // filtering we need.\n continue;\n }\n foundThreads.push({\n name: thread.name,\n pid,\n tid,\n entries: thread.entries,\n tree: thread.tree,\n type: threadType,\n entryToNode: traceParseData.Renderer.entryToNode,\n });\n }\n }\n } else if (traceParseData.Samples && traceParseData.Samples.profilesInProcess.size) {\n for (const [pid, process] of traceParseData.Samples.profilesInProcess) {\n for (const [tid, thread] of process) {\n if (!thread.profileTree) {\n // Drop threads where we could not create the tree; this indicates\n // unexpected data and we won't be able to support all the UI\n // filtering we need.\n continue;\n }\n\n foundThreads.push({\n pid,\n tid,\n // CPU Profile threads do not have a name.\n name: null,\n entries: thread.profileCalls,\n tree: thread.profileTree,\n type: ThreadType.CPU_PROFILE,\n entryToNode: traceParseData.Samples.entryToNode,\n });\n }\n }\n }\n\n return foundThreads;\n}\n", "// Copyright 2014 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n//\n// This is what was SDK.TracingModel moved into models/trace to avoid circular dependency issues. Our ultimate goal is to remove this model entirely once the migration to the new model is done\n\n\n\nimport * as Helpers from './helpers/helpers.js';\nimport {type EventPayload} from './TracingManager.js';\nimport * as Types from './types/types.js';\n\ntype IgnoreListArgs = {\n [key: string]: string|number|ObjectSnapshot,\n};\n\nexport class TracingModel {\n readonly #title: string|undefined;\n readonly #processById: Map<string|number, Process>;\n readonly #processByName: Map<string, Process>;\n #minimumRecordTimeInternal: number;\n #maximumRecordTimeInternal: number;\n readonly #devToolsMetadataEventsInternal: Event[];\n #asyncEvents: AsyncEvent[];\n readonly #openAsyncEvents: Map<string, AsyncEvent>;\n readonly #openNestableAsyncEvents: Map<string, AsyncEvent[]>;\n readonly #profileGroups: Map<string, ProfileEventsGroup>;\n readonly #parsedCategories: Map<string, Set<string>>;\n readonly #allEventsPayload: EventPayload[] = [];\n\n constructor(title?: string) {\n this.#title = title;\n this.#processById = new Map();\n this.#processByName = new Map();\n this.#minimumRecordTimeInternal = Number(Infinity);\n this.#maximumRecordTimeInternal = Number(-Infinity);\n this.#devToolsMetadataEventsInternal = [];\n this.#asyncEvents = [];\n this.#openAsyncEvents = new Map();\n this.#openNestableAsyncEvents = new Map();\n this.#profileGroups = new Map();\n this.#parsedCategories = new Map();\n }\n\n static isTopLevelEvent(event: CompatibleTraceEvent): boolean {\n return eventHasCategory(event, DevToolsTimelineEventCategory) && event.name === 'RunTask' ||\n eventHasCategory(event, LegacyTopLevelEventCategory) ||\n eventHasCategory(event, DevToolsMetadataEventCategory) &&\n event.name === 'Program'; // Older timelines may have this instead of toplevel.\n }\n\n static extractId(payload: EventPayload): string|undefined {\n const scope = payload.scope || '';\n if (typeof payload.id2 === 'undefined') {\n return scope && payload.id ? `${scope}@${payload.id}` : payload.id;\n }\n const id2 = payload.id2;\n if (typeof id2 === 'object' && ('global' in id2) !== ('local' in id2)) {\n return typeof id2['global'] !== 'undefined' ? `:${scope}:${id2['global']}` :\n `:${scope}:${payload.pid}:${id2['local']}`;\n }\n console.error(\n `Unexpected id2 field at ${payload.ts / 1000}, one and only one of 'local' and 'global' should be present.`);\n return undefined;\n }\n\n static browserMainThread(tracingModel: TracingModel): Thread|null {\n const processes = tracingModel.sortedProcesses();\n // Avoid warning for an empty #model.\n if (!processes.length) {\n return null;\n }\n const browserMainThreadName = 'CrBrowserMain';\n const browserProcesses = [];\n const browserMainThreads = [];\n for (const process of processes) {\n if (process.name().toLowerCase().endsWith('browser')) {\n browserProcesses.push(process);\n }\n browserMainThreads.push(...process.sortedThreads().filter(t => t.name() === browserMainThreadName));\n }\n if (browserMainThreads.length === 1) {\n return browserMainThreads[0];\n }\n if (browserProcesses.length === 1) {\n return browserProcesses[0].threadByName(browserMainThreadName);\n }\n const tracingStartedInBrowser =\n tracingModel.devToolsMetadataEvents().filter(e => e.name === 'TracingStartedInBrowser');\n if (tracingStartedInBrowser.length === 1) {\n return tracingStartedInBrowser[0].thread;\n }\n console.error(\n 'Failed to find browser main thread in trace, some timeline features may be unavailable');\n return null;\n }\n\n allRawEvents(): readonly EventPayload[] {\n return this.#allEventsPayload;\n }\n\n devToolsMetadataEvents(): Event[] {\n return this.#devToolsMetadataEventsInternal;\n }\n\n addEvents(events: readonly EventPayload[]): void {\n for (let i = 0; i < events.length; ++i) {\n this.addEvent(events[i]);\n }\n }\n\n tracingComplete(): void {\n this.processPendingAsyncEvents();\n for (const process of this.#processById.values()) {\n for (const thread of process.threads.values()) {\n thread.tracingComplete();\n }\n }\n }\n\n private addEvent(payload: EventPayload): void {\n this.#allEventsPayload.push(payload);\n let process = this.#processById.get(payload.pid);\n if (!process) {\n process = new Process(this, payload.pid);\n this.#processById.set(payload.pid, process);\n }\n\n const timestamp = payload.ts / 1000;\n // We do allow records for unrelated threads to arrive out-of-order,\n // so there's a chance we're getting records from the past.\n if (timestamp && timestamp < this.#minimumRecordTimeInternal &&\n eventPhasesOfInterestForTraceBounds.has(payload.ph as Types.TraceEvents.Phase) &&\n // UMA related events are ignored when calculating the minimumRecordTime because they might\n // be related to previous navigations that happened before the current trace started and\n // will currently not be displayed anyways.\n // See crbug.com/1201198\n (!payload.name.endsWith('::UMA'))) {\n this.#minimumRecordTimeInternal = timestamp;\n }\n\n if (payload.name === 'TracingStartedInBrowser') {\n // If we received a timestamp for tracing start, use that for minimumRecordTime.\n this.#minimumRecordTimeInternal = timestamp;\n }\n\n if (eventPhasesOfInterestForTraceBounds.has(payload.ph as Types.TraceEvents.Phase)) {\n const endTimeStamp = (payload.ts + (payload.dur || 0)) / 1000;\n this.#maximumRecordTimeInternal = Math.max(this.#maximumRecordTimeInternal, endTimeStamp);\n }\n const event = process.addEvent(payload);\n if (!event) {\n return;\n }\n if (payload.ph === Types.TraceEvents.Phase.SAMPLE) {\n this.addSampleEvent(event);\n return;\n }\n // Build async event when we've got events from all threads & processes, so we can sort them and process in the\n // chronological order. However, also add individual async events to the thread flow (above), so we can easily\n // display them on the same chart as other events, should we choose so.\n if (Types.TraceEvents.isAsyncPhase(payload.ph)) {\n this.#asyncEvents.push((event as AsyncEvent));\n }\n if (event.hasCategory(DevToolsMetadataEventCategory)) {\n this.#devToolsMetadataEventsInternal.push(event);\n }\n\n if (payload.ph !== Types.TraceEvents.Phase.METADATA) {\n return;\n }\n\n switch (payload.name) {\n case MetadataEvent.ProcessSortIndex: {\n process.setSortIndex(payload.args['sort_index']);\n break;\n }\n case MetadataEvent.ProcessName: {\n const processName = payload.args['name'];\n process.setName(processName);\n this.#processByName.set(processName, process);\n break;\n }\n case MetadataEvent.ThreadSortIndex: {\n process.threadById(payload.tid).setSortIndex(payload.args['sort_index']);\n break;\n }\n case MetadataEvent.ThreadName: {\n process.threadById(payload.tid).setName(payload.args['name']);\n break;\n }\n }\n }\n\n private addSampleEvent(event: Event): void {\n const id = `${event.thread.process().id()}:${event.id}`;\n const group = this.#profileGroups.get(id);\n if (group) {\n group.addChild(event);\n } else {\n this.#profileGroups.set(id, new ProfileEventsGroup(event));\n }\n }\n\n profileGroup(event: Event): ProfileEventsGroup|null {\n return this.#profileGroups.get(`${event.thread.process().id()}:${event.id}`) || null;\n }\n\n minimumRecordTime(): number {\n return this.#minimumRecordTimeInternal;\n }\n\n maximumRecordTime(): number {\n return this.#maximumRecordTimeInternal;\n }\n\n sortedProcesses(): Process[] {\n return NamedObject.sort([...this.#processById.values()]);\n }\n\n getProcessByName(name: string): Process|null {\n return this.#processByName.get(name) ?? null;\n }\n\n getProcessById(pid: number): Process|null {\n return this.#processById.get(pid) || null;\n }\n\n getThreadByName(processName: string, threadName: string): Thread|null {\n const process = this.getProcessByName(processName);\n return process && process.threadByName(threadName);\n }\n\n private processPendingAsyncEvents(): void {\n this.#asyncEvents.sort(Event.compareStartTime);\n for (let i = 0; i < this.#asyncEvents.length; ++i) {\n const event = this.#asyncEvents[i];\n if (Types.TraceEvents.isNestableAsyncPhase(event.phase)) {\n this.addNestableAsyncEvent(event);\n } else {\n this.addAsyncEvent(event);\n }\n }\n this.#asyncEvents = [];\n this.closeOpenAsyncEvents();\n }\n\n private closeOpenAsyncEvents(): void {\n for (const event of this.#openAsyncEvents.values()) {\n event.setEndTime(this.#maximumRecordTimeInternal);\n // FIXME: remove this once we figure a better way to convert async console\n // events to sync [waterfall] timeline records.\n event.steps[0].setEndTime(this.#maximumRecordTimeInternal);\n }\n this.#openAsyncEvents.clear();\n\n for (const eventStack of this.#openNestableAsyncEvents.values()) {\n while (eventStack.length) {\n const event = eventStack.pop();\n if (!event) {\n continue;\n }\n event.setEndTime(this.#maximumRecordTimeInternal);\n }\n }\n this.#openNestableAsyncEvents.clear();\n }\n\n private addNestableAsyncEvent(event: Event): void {\n const key = event.categoriesString + '.' + event.id;\n let openEventsStack = this.#openNestableAsyncEvents.get(key);\n\n switch (event.phase) {\n case Types.TraceEvents.Phase.ASYNC_NESTABLE_START: {\n if (!openEventsStack) {\n openEventsStack = [];\n this.#openNestableAsyncEvents.set(key, openEventsStack);\n }\n const asyncEvent = new AsyncEvent(event);\n openEventsStack.push(asyncEvent);\n event.thread.addAsyncEvent(asyncEvent);\n break;\n }\n\n case Types.TraceEvents.Phase.ASYNC_NESTABLE_INSTANT: {\n if (openEventsStack && openEventsStack.length) {\n const event = openEventsStack[openEventsStack.length - 1];\n if (event) {\n event.addStep(event);\n }\n }\n break;\n }\n\n case Types.TraceEvents.Phase.ASYNC_NESTABLE_END: {\n if (!openEventsStack || !openEventsStack.length) {\n break;\n }\n const top = openEventsStack.pop();\n if (!top) {\n break;\n }\n if (top.name !== event.name) {\n console.error(\n `Begin/end event mismatch for nestable async event, ${top.name} vs. ${event.name}, key: ${key}`);\n break;\n }\n top.addStep(event);\n }\n }\n }\n\n private addAsyncEvent(event: Event): void {\n const key = event.categoriesString + '.' + event.name + '.' + event.id;\n let asyncEvent = this.#openAsyncEvents.get(key);\n\n if (event.phase === Types.TraceEvents.Phase.ASYNC_BEGIN) {\n if (asyncEvent) {\n console.error(`Event ${event.name} has already been started`);\n return;\n }\n asyncEvent = new AsyncEvent(event);\n this.#openAsyncEvents.set(key, asyncEvent);\n event.thread.addAsyncEvent(asyncEvent);\n return;\n }\n if (!asyncEvent) {\n // Quietly ignore stray async events, we're probably too late for the start.\n return;\n }\n if (event.phase === Types.TraceEvents.Phase.ASYNC_END) {\n asyncEvent.addStep(event);\n this.#openAsyncEvents.delete(key);\n return;\n }\n if (event.phase === Types.TraceEvents.Phase.ASYNC_STEP_INTO ||\n event.phase === Types.TraceEvents.Phase.ASYNC_STEP_PAST) {\n const lastStep = asyncEvent.steps[asyncEvent.steps.length - 1];\n if (lastStep && lastStep.phase !== Types.TraceEvents.Phase.ASYNC_BEGIN && lastStep.phase !== event.phase) {\n console.assert(\n false,\n 'Async event step phase mismatch: ' + lastStep.phase + ' at ' + lastStep.startTime + ' vs. ' + event.phase +\n ' at ' + event.startTime);\n return;\n }\n asyncEvent.addStep(event);\n return;\n }\n console.assert(false, 'Invalid async event phase');\n }\n\n title(): string|undefined {\n return this.#title;\n }\n\n parsedCategoriesForString(str: string): Set<string> {\n let parsedCategories = this.#parsedCategories.get(str);\n if (!parsedCategories) {\n parsedCategories = new Set(str ? str.split(',') : []);\n this.#parsedCategories.set(str, parsedCategories);\n }\n return parsedCategories;\n }\n}\n\nexport const eventPhasesOfInterestForTraceBounds: Set<Types.TraceEvents.Phase> = new Set([\n Types.TraceEvents.Phase.BEGIN,\n Types.TraceEvents.Phase.END,\n Types.TraceEvents.Phase.COMPLETE,\n Types.TraceEvents.Phase.INSTANT,\n]);\n\nexport const MetadataEvent = {\n ProcessSortIndex: 'process_sort_index',\n ProcessName: 'process_name',\n ThreadSortIndex: 'thread_sort_index',\n ThreadName: 'thread_name',\n};\n\n// TODO(alph): LegacyTopLevelEventCategory is not recorded since M74 and used for loading\n// legacy profiles. Drop at some point.\nexport const LegacyTopLevelEventCategory = 'toplevel';\n\nexport const DevToolsMetadataEventCategory = 'disabled-by-default-devtools.timeline';\nexport const DevToolsTimelineEventCategory = 'disabled-by-default-devtools.timeline';\n\nexport function eventHasPayload(event: Event): event is PayloadEvent {\n return 'rawPayload' in event;\n}\n\nexport class Event {\n categoriesString: string;\n readonly #parsedCategories: Set<string>;\n name: string;\n phase: Types.TraceEvents.Phase;\n startTime: number;\n thread: Thread;\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n args: any;\n id!: string|null;\n ordinal: number;\n selfTime: number;\n endTime?: number;\n duration?: number;\n\n // The constructor is protected so that we ensure that only classes or\n // subclasses can directly instantiate events. All other callers should\n // either create ConstructedEvent instances, which have a public constructor,\n // or use the static fromPayload method which can create an event instance\n // from the trace payload.\n protected constructor(\n categories: string|undefined, name: string, phase: Types.TraceEvents.Phase, startTime: number, thread: Thread) {\n this.categoriesString = categories || '';\n this.#parsedCategories = thread.getModel().parsedCategoriesForString(this.categoriesString);\n this.name = name;\n this.phase = phase;\n this.startTime = startTime;\n this.thread = thread;\n this.args = {};\n this.ordinal = 0;\n\n this.selfTime = 0;\n }\n\n static compareStartTime(a: Event|null, b: Event|null): number {\n if (!a || !b) {\n return 0;\n }\n\n return a.startTime - b.startTime;\n }\n\n static orderedCompareStartTime(a: Event, b: Event): number {\n // Array.mergeOrdered coalesces objects if comparator returns 0.\n // To change this behavior this comparator return -1 in the case events\n // startTime's are equal, so both events got placed into the result array.\n return a.startTime - b.startTime || a.ordinal - b.ordinal || -1;\n }\n\n hasCategory(categoryName: string): boolean {\n return this.#parsedCategories.has(categoryName);\n }\n\n setEndTime(endTime: number): void {\n if (endTime < this.startTime) {\n console.assert(false, 'Event out of order: ' + this.name);\n return;\n }\n this.endTime = endTime;\n this.duration = endTime - this.startTime;\n }\n\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n addArgs(args: any): void {\n // Shallow copy args to avoid modifying original #payload which may be saved to file.\n for (const name in args) {\n if (name in this.args) {\n console.error('Same argument name (' + name + ') is used for begin and end phases of ' + this.name);\n }\n\n (this.args as IgnoreListArgs)[name] = (args as IgnoreListArgs)[name];\n }\n }\n\n complete(endEvent: Event): void {\n if (endEvent.args) {\n this.addArgs(endEvent.args);\n } else {\n console.error('Missing mandatory event argument \\'args\\' at ' + endEvent.startTime);\n }\n this.setEndTime(endEvent.startTime);\n }\n}\n\n/**\n * Represents a tracing event that is not directly linked to an individual\n * object in the trace. We construct these events at times, particularly when\n * building up the CPU profile data for JS Profiling.\n **/\nexport class ConstructedEvent extends Event {\n // Because the constructor of Event is marked as protected, but we want\n // people to be able to create constructed events, we override the\n // constructor here, even though we are only calling super, in order to mark\n // it as public.\n constructor(\n categories: string|undefined, name: string, phase: Types.TraceEvents.Phase, startTime: number, thread: Thread) {\n super(categories, name, phase, startTime, thread);\n }\n}\n\n/**\n * Represents a tracing event that has been created directly from an object in\n * the trace file and therefore is guaranteed to have a payload associated with\n * it. The only way to create these events is to use the static fromPayload\n * method, which you must call with a payload.\n **/\nexport class PayloadEvent extends Event {\n #rawPayload: EventPayload;\n\n /**\n * Returns the raw payload that was used to create this event instance.\n **/\n rawLegacyPayload(): EventPayload {\n return this.#rawPayload;\n }\n\n /**\n * Returns the raw payload that was used to create this event instance, but\n * returns it typed as the new engine's TraceEventArgs option.\n **/\n rawPayload(): Types.TraceEvents.TraceEventData {\n return this.#rawPayload as unknown as Types.TraceEvents.TraceEventData;\n }\n\n protected constructor(\n categories: string|undefined, name: string, phase: Types.TraceEvents.Phase, startTime: number, thread: Thread,\n rawPayload: EventPayload) {\n super(categories, name, phase, startTime, thread);\n this.#rawPayload = rawPayload;\n }\n\n static fromPayload(payload: EventPayload, thread: Thread): PayloadEvent {\n const event = new PayloadEvent(payload.cat, payload.name, payload.ph, payload.ts / 1000, thread, payload);\n event.#rawPayload = payload;\n if (payload.args) {\n event.addArgs(payload.args);\n }\n if (typeof payload.dur === 'number') {\n event.setEndTime((payload.ts + payload.dur) / 1000);\n }\n const id = TracingModel.extractId(payload);\n if (typeof id !== 'undefined') {\n event.id = id;\n }\n\n return event;\n }\n}\n\nexport class ObjectSnapshot extends PayloadEvent {\n private constructor(\n category: string|undefined, name: string, startTime: number, thread: Thread, rawPayload: EventPayload) {\n super(category, name, Types.TraceEvents.Phase.OBJECT_SNAPSHOT, startTime, thread, rawPayload);\n }\n\n static override fromPayload(payload: EventPayload, thread: Thread): ObjectSnapshot {\n const snapshot = new ObjectSnapshot(payload.cat, payload.name, payload.ts / 1000, thread, payload);\n const id = TracingModel.extractId(payload);\n if (typeof id !== 'undefined') {\n snapshot.id = id;\n }\n if (!payload.args || !payload.args['snapshot']) {\n console.error('Missing mandatory \\'snapshot\\' argument at ' + payload.ts / 1000);\n return snapshot;\n }\n if (payload.args) {\n snapshot.addArgs(payload.args);\n }\n return snapshot;\n }\n\n getSnapshot(): ObjectSnapshot {\n const snapshot = this.args['snapshot'];\n if (!snapshot) {\n throw new Error('ObjectSnapshot has no snapshot argument.');\n }\n return snapshot;\n }\n}\n\nexport class AsyncEvent extends ConstructedEvent {\n steps: Event[];\n causedFrame: boolean;\n\n constructor(startEvent: Event) {\n super(startEvent.categoriesString, startEvent.name, startEvent.phase, startEvent.startTime, startEvent.thread);\n this.addArgs(startEvent.args);\n this.steps = [startEvent];\n this.causedFrame = false;\n }\n\n addStep(event: Event): void {\n this.steps.push(event);\n if (event.phase === Types.TraceEvents.Phase.ASYNC_END ||\n event.phase === Types.TraceEvents.Phase.ASYNC_NESTABLE_END) {\n this.setEndTime(event.startTime);\n // FIXME: ideally, we shouldn't do this, but this makes the logic of converting\n // async console events to sync ones much simpler.\n this.steps[0].setEndTime(event.startTime);\n }\n }\n}\n\nclass ProfileEventsGroup {\n children: Event[];\n constructor(event: Event) {\n this.children = [event];\n }\n\n addChild(event: Event): void {\n this.children.push(event);\n }\n}\n\nclass NamedObject {\n model: TracingModel;\n readonly idInternal: number;\n #nameInternal: string;\n #sortIndex: number;\n constructor(model: TracingModel, id: number) {\n this.model = model;\n this.idInternal = id;\n this.#nameInternal = '';\n this.#sortIndex = 0;\n }\n\n static sort<Item extends NamedObject>(array: Item[]): Item[] {\n return array.sort((a, b) => {\n return a.#sortIndex !== b.#sortIndex ? a.#sortIndex - b.#sortIndex : a.name().localeCompare(b.name());\n });\n }\n\n setName(name: string): void {\n this.#nameInternal = name;\n }\n\n name(): string {\n return this.#nameInternal;\n }\n\n id(): number {\n return this.idInternal;\n }\n\n setSortIndex(sortIndex: number): void {\n this.#sortIndex = sortIndex;\n }\n\n getModel(): TracingModel {\n return this.model;\n }\n}\n\nexport class Process extends NamedObject {\n readonly threads: Map<number, Thread>;\n readonly #threadByNameInternal: Map<string, Thread|null>;\n constructor(model: TracingModel, id: number) {\n super(model, id);\n this.threads = new Map();\n this.#threadByNameInternal = new Map();\n }\n\n threadById(id: number): Thread {\n let thread = this.threads.get(id);\n if (!thread) {\n thread = new Thread(this, id);\n this.threads.set(id, thread);\n }\n return thread;\n }\n\n threadByName(name: string): Thread|null {\n return this.#threadByNameInternal.get(name) || null;\n }\n\n setThreadByName(name: string, thread: Thread): void {\n this.#threadByNameInternal.set(name, thread);\n }\n\n addEvent(payload: EventPayload): Event|null {\n return this.threadById(payload.tid).addEvent(payload);\n }\n\n sortedThreads(): Thread[] {\n return NamedObject.sort([...this.threads.values()]);\n }\n}\n\nexport class Thread extends NamedObject {\n readonly #processInternal: Process;\n #eventsInternal: Event[];\n readonly #asyncEventsInternal: AsyncEvent[];\n #lastTopLevelEvent: Event|null;\n constructor(process: Process, id: number) {\n super(process.getModel(), id);\n this.#processInternal = process;\n\n this.#eventsInternal = [];\n this.#asyncEventsInternal = [];\n this.#lastTopLevelEvent = null;\n }\n\n /**\n * Whilst we are in the middle of migrating to the new Phase enum, we need to\n * be able to compare events with the legacy phase to the new enum. This method\n * does this by casting the event phase to a string, ensuring we can compare it\n * against either enum. Once the migration is complete (crbug.com/1417587), we\n * will be able to use === to compare with no TS errors and this method can be\n * removed.\n */\n #eventMatchesPhase(event: Event, phase: Types.TraceEvents.Phase): boolean {\n return (event.phase as string) === phase;\n }\n\n tracingComplete(): void {\n this.#asyncEventsInternal.sort(Event.compareStartTime);\n this.#eventsInternal.sort(Event.compareStartTime);\n const stack: Event[] = [];\n const toDelete = new Set<number>();\n for (let i = 0; i < this.#eventsInternal.length; ++i) {\n const e = this.#eventsInternal[i];\n e.ordinal = i;\n if (this.#eventMatchesPhase(e, Types.TraceEvents.Phase.END)) {\n toDelete.add(i); // Mark for removal.\n // Quietly ignore unbalanced close events, they're legit (we could have missed start one).\n if (!stack.length) {\n continue;\n }\n const top = stack.pop();\n if (!top) {\n continue;\n }\n if (top.name !== e.name || top.categoriesString !== e.categoriesString) {\n console.error(\n 'B/E events mismatch at ' + top.startTime + ' (' + top.name + ') vs. ' + e.startTime + ' (' + e.name +\n ')');\n } else {\n top.complete(e);\n }\n } else if (this.#eventMatchesPhase(e, Types.TraceEvents.Phase.BEGIN)) {\n stack.push(e);\n }\n }\n\n // Handle Begin events with no matching End.\n // This commonly happens due to a bug in the trace machinery. See crbug.com/982252\n while (stack.length) {\n const event = stack.pop();\n if (event) {\n // Masquerade the event as Instant, so it's rendered to the user.\n // The ideal fix is resolving crbug.com/1021571, but handling that without a perfetto migration appears prohibitive\n event.phase = Types.TraceEvents.Phase.INSTANT;\n }\n }\n this.#eventsInternal = this.#eventsInternal.filter((_, idx) => !toDelete.has(idx));\n }\n\n addEvent(payload: EventPayload): Event|null {\n const event = payload.ph === Types.TraceEvents.Phase.OBJECT_SNAPSHOT ? ObjectSnapshot.fromPayload(payload, this) :\n PayloadEvent.fromPayload(payload, this);\n if (TracingModel.isTopLevelEvent(event)) {\n // Discard nested \"top-level\" events.\n const lastTopLevelEvent = this.#lastTopLevelEvent;\n if (lastTopLevelEvent && (lastTopLevelEvent.endTime || 0) > event.startTime) {\n return null;\n }\n this.#lastTopLevelEvent = event;\n }\n this.#eventsInternal.push(event);\n return event;\n }\n\n addAsyncEvent(asyncEvent: AsyncEvent): void {\n this.#asyncEventsInternal.push(asyncEvent);\n }\n\n override setName(name: string): void {\n super.setName(name);\n this.#processInternal.setThreadByName(name, this);\n }\n\n process(): Process {\n return this.#processInternal;\n }\n\n events(): Event[] {\n return this.#eventsInternal;\n }\n\n asyncEvents(): AsyncEvent[] {\n return this.#asyncEventsInternal;\n }\n\n removeEventsByName(name: string): Event[] {\n const extracted: Event[] = [];\n this.#eventsInternal = this.#eventsInternal.filter(e => {\n if (!e) {\n return false;\n }\n\n if (e.name !== name) {\n return true;\n }\n\n extracted.push(e);\n return false;\n });\n\n return extracted;\n }\n}\n\nexport interface TimesForEventMs {\n startTime: Types.Timing.MilliSeconds;\n endTime?: Types.Timing.MilliSeconds;\n selfTime: Types.Timing.MilliSeconds;\n duration: Types.Timing.MilliSeconds;\n}\n\nexport function timesForEventInMilliseconds(event: Event|Types.TraceEvents.TraceEventData): TimesForEventMs {\n if (event instanceof Event) {\n return {\n startTime: Types.Timing.MilliSeconds(event.startTime),\n endTime: event.endTime ? Types.Timing.MilliSeconds(event.endTime) : undefined,\n duration: Types.Timing.MilliSeconds(event.duration || 0),\n selfTime: Types.Timing.MilliSeconds(event.selfTime),\n };\n }\n return Helpers.Timing.eventTimingsMilliSeconds(event);\n}\n// Parsed categories are cached to prevent calling cat.split() multiple\n// times on the same categories string.\nconst parsedCategories = new Map<string, Set<string>>();\nexport function eventHasCategory(event: CompatibleTraceEvent, category: string): boolean {\n if (event instanceof Event) {\n return event.hasCategory(category);\n }\n let parsedCategoriesForEvent = parsedCategories.get(event.cat);\n if (!parsedCategoriesForEvent) {\n parsedCategoriesForEvent = new Set(event.cat.split(',') || []);\n }\n return parsedCategoriesForEvent.has(category);\n}\n\nexport function phaseForEvent(event: Event|Types.TraceEvents.TraceEventData): Types.TraceEvents.Phase {\n if (event instanceof Event) {\n return event.phase;\n }\n return event.ph;\n}\n\nexport function threadIDForEvent(event: Event|Types.TraceEvents.TraceEventData): Types.TraceEvents.ThreadID {\n if (event instanceof Event) {\n return event.thread.idInternal as Types.TraceEvents.ThreadID;\n }\n return event.tid;\n}\n\nexport function eventIsFromNewEngine(event: CompatibleTraceEvent|null): event is Types.TraceEvents.TraceEventData {\n return event !== null && !(event instanceof Event);\n}\n\nexport type CompatibleTraceEvent = Event|Types.TraceEvents.TraceEventData;\n", "// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../core/platform/platform.js';\n\nimport * as Handlers from './handlers/handlers.js';\nimport * as Helpers from './helpers/helpers.js';\nimport {TraceParseProgressEvent, TraceProcessor} from './Processor.js';\nimport * as Types from './types/types.js';\n\n// Note: this model is implemented in a way that can support multiple trace\n// processors. Currently there is only one implemented, but you will see\n// references to \"processors\" plural because it can easily be extended in the future.\n\nexport interface ParseConfig {\n metadata?: Types.File.MetaData;\n // Unused but will eventually be consumed by UIUtils Linkifier, etc.\n isFreshRecording?: boolean;\n}\n\n/**\n * The new trace engine model we are migrating to. The Model is responsible for\n * parsing arrays of raw trace events and storing the resulting data. It can\n * store multiple traces at once, and can return the data for any of them.\n * Currently as we migrate from the old engine to this, we are turning on the\n * model handlers incrementally as we need the data, to save performance costs\n * of running handlers that we do not use. Therefore, when the model is\n * constructed we pass through a set of handlers that should be used. Once we\n * have migrated all tracks in the Performance Panel to this model, we can\n * remove this ability to run a subset of handlers, as we will need all handlers\n * to be used at that point. For tests, if you want to construct a model with\n * all handlers, you can use the static `Model.createWithAllHandlers` method.\n **/\nexport class Model<EnabledModelHandlers extends {[key: string]: Handlers.Types.TraceEventHandler}> extends EventTarget {\n readonly #traces: ParsedTraceFile<EnabledModelHandlers>[] = [];\n readonly #nextNumberByDomain = new Map<string, number>();\n\n readonly #recordingsAvailable: string[] = [];\n #lastRecordingIndex = 0;\n #processor: TraceProcessor<Handlers.Types.HandlersWithMeta<EnabledModelHandlers>>;\n #config: Types.Configuration.Configuration = Types.Configuration.DEFAULT;\n\n static createWithAllHandlers(config?: Types.Configuration.Configuration): Model<typeof Handlers.ModelHandlers> {\n return new Model(Handlers.ModelHandlers, config);\n }\n\n static createWithRequiredHandlersForMigration(config?: Types.Configuration.Configuration): Model<{\n [K in keyof typeof Handlers.Migration.ENABLED_TRACE_HANDLERS]: typeof Handlers.Migration.ENABLED_TRACE_HANDLERS[K];\n }> {\n return new Model(Handlers.Migration.ENABLED_TRACE_HANDLERS, config);\n }\n\n constructor(handlers: EnabledModelHandlers, config?: Types.Configuration.Configuration) {\n super();\n if (config) {\n this.#config = config;\n }\n this.#processor = new TraceProcessor(handlers, this.#config);\n }\n\n /**\n * Updates the configuration. Useful if a user changes a setting - this lets\n * us update the model without having to destroy it and recreate it with the\n * new settings.\n */\n updateConfiguration(config: Types.Configuration.Configuration): void {\n this.#config = config;\n this.#processor.updateConfiguration(config);\n }\n\n /**\n * Parses an array of trace events into a structured object containing all the\n * information parsed by the trace handlers.\n * You can `await` this function to pause execution until parsing is complete,\n * or instead rely on the `ModuleUpdateEvent` that is dispatched when the\n * parsing is finished.\n *\n * Once parsed, you then have to call the `traceParsedData` method, providing an\n * index of the trace you want to have the data for. This is because any model\n * can store a number of traces. Each trace is given an index, which starts at 0\n * and increments by one as a new trace is parsed.\n *\n * @example\n * // Awaiting the parse method() to block until parsing complete\n * await this.traceModel.parse(events);\n * const data = this.traceModel.traceParsedData(0)\n *\n * @example\n * // Using an event listener to be notified when tracing is complete.\n * this.traceModel.addEventListener(Trace.ModelUpdateEvent.eventName, (event) => {\n * if(event.data.data === 'done') {\n * // trace complete\n * const data = this.traceModel.traceParsedData(0);\n * }\n * });\n * void this.traceModel.parse(events);\n **/\n async parse(traceEvents: readonly Types.TraceEvents.TraceEventData[], config?: ParseConfig): Promise<void> {\n const metadata = config?.metadata || {};\n const isFreshRecording = config?.isFreshRecording || false;\n // During parsing, periodically update any listeners on each processors'\n // progress (if they have any updates).\n const onTraceUpdate = (event: Event): void => {\n const {data} = event as TraceParseProgressEvent;\n this.dispatchEvent(new ModelUpdateEvent({type: ModelUpdateType.PROGRESS_UPDATE, data: data}));\n };\n\n this.#processor.addEventListener(TraceParseProgressEvent.eventName, onTraceUpdate);\n\n // Create a parsed trace file. It will be populated with data from the processor.\n const file: ParsedTraceFile<EnabledModelHandlers> = {\n traceEvents,\n metadata,\n traceParsedData: null,\n };\n\n try {\n // Wait for all outstanding promises before finishing the async execution,\n // but perform all tasks in parallel.\n await this.#processor.parse(traceEvents, isFreshRecording);\n this.#storeParsedFileData(file, this.#processor.data);\n // We only push the file onto this.#traces here once we know it's valid\n // and there's been no errors in the parsing.\n this.#traces.push(file);\n } catch (e) {\n throw e;\n } finally {\n // All processors have finished parsing, no more updates are expected.\n this.#processor.removeEventListener(TraceParseProgressEvent.eventName, onTraceUpdate);\n // Finally, update any listeners that all processors are 'done'.\n this.dispatchEvent(new ModelUpdateEvent({type: ModelUpdateType.COMPLETE, data: 'done'}));\n }\n }\n\n #storeParsedFileData(\n file: ParsedTraceFile<EnabledModelHandlers>,\n data: Handlers.Types.EnabledHandlerDataWithMeta<EnabledModelHandlers>|null): void {\n file.traceParsedData = data;\n this.#lastRecordingIndex++;\n let recordingName = `Trace ${this.#lastRecordingIndex}`;\n let origin: string|null = null;\n if (file.traceParsedData) {\n origin = Helpers.Trace.extractOriginFromTrace(file.traceParsedData.Meta.mainFrameURL);\n if (origin) {\n const nextSequenceForDomain = Platform.MapUtilities.getWithDefault(this.#nextNumberByDomain, origin, () => 1);\n recordingName = `${origin} (${nextSequenceForDomain})`;\n this.#nextNumberByDomain.set(origin, nextSequenceForDomain + 1);\n }\n }\n this.#recordingsAvailable.push(recordingName);\n }\n\n /**\n * Returns the parsed trace data indexed by the order in which it was stored.\n * If no index is given, the last stored parsed data is returned.\n */\n traceParsedData(index: number = this.#traces.length - 1):\n Handlers.Types.EnabledHandlerDataWithMeta<EnabledModelHandlers>|null {\n if (!this.#traces[index]) {\n return null;\n }\n\n return this.#traces[index].traceParsedData;\n }\n\n metadata(index: number): Types.File.MetaData|null {\n if (!this.#traces[index]) {\n return null;\n }\n\n return this.#traces[index].metadata;\n }\n\n traceEvents(index: number): readonly Types.TraceEvents.TraceEventData[]|null {\n if (!this.#traces[index]) {\n return null;\n }\n\n return this.#traces[index].traceEvents;\n }\n\n size(): number {\n return this.#traces.length;\n }\n\n deleteTraceByIndex(recordingIndex: number): void {\n this.#traces.splice(recordingIndex, 1);\n this.#recordingsAvailable.splice(recordingIndex, 1);\n }\n\n getRecordingsAvailable(): string[] {\n return this.#recordingsAvailable;\n }\n\n resetProcessor(): void {\n this.#processor.reset();\n }\n}\n\n/**\n * This parsed trace file is used by the Model. It keeps multiple instances\n * of these so that the user can swap between them. The key is that it is\n * essentially the TraceFile plus whatever the model has parsed from it.\n */\nexport type ParsedTraceFile<Handlers extends {[key: string]: Handlers.Types.TraceEventHandler}> = Types.File.TraceFile&{\n traceParsedData: Handlers.Types.EnabledHandlerDataWithMeta<Handlers>| null,\n};\n\nexport const enum ModelUpdateType {\n COMPLETE = 'COMPLETE',\n PROGRESS_UPDATE = 'PROGRESS_UPDATE',\n}\n\nexport type ModelUpdateEventData = ModelUpdateEventComplete|ModelUpdateEventProgress;\n\nexport type ModelUpdateEventComplete = {\n type: ModelUpdateType.COMPLETE,\n data: 'done',\n};\nexport type ModelUpdateEventProgress = {\n type: ModelUpdateType.PROGRESS_UPDATE,\n data: TraceParseEventProgressData,\n};\n\nexport type TraceParseEventProgressData = {\n index: number,\n total: number,\n};\n\nexport class ModelUpdateEvent extends Event {\n static readonly eventName = 'modelupdate';\n constructor(public data: ModelUpdateEventData) {\n super(ModelUpdateEvent.eventName);\n }\n}\n\ndeclare global {\n interface HTMLElementEventMap {\n [ModelUpdateEvent.eventName]: ModelUpdateEvent;\n }\n}\n\nexport function isModelUpdateDataComplete(eventData: ModelUpdateEventData): eventData is ModelUpdateEventComplete {\n return eventData.type === ModelUpdateType.COMPLETE;\n}\n\nexport function isModelUpdateDataProgress(eventData: ModelUpdateEventData): eventData is ModelUpdateEventProgress {\n return eventData.type === ModelUpdateType.PROGRESS_UPDATE;\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\nimport * as Handlers from './handlers/handlers.js';\nimport * as Types from './types/types.js';\n\nconst enum Status {\n IDLE = 'IDLE',\n PARSING = 'PARSING',\n FINISHED_PARSING = 'FINISHED_PARSING',\n ERRORED_WHILE_PARSING = 'ERRORED_WHILE_PARSING',\n}\n\nexport type TraceParseEventProgressData = {\n index: number,\n total: number,\n};\n\nexport class TraceParseProgressEvent extends Event {\n static readonly eventName = 'traceparseprogress';\n constructor(public data: TraceParseEventProgressData, init: EventInit = {bubbles: true}) {\n super(TraceParseProgressEvent.eventName, init);\n }\n}\ndeclare global {\n interface HTMLElementEventMap {\n [TraceParseProgressEvent.eventName]: TraceParseProgressEvent;\n }\n}\n\nexport class TraceProcessor<EnabledModelHandlers extends {[key: string]: Handlers.Types.TraceEventHandler}> extends\n EventTarget {\n // We force the Meta handler to be enabled, so the TraceHandlers type here is\n // the model handlers the user passes in and the Meta handler.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n readonly #traceHandlers: Handlers.Types.HandlersWithMeta<EnabledModelHandlers>;\n #status = Status.IDLE;\n #modelConfiguration = Types.Configuration.DEFAULT;\n\n static createWithAllHandlers(): TraceProcessor<typeof Handlers.ModelHandlers> {\n return new TraceProcessor(Handlers.ModelHandlers, Types.Configuration.DEFAULT);\n }\n\n constructor(traceHandlers: EnabledModelHandlers, modelConfiguration?: Types.Configuration.Configuration) {\n super();\n\n this.#verifyHandlers(traceHandlers);\n this.#traceHandlers = {\n Meta: Handlers.ModelHandlers.Meta,\n ...traceHandlers,\n };\n if (modelConfiguration) {\n this.#modelConfiguration = modelConfiguration;\n }\n this.#passConfigToHandlers();\n }\n\n updateConfiguration(config: Types.Configuration.Configuration): void {\n this.#modelConfiguration = config;\n this.#passConfigToHandlers();\n }\n\n #passConfigToHandlers(): void {\n for (const handler of Object.values(this.#traceHandlers)) {\n // Bit of an odd double check, but without this TypeScript refuses to let\n // you call the function as it thinks it might be undefined.\n if ('handleUserConfig' in handler && handler.handleUserConfig) {\n handler.handleUserConfig(this.#modelConfiguration);\n }\n }\n }\n\n /**\n * When the user passes in a set of handlers, we want to ensure that we have all\n * the required handlers. Handlers can depend on other handlers, so if the user\n * passes in FooHandler which depends on BarHandler, they must also pass in\n * BarHandler too. This method verifies that all dependencies are met, and\n * throws if not.\n **/\n #verifyHandlers(providedHandlers: EnabledModelHandlers): void {\n // Tiny optimisation: if the amount of provided handlers matches the amount\n // of handlers in the Handlers.ModelHandlers object, that means that the\n // user has passed in every handler we have. So therefore they cannot have\n // missed any, and there is no need to iterate through the handlers and\n // check the dependencies.\n if (Object.keys(providedHandlers).length === Object.keys(Handlers.ModelHandlers).length) {\n return;\n }\n const requiredHandlerKeys: Set<Handlers.Types.TraceEventHandlerName> = new Set();\n for (const [handlerName, handler] of Object.entries(providedHandlers)) {\n requiredHandlerKeys.add(handlerName as Handlers.Types.TraceEventHandlerName);\n for (const depName of (handler.deps?.() || [])) {\n requiredHandlerKeys.add(depName);\n }\n }\n\n const providedHandlerKeys = new Set(Object.keys(providedHandlers));\n // We always force the Meta handler to be enabled when creating the\n // Processor, so if it is missing from the set the user gave us that is OK,\n // as we will have enabled it anyway.\n requiredHandlerKeys.delete('Meta');\n\n for (const requiredKey of requiredHandlerKeys) {\n if (!providedHandlerKeys.has(requiredKey)) {\n throw new Error(`Required handler ${requiredKey} not provided.`);\n }\n }\n }\n\n reset(): void {\n if (this.#status === Status.PARSING) {\n throw new Error('Trace processor can\\'t reset while parsing.');\n }\n\n const handlers = Object.values(this.#traceHandlers);\n for (const handler of handlers) {\n handler.reset();\n }\n\n this.#status = Status.IDLE;\n }\n\n async parse(traceEvents: readonly Types.TraceEvents.TraceEventData[], freshRecording = false): Promise<void> {\n if (this.#status !== Status.IDLE) {\n throw new Error(`Trace processor can't start parsing when not idle. Current state: ${this.#status}`);\n }\n try {\n this.#status = Status.PARSING;\n await this.#parse(traceEvents, freshRecording);\n this.#status = Status.FINISHED_PARSING;\n } catch (e) {\n this.#status = Status.ERRORED_WHILE_PARSING;\n throw e;\n }\n }\n\n async #parse(traceEvents: readonly Types.TraceEvents.TraceEventData[], freshRecording: boolean): Promise<void> {\n // This iterator steps through all events, periodically yielding back to the\n // main thread to avoid blocking execution. It uses `dispatchEvent` to\n // provide status update events, and other various bits of config like the\n // pause duration and frequency.\n const {pauseDuration, eventsPerChunk} = this.#modelConfiguration.processing;\n const traceEventIterator = new TraceEventIterator(traceEvents, pauseDuration, eventsPerChunk);\n\n // Convert to array so that we are able to iterate all handlers multiple times.\n const sortedHandlers = [...sortHandlers(this.#traceHandlers).values()];\n // Reset.\n for (const handler of sortedHandlers) {\n handler.reset();\n }\n\n // Initialize.\n for (const handler of sortedHandlers) {\n handler.initialize?.(freshRecording);\n }\n\n // Handle each event.\n for await (const item of traceEventIterator) {\n if (item.kind === IteratorItemType.STATUS_UPDATE) {\n this.dispatchEvent(new TraceParseProgressEvent(item.data));\n continue;\n }\n for (const handler of sortedHandlers) {\n handler.handleEvent(item.data);\n }\n }\n\n // Finalize.\n for (const handler of sortedHandlers) {\n await handler.finalize?.();\n }\n }\n\n get data(): Handlers.Types.EnabledHandlerDataWithMeta<EnabledModelHandlers>|null {\n if (this.#status !== Status.FINISHED_PARSING) {\n return null;\n }\n\n const data = {};\n for (const [name, handler] of Object.entries(this.#traceHandlers)) {\n Object.assign(data, {[name]: handler.data()});\n }\n\n return data as Handlers.Types.EnabledHandlerDataWithMeta<EnabledModelHandlers>;\n }\n}\n\n/**\n * Some Handlers need data provided by others. Dependencies of a handler handler are\n * declared in the `deps` field.\n * @returns A map from trace event handler name to trace event hander whose entries\n * iterate in such a way that each handler is visited after its dependencies.\n */\nexport function sortHandlers(\n traceHandlers: Partial<{[key in Handlers.Types.TraceEventHandlerName]: Handlers.Types.TraceEventHandler}>):\n Map<Handlers.Types.TraceEventHandlerName, Handlers.Types.TraceEventHandler> {\n const sortedMap = new Map<Handlers.Types.TraceEventHandlerName, Handlers.Types.TraceEventHandler>();\n const visited = new Set<Handlers.Types.TraceEventHandlerName>();\n const visitHandler = (handlerName: Handlers.Types.TraceEventHandlerName): void => {\n if (sortedMap.has(handlerName)) {\n return;\n }\n if (visited.has(handlerName)) {\n let stackPath = '';\n for (const handler of visited) {\n if (stackPath || handler === handlerName) {\n stackPath += `${handler}->`;\n }\n }\n stackPath += handlerName;\n throw new Error(`Found dependency cycle in trace event handlers: ${stackPath}`);\n }\n visited.add(handlerName);\n const handler = traceHandlers[handlerName];\n if (!handler) {\n return;\n }\n const deps = handler.deps?.();\n if (deps) {\n deps.forEach(visitHandler);\n }\n sortedMap.set(handlerName, handler);\n };\n\n for (const handlerName of Object.keys(traceHandlers)) {\n visitHandler(handlerName as Handlers.Types.TraceEventHandlerName);\n }\n return sortedMap;\n}\n\nconst enum IteratorItemType {\n TRACE_EVENT = 1,\n STATUS_UPDATE = 2,\n}\n\ntype IteratorItem = IteratorTraceEventItem|IteratorStatusUpdateItem;\n\ntype IteratorTraceEventItem = {\n kind: IteratorItemType.TRACE_EVENT,\n data: Types.TraceEvents.TraceEventData,\n};\n\ntype IteratorStatusUpdateItem = {\n kind: IteratorItemType.STATUS_UPDATE,\n data: TraceParseEventProgressData,\n};\n\nclass TraceEventIterator {\n #eventCount: number;\n\n constructor(\n private traceEvents: readonly Types.TraceEvents.TraceEventData[], private pauseDuration: number,\n private eventsPerChunk: number) {\n this.#eventCount = 0;\n }\n\n async * [Symbol.asyncIterator](): AsyncGenerator<IteratorItem, void, void> {\n for (let i = 0, length = this.traceEvents.length; i < length; i++) {\n // Every so often we take a break just to render.\n if (++this.#eventCount % this.eventsPerChunk === 0) {\n // Take the opportunity to provide status update events.\n yield {kind: IteratorItemType.STATUS_UPDATE, data: {index: i, total: length}};\n // Wait for rendering before resuming.\n await new Promise(resolve => setTimeout(resolve, this.pauseDuration));\n }\n\n yield {kind: IteratorItemType.TRACE_EVENT, data: this.traceEvents[i]};\n }\n }\n}\n", "// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\nimport * as Platform from '../../core/platform/platform.js';\n\nimport type * as Handlers from './handlers/handlers.js';\nimport type * as Helpers from './helpers/helpers.js';\nimport type * as Types from './types/types.js';\n\ntype EntryToNodeMap = Map<Types.TraceEvents.TraceEntry, Helpers.TreeHelpers.TraceEntryNode>;\n\nexport interface UserTreeAction {\n type: 'MERGE_FUNCTION'|'COLLAPSE_FUNCTION';\n entry: Types.TraceEvents.TraceEntry;\n}\n\n/**\n * This class can take in a thread that has been generated by the\n * RendererHandler and apply certain actions to it in order to modify what is\n * shown to the user. These actions can be automatically applied by DevTools or\n * applied by the user.\n *\n * Once actions are applied, the visibleEntries() method will return only the\n * entries that are still visible, and this is the list of entries that can\n * then be used to render the resulting thread on the timeline.\n **/\nexport class TreeManipulator {\n readonly #thread: Handlers.ModelHandlers.Renderer.RendererThread;\n // Maps from an individual TraceEvent entry to its representation as a\n // RendererEntryNode. We need this so we can then parse the tree structure\n // generated by the RendererHandler.\n #entryToNode: EntryToNodeMap;\n\n // Track the last calculated set of visible entries. This means we can avoid\n // re-generating this if the set of actions that have been applied has not\n // changed.\n #lastVisibleEntries: readonly Types.TraceEvents.TraceEntry[]|null = null;\n #activeActions: UserTreeAction[] = [];\n\n constructor(\n thread: Handlers.ModelHandlers.Renderer.RendererThread,\n entryToNode: EntryToNodeMap,\n ) {\n this.#thread = thread;\n this.#entryToNode = entryToNode;\n }\n\n /**\n * Applies an action to the visible tree. This will also clear the cache of\n * visible entries, ensuring that it will be recalculated with the latest set\n * of actions.\n **/\n applyAction(action: UserTreeAction): void {\n if (this.#actionIsActive(action)) {\n // If the action is already active there is no reason to apply it again.\n return;\n }\n\n this.#activeActions.push(action);\n // Clear the last list of visible entries - this invalidates the cache and\n // ensures that the visible list will be recalculated, which we have to do\n // now we have changed the list of actions.\n this.#lastVisibleEntries = null;\n }\n\n /**\n * Removes a matching action, if one is found, from the active actions set.\n * Note that we do not match on action equality and instead search through\n * the set of active actions for one that is of the same type, and has the\n * same entry associated with it.\n *\n * This is a no-op if the action is not active.\n **/\n removeActiveAction(action: UserTreeAction): void {\n let removedAction = false;\n this.#activeActions = this.#activeActions.filter(activeAction => {\n if (activeAction.type === action.type && activeAction.entry === action.entry) {\n removedAction = true;\n return false;\n }\n return true;\n });\n\n if (removedAction) {\n // If we found and removed an action, we need to clear the cache to force\n // the set of visible entries to be recalculcated.\n this.#lastVisibleEntries = null;\n }\n }\n\n #actionIsActive(action: UserTreeAction): boolean {\n return this.#activeActions.some(activeAction => {\n return action.entry === activeAction.entry && action.type === activeAction.type;\n });\n }\n\n /**\n * The set of entries that are visible given the set of applied actions. If\n * no actions are applied, this will return all entries in the thread.\n *\n * This method is cached, so it is safe to call multiple times.\n **/\n visibleEntries(): readonly Types.TraceEvents.TraceEventData[] {\n if (this.#activeActions.length === 0) {\n return this.#thread.entries;\n }\n return this.#calculateVisibleEntries();\n }\n\n #calculateVisibleEntries(): readonly Types.TraceEvents.TraceEventData[] {\n // When an action is added, we clear this cache. So if this cache is\n // present it means that the set of active actions has not changed, and so\n // we do not need to recalculate anything.\n if (this.#lastVisibleEntries) {\n return this.#lastVisibleEntries;\n }\n\n if (!this.#thread.tree) {\n // We need a tree to be able to calculate user actions, if we do not have\n // it, just return all the entries.\n return this.#thread.entries;\n }\n\n // We apply each user action in turn to the set of all entries, and mark\n // any that should be hidden by adding them to this set. We do this to\n // ensure we minimise the amount of passes through the list of all entries.\n // Another approach would be to use splice() to remove items from the\n // array, but doing this would be a mutation of the arry for every hidden\n // event. Instead, we add entries to this set, and at the very end loop\n // through the entries array once to filter out any that should be hidden.\n const entriesToHide = new Set<Types.TraceEvents.TraceEntry>();\n\n const entries = [...this.#thread.entries];\n for (const action of this.#activeActions) {\n switch (action.type) {\n case 'MERGE_FUNCTION': {\n // The entry that was clicked on is merged into its parent. All its\n // children remain visible, so we just have to hide the entry that was\n // selected.\n entriesToHide.add(action.entry);\n break;\n }\n\n case 'COLLAPSE_FUNCTION': {\n // The entry itself remains visible, but all of its ancestors are hidden.\n const entryNode = this.#entryToNode.get(action.entry);\n if (!entryNode) {\n // Invalid node was given, just ignore and move on.\n continue;\n }\n const allAncestors = this.#findAllAncestorsOfNode(entryNode);\n allAncestors.forEach(ancestor => entriesToHide.add(ancestor));\n break;\n }\n default:\n Platform.assertNever(action.type, `Unknown TreeManipulator action: ${action.type}`);\n }\n }\n\n // Now we have applied all actions, loop through the list of entries and\n // remove any that are marked as hidden.\n // We cache this under lastVisibleEntries - if this function is called\n // again and the user actions have not changed, we can avoid recalculating\n // this and just return the last one. This cache is automatically cleared\n // when the user actions are changed.\n this.#lastVisibleEntries = entries.filter(entry => {\n return entriesToHide.has(entry) === false;\n });\n\n return this.#lastVisibleEntries;\n }\n\n #findAllAncestorsOfNode(root: Helpers.TreeHelpers.TraceEntryNode): Types.TraceEvents.TraceEntry[] {\n const ancestors: Types.TraceEvents.TraceEntry[] = [];\n\n // Walk through all the ancestors, starting at the root node.\n const children: Helpers.TreeHelpers.TraceEntryNode[] = Array.from(root.children);\n while (children.length > 0) {\n const childNode = children.shift();\n if (childNode) {\n ancestors.push(childNode.entry);\n const newChildIds = Array.from(childNode.children);\n children.push(...newChildIds);\n }\n }\n\n return ancestors;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }