@paulirish/trace_engine 0.0.10 → 0.0.12
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/README.md +1 -1
- package/analyze-trace.mjs +1 -1
- package/core/platform/DevToolsPath.d.ts +4 -13
- package/core/platform/DevToolsPath.js +7 -4
- package/core/platform/DevToolsPath.js.map +1 -7
- package/core/platform/MimeType.d.ts +27 -0
- package/core/platform/MimeType.js +119 -86
- package/core/platform/MimeType.js.map +1 -7
- package/core/platform/Timing.d.ts +7 -0
- package/core/platform/Timing.js +7 -4
- package/core/platform/Timing.js.map +1 -7
- package/core/platform/UIString.d.ts +2 -5
- package/core/platform/UIString.js +5 -2
- package/core/platform/UIString.js.map +1 -7
- package/core/platform/UserVisibleError.js +19 -10
- package/core/platform/UserVisibleError.js.map +1 -7
- package/core/platform/array-utilities.d.ts +48 -10
- package/core/platform/array-utilities.js +160 -124
- package/core/platform/array-utilities.js.map +1 -7
- package/core/platform/brand.d.ts +14 -0
- package/core/platform/brand.js +5 -1
- package/core/platform/brand.js.map +1 -7
- package/core/platform/date-utilities.js +10 -6
- package/core/platform/date-utilities.js.map +1 -7
- package/core/platform/dom-utilities.d.ts +3 -1
- package/core/platform/dom-utilities.js +94 -83
- package/core/platform/dom-utilities.js.map +1 -7
- package/core/platform/keyboard-utilities.d.ts +2 -0
- package/core/platform/keyboard-utilities.js +15 -24
- package/core/platform/keyboard-utilities.js.map +1 -7
- package/core/platform/map-utilities.d.ts +4 -0
- package/core/platform/map-utilities.js +66 -60
- package/core/platform/map-utilities.js.map +1 -7
- package/core/platform/number-utilities.js +66 -55
- package/core/platform/number-utilities.js.map +1 -7
- package/core/platform/platform.d.ts +5 -1
- package/core/platform/platform.js +54 -37
- package/core/platform/platform.js.map +1 -7
- package/core/platform/promise-utilities.d.ts +10 -0
- package/core/platform/promise-utilities.js +16 -8
- package/core/platform/promise-utilities.js.map +1 -7
- package/core/platform/set-utilities.js +20 -17
- package/core/platform/set-utilities.js.map +1 -7
- package/core/platform/string-utilities.d.ts +32 -1
- package/core/platform/string-utilities.js +453 -379
- package/core/platform/string-utilities.js.map +1 -7
- package/core/platform/typescript-utilities.d.ts +5 -5
- package/core/platform/typescript-utilities.js +19 -7
- package/core/platform/typescript-utilities.js.map +1 -7
- package/generated/protocol.d.ts +2081 -347
- package/generated/protocol.js +5 -2230
- package/models/cpu_profile/CPUProfileDataModel.d.ts +77 -0
- package/models/cpu_profile/CPUProfileDataModel.js +492 -359
- package/models/cpu_profile/CPUProfileDataModel.js.map +1 -7
- package/models/cpu_profile/ProfileTreeModel.d.ts +29 -0
- package/models/cpu_profile/ProfileTreeModel.js +87 -82
- package/models/cpu_profile/ProfileTreeModel.js.map +1 -7
- package/models/cpu_profile/cpu_profile.d.ts +3 -0
- package/models/cpu_profile/cpu_profile.js +7 -7
- package/models/cpu_profile/cpu_profile.js.map +1 -7
- package/models/trace/EntriesFilter.d.ts +55 -0
- package/models/trace/EntriesFilter.js +227 -166
- package/models/trace/EntriesFilter.js.map +1 -7
- package/models/trace/LegacyTracingModel.js.map +1 -7
- package/models/trace/ModelImpl.d.ts +110 -0
- package/models/trace/ModelImpl.js +161 -102
- package/models/trace/ModelImpl.js.map +1 -7
- package/models/trace/Processor.d.ts +36 -0
- package/models/trace/Processor.js +197 -163
- package/models/trace/Processor.js.map +1 -7
- package/models/trace/TracingManager.js.map +1 -7
- package/models/trace/extras/FetchNodes.d.ts +46 -0
- package/models/trace/extras/FetchNodes.js +132 -91
- package/models/trace/extras/FetchNodes.js.map +1 -7
- package/models/trace/extras/FilmStrip.d.ts +19 -0
- package/models/trace/extras/FilmStrip.js +38 -31
- package/models/trace/extras/FilmStrip.js.map +1 -7
- package/models/trace/extras/MainThreadActivity.d.ts +2 -0
- package/models/trace/extras/MainThreadActivity.js +72 -56
- package/models/trace/extras/MainThreadActivity.js.map +1 -7
- package/models/trace/extras/Metadata.d.ts +2 -0
- package/models/trace/extras/Metadata.js +42 -26
- package/models/trace/extras/Metadata.js.map +1 -7
- package/models/trace/extras/extras.js.map +1 -7
- package/models/trace/handlers/AnimationHandler.d.ts +8 -0
- package/models/trace/handlers/AnimationHandler.js +22 -20
- package/models/trace/handlers/AnimationHandler.js.map +1 -7
- package/models/trace/handlers/AuctionWorkletsHandler.d.ts +8 -0
- package/models/trace/handlers/AuctionWorkletsHandler.js +143 -89
- package/models/trace/handlers/AuctionWorkletsHandler.js.map +1 -7
- package/models/trace/handlers/FramesHandler.d.ts +76 -0
- package/models/trace/handlers/FramesHandler.js +424 -355
- package/models/trace/handlers/FramesHandler.js.map +1 -7
- package/models/trace/handlers/GPUHandler.d.ts +11 -0
- package/models/trace/handlers/GPUHandler.js +41 -37
- package/models/trace/handlers/GPUHandler.js.map +1 -7
- package/models/trace/handlers/InitiatorsHandler.d.ts +10 -0
- package/models/trace/handlers/InitiatorsHandler.js +164 -113
- package/models/trace/handlers/InitiatorsHandler.js.map +1 -7
- package/models/trace/handlers/InvalidationsHandler.d.ts +10 -0
- package/models/trace/handlers/InvalidationsHandler.js +101 -79
- package/models/trace/handlers/InvalidationsHandler.js.map +1 -7
- package/models/trace/handlers/LargestImagePaintHandler.d.ts +5 -0
- package/models/trace/handlers/LargestImagePaintHandler.js +32 -12
- package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -7
- package/models/trace/handlers/LargestTextPaintHandler.d.ts +5 -0
- package/models/trace/handlers/LargestTextPaintHandler.js +20 -12
- package/models/trace/handlers/LargestTextPaintHandler.js.map +1 -7
- package/models/trace/handlers/LayerTreeHandler.d.ts +13 -0
- package/models/trace/handlers/LayerTreeHandler.js +96 -70
- package/models/trace/handlers/LayerTreeHandler.js.map +1 -7
- package/models/trace/handlers/LayoutShiftsHandler.d.ts +44 -0
- package/models/trace/handlers/LayoutShiftsHandler.js +304 -227
- package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -7
- package/models/trace/handlers/MemoryHandler.d.ts +7 -0
- package/models/trace/handlers/MemoryHandler.js +14 -11
- package/models/trace/handlers/MemoryHandler.js.map +1 -7
- package/models/trace/handlers/MetaHandler.d.ts +37 -0
- package/models/trace/handlers/MetaHandler.js +314 -226
- package/models/trace/handlers/MetaHandler.js.map +1 -7
- package/models/trace/handlers/ModelHandlers.d.ts +21 -0
- package/models/trace/handlers/ModelHandlers.js +25 -22
- package/models/trace/handlers/ModelHandlers.js.map +1 -7
- package/models/trace/handlers/NetworkRequestsHandler.d.ts +17 -0
- package/models/trace/handlers/NetworkRequestsHandler.js +342 -218
- package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -7
- package/models/trace/handlers/PageLoadMetricsHandler.d.ts +67 -0
- package/models/trace/handlers/PageLoadMetricsHandler.js +357 -284
- package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -7
- package/models/trace/handlers/RendererHandler.d.ts +101 -0
- package/models/trace/handlers/RendererHandler.js +295 -191
- package/models/trace/handlers/RendererHandler.js.map +1 -7
- package/models/trace/handlers/SamplesHandler.d.ts +46 -0
- package/models/trace/handlers/SamplesHandler.js +195 -158
- package/models/trace/handlers/SamplesHandler.js.map +1 -7
- package/models/trace/handlers/ScreenshotsHandler.d.ts +7 -0
- package/models/trace/handlers/ScreenshotsHandler.js +63 -41
- package/models/trace/handlers/ScreenshotsHandler.js.map +1 -7
- package/models/trace/handlers/Threads.d.ts +33 -0
- package/models/trace/handlers/Threads.js +85 -67
- package/models/trace/handlers/Threads.js.map +1 -7
- package/models/trace/handlers/UserInteractionsHandler.d.ts +57 -0
- package/models/trace/handlers/UserInteractionsHandler.js +240 -141
- package/models/trace/handlers/UserInteractionsHandler.js.map +1 -7
- package/models/trace/handlers/UserTimingsHandler.d.ts +28 -0
- package/models/trace/handlers/UserTimingsHandler.js +91 -80
- package/models/trace/handlers/UserTimingsHandler.js.map +1 -7
- package/models/trace/handlers/WarningsHandler.d.ts +14 -0
- package/models/trace/handlers/WarningsHandler.js +100 -62
- package/models/trace/handlers/WarningsHandler.js.map +1 -7
- package/models/trace/handlers/WorkersHandler.d.ts +11 -0
- package/models/trace/handlers/WorkersHandler.js +40 -38
- package/models/trace/handlers/WorkersHandler.js.map +1 -7
- package/models/trace/handlers/handlers.d.ts +3 -0
- package/models/trace/handlers/handlers.js +7 -4
- package/models/trace/handlers/handlers.js.map +1 -7
- package/models/trace/handlers/types.d.ts +45 -0
- package/models/trace/handlers/types.js +15 -15
- package/models/trace/handlers/types.js.map +1 -7
- package/models/trace/helpers/SamplesIntegrator.d.ts +49 -0
- package/models/trace/helpers/SamplesIntegrator.js +381 -204
- package/models/trace/helpers/SamplesIntegrator.js.map +1 -7
- package/models/trace/helpers/Timing.d.ts +26 -0
- package/models/trace/helpers/Timing.js +131 -110
- package/models/trace/helpers/Timing.js.map +1 -7
- package/models/trace/helpers/Trace.d.ts +37 -0
- package/models/trace/helpers/Trace.js +200 -166
- package/models/trace/helpers/Trace.js.map +1 -7
- package/models/trace/helpers/TreeHelpers.d.ts +90 -0
- package/models/trace/helpers/TreeHelpers.js +203 -100
- package/models/trace/helpers/TreeHelpers.js.map +1 -7
- package/models/trace/helpers/helpers.d.ts +4 -0
- package/models/trace/helpers/helpers.js +8 -5
- package/models/trace/helpers/helpers.js.map +1 -7
- package/models/trace/root-causes/LayoutShift.d.ts +119 -0
- package/models/trace/root-causes/LayoutShift.js +470 -323
- package/models/trace/root-causes/LayoutShift.js.map +1 -7
- package/models/trace/root-causes/RootCauses.d.ts +14 -0
- package/models/trace/root-causes/RootCauses.js +9 -6
- package/models/trace/root-causes/RootCauses.js.map +1 -7
- package/models/trace/root-causes/root-causes.d.ts +1 -0
- package/models/trace/root-causes/root-causes.js +5 -2
- package/models/trace/root-causes/root-causes.js.map +1 -7
- package/models/trace/trace.d.ts +11 -0
- package/models/trace/trace.js +17 -23
- package/models/trace/trace.js.map +1 -7
- package/models/trace/types/Configuration.d.ts +33 -0
- package/models/trace/types/Configuration.js +25 -14
- package/models/trace/types/Configuration.js.map +1 -7
- package/models/trace/types/File.d.ts +23 -0
- package/models/trace/types/File.js +5 -6
- package/models/trace/types/File.js.map +1 -7
- package/models/trace/types/Timing.d.ts +25 -0
- package/models/trace/types/Timing.js +10 -11
- package/models/trace/types/Timing.js.map +1 -7
- package/models/trace/types/TraceEvents.d.ts +1571 -0
- package/models/trace/types/TraceEvents.js +174 -381
- package/models/trace/types/TraceEvents.js.map +1 -7
- package/models/trace/types/types.d.ts +4 -0
- package/models/trace/types/types.js +8 -5
- package/models/trace/types/types.js.map +1 -7
- package/package.json +1 -1
- package/TracingManager.js +0 -0
- package/core/platform/devtools_entrypoint-bundle-tsconfig-tsconfig.json +0 -40
- package/core/platform/platform.js.compressed +0 -0
- package/core/platform/platform.js.hash +0 -1
- package/core/platform/platform.prebundle.d.ts +0 -15
- package/core/platform/platform.prebundle.js +0 -50
- package/core/platform/platform.prebundle.js.map +0 -1
- package/core/platform/platform.prebundle.ts +0 -64
- package/extras/extras.js +0 -0
- package/models/trace/SDKServices.js +0 -104
- package/models/trace/SDKServices.js.map +0 -7
- package/models/trace/TraceProcessor.js +0 -133
- package/models/trace/TraceProcessor.js.map +0 -7
- package/models/trace/TreeManipulator.js +0 -85
- package/models/trace/TreeManipulator.js.map +0 -7
- package/models/trace/devtools_entrypoint-legacy-typescript-tsconfig.json +0 -43
- package/models/trace/frames/TimelineFrameModel.js +0 -392
- package/models/trace/frames/TimelineFrameModel.js.map +0 -7
- package/models/trace/frames/bundle-tsconfig.json +0 -1
- package/models/trace/frames/devtools_entrypoint-bundle-typescript-tsconfig.json +0 -43
- package/models/trace/frames/frames-tsconfig.json +0 -58
- package/models/trace/frames/frames.js +0 -5
- package/models/trace/frames/frames.js.map +0 -7
- package/models/trace/handlers/Migration.js +0 -27
- package/models/trace/handlers/Migration.js.map +0 -7
- package/models/trace/handlers/UberFramesHandler.js +0 -293
- package/models/trace/handlers/UberFramesHandler.js.map +0 -7
- package/models/trace/legacy-tsconfig.json +0 -1
- package/models/trace/sdk_services/DOMNodeLookup.js +0 -41
- package/models/trace/sdk_services/DOMNodeLookup.js.map +0 -7
- package/models/trace/sdk_services/LayoutShifts.js +0 -68
- package/models/trace/sdk_services/LayoutShifts.js.map +0 -7
- package/models/trace/sdk_services/bundle-tsconfig.json +0 -1
- package/models/trace/sdk_services/devtools_entrypoint-bundle-typescript-tsconfig.json +0 -41
- package/models/trace/sdk_services/sdk_services-tsconfig.json +0 -57
- package/models/trace/sdk_services/sdk_services.js +0 -7
- package/models/trace/sdk_services/sdk_services.js.map +0 -7
- package/models/trace/trace-legacy.js +0 -16
- package/models/trace/trace-legacy.js.map +0 -7
- package/models/trace/worker/Processor.js +0 -143
- package/models/trace/worker/Processor.js.map +0 -7
- package/models/trace/worker/Types.js +0 -1
- package/models/trace/worker/Types.js.map +0 -7
- package/models/trace/worker/bundle-tsconfig.json +0 -1
- package/models/trace/worker/devtools_entrypoint-bundle-typescript-tsconfig.json +0 -41
- package/models/trace/worker/devtools_entrypoint-worker_entrypoint-typescript-tsconfig.json +0 -41
- package/models/trace/worker/processor-tsconfig.json +0 -45
- package/models/trace/worker/worker.js +0 -7
- package/models/trace/worker/worker.js.map +0 -7
- package/models/trace/worker/worker_entrypoint-tsconfig.json +0 -1
- package/models/trace/worker/worker_entrypoint.js +0 -36
- package/models/trace/worker/worker_entrypoint.js.map +0 -7
- package/trace.mjs +0 -6980
- package/trace.mjs.map +0 -8
package/trace.mjs.map
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../front_end/models/trace/EntriesFilter.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/helpers/helpers.ts", "../../../../front_end/models/trace/helpers/SamplesIntegrator.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/helpers/Timing.ts", "../../../../front_end/models/trace/helpers/Trace.ts", "../../../../front_end/models/trace/helpers/TreeHelpers.ts", "../../../../front_end/models/trace/trace.ts", "../../../../front_end/models/trace/handlers/handlers.ts", "../../../../front_end/models/trace/handlers/ModelHandlers.ts", "../../../../front_end/models/trace/handlers/AnimationHandler.ts", "../../../../front_end/models/trace/handlers/types.ts", "../../../../front_end/models/trace/handlers/AuctionWorkletsHandler.ts", "../../../../front_end/models/trace/handlers/FramesHandler.ts", "../../../../front_end/models/trace/handlers/LayerTreeHandler.ts", "../../../../front_end/models/trace/handlers/MetaHandler.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/handlers/GPUHandler.ts", "../../../../front_end/models/trace/handlers/InitiatorsHandler.ts", "../../../../front_end/models/trace/handlers/InvalidationsHandler.ts", "../../../../front_end/models/trace/handlers/LargestImagePaintHandler.ts", "../../../../front_end/models/trace/handlers/LargestTextPaintHandler.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/LegacyTracingModel.ts", "../../../../front_end/models/trace/ModelImpl.ts", "../../../../front_end/models/trace/Processor.ts", "../../../../front_end/models/trace/root-causes/root-causes.ts", "../../../../front_end/models/trace/root-causes/RootCauses.ts", "../../../../front_end/models/trace/root-causes/LayoutShift.ts"],
|
|
4
|
-
"sourceRoot": "@trace_engine/x/x/x/x/",
|
|
5
|
-
"sourcesContent": ["// 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 * as Helpers from './helpers/helpers.js';\nimport * as Types from './types/types.js';\n\ntype EntryToNodeMap = Map<Types.TraceEvents.TraceEntry, Helpers.TreeHelpers.TraceEntryNode>;\n\nexport type FilterAction = FilterApplyAction|FilterUndoAction;\n\nexport const enum FilterApplyAction {\n MERGE_FUNCTION = 'MERGE_FUNCTION',\n COLLAPSE_FUNCTION = 'COLLAPSE_FUNCTION',\n COLLAPSE_REPEATING_DESCENDANTS = 'COLLAPSE_REPEATING_DESCENDANTS',\n}\n\nexport const enum FilterUndoAction {\n RESET_CHILDREN = 'RESET_CHILDREN',\n UNDO_ALL_ACTIONS = 'UNDO_ALL_ACTIONS',\n}\n\nconst filterApplyActionSet: Set<FilterApplyAction> = new Set([\n FilterApplyAction.MERGE_FUNCTION,\n FilterApplyAction.COLLAPSE_FUNCTION,\n FilterApplyAction.COLLAPSE_REPEATING_DESCENDANTS,\n]);\n\nconst filterUndoActionSet: Set<FilterUndoAction> = new Set([\n FilterUndoAction.RESET_CHILDREN,\n FilterUndoAction.UNDO_ALL_ACTIONS,\n]);\n\n// Object passed from the frontend that can be either Undo or Apply filter action.\nexport interface UserFilterAction {\n type: FilterAction;\n entry: Types.TraceEvents.TraceEntry;\n}\n\nexport interface UserApplyFilterAction {\n type: FilterApplyAction;\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 invisibleEntries() method will return the\n * entries that are invisible, and this is the list of entries that should be\n * removed before rendering the resulting thread on the timeline.\n **/\nexport class EntriesFilter {\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 set of invisible entries.\n #invisibleEntries: Types.TraceEvents.TraceEventData[] = [];\n // List of entries whose children are modified. This list is used to\n // keep track of entries that should be identified in the UI as modified.\n #modifiedVisibleEntries: Types.TraceEvents.TraceEventData[] = [];\n // Cache for ancestors of entry that have already been gathered. The ancestors\n // will never change so we can avoid running the potentially expensive search again.\n #entryToAncestorsMap: Map<Helpers.TreeHelpers.TraceEntryNode, Types.TraceEvents.TraceEventData[]> = new Map();\n\n constructor(entryToNode: EntryToNodeMap) {\n this.#entryToNode = entryToNode;\n }\n\n /**\n * Applies an action to hide entries or removes entries\n * from hidden entries array depending on the type of action.\n **/\n applyAction(action: UserFilterAction): void {\n if (/* FilterApplyActions */ this.#isUserApplyFilterAction(action)) {\n this.#applyFilterAction(action);\n\n } else if (/* FilterUndoActions */ this.#isFilterUndoAction(action.type)) {\n this.#applyUndoAction(action);\n }\n }\n\n /**\n * If undo action is UNDO_ALL_ACTIONS, assign invisibleEntries array to an empty one.\n * **/\n #applyUndoAction(action: UserFilterAction): void {\n switch (action.type) {\n case FilterUndoAction.UNDO_ALL_ACTIONS: {\n this.#invisibleEntries = [];\n this.#modifiedVisibleEntries = [];\n break;\n }\n case FilterUndoAction.RESET_CHILDREN: {\n this.#makeEntryChildrenVisible(action.entry);\n break;\n }\n }\n }\n\n /**\n * Returns the set of entries that are invisible given the set of applied actions.\n **/\n invisibleEntries(): Types.TraceEvents.TraceEventData[] {\n return this.#invisibleEntries;\n }\n\n #applyFilterAction(action: UserApplyFilterAction): Types.TraceEvents.TraceEventData[] {\n // Identify in the UI that children of the entry are modified.\n this.#modifiedVisibleEntries.push(action.entry);\n // We apply new user action to the set of all entries, and mark\n // any that should be hidden by adding them to this set.\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 return it as an array at the end.\n const entriesToHide = new Set<Types.TraceEvents.TraceEventData>();\n\n switch (action.type) {\n case FilterApplyAction.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 FilterApplyAction.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 break;\n }\n const allAncestors = this.#findAllAncestorsOfNode(entryNode);\n allAncestors.forEach(ancestor => entriesToHide.add(ancestor));\n break;\n }\n\n case FilterApplyAction.COLLAPSE_REPEATING_DESCENDANTS: {\n const entryNode = this.#entryToNode.get(action.entry);\n if (!entryNode) {\n // Invalid node was given, just ignore and move on.\n break;\n }\n const allRepeatingDescendants = this.#findAllRepeatingDescendantsOfNext(entryNode);\n allRepeatingDescendants.forEach(ancestor => entriesToHide.add(ancestor));\n break;\n }\n default:\n Platform.assertNever(action.type, `Unknown EntriesFilter action: ${action.type}`);\n }\n\n this.#invisibleEntries.push(...entriesToHide);\n\n return this.#invisibleEntries;\n }\n\n #findAllAncestorsOfNode(root: Helpers.TreeHelpers.TraceEntryNode): Types.TraceEvents.TraceEventData[] {\n const cachedAncestors = this.#entryToAncestorsMap.get(root);\n if (cachedAncestors) {\n return cachedAncestors;\n }\n\n const ancestors: Types.TraceEvents.TraceEventData[] = [];\n\n // Walk through all the ancestors, starting at the root node.\n const children: Helpers.TreeHelpers.TraceEntryNode[] = [...root.children];\n while (children.length > 0) {\n const childNode = children.shift();\n if (childNode) {\n ancestors.push(childNode.entry);\n const childNodeCachedAncestors = this.#entryToAncestorsMap.get(childNode);\n // If the ancestors of a child are cached, get them from the cache instead of iterating through them again\n if (childNodeCachedAncestors) {\n ancestors.push(...childNodeCachedAncestors);\n } else {\n children.push(...childNode.children);\n }\n }\n }\n\n this.#entryToAncestorsMap.set(root, ancestors);\n return ancestors;\n }\n\n #findAllRepeatingDescendantsOfNext(root: Helpers.TreeHelpers.TraceEntryNode): Types.TraceEvents.TraceEntry[] {\n // Walk through all the ancestors, starting at the root node.\n const children: Helpers.TreeHelpers.TraceEntryNode[] = [...root.children];\n const repeatingNodes: Types.TraceEvents.TraceEntry[] = [];\n const rootIsProfileCall = Types.TraceEvents.isProfileCall(root.entry);\n\n while (children.length > 0) {\n const childNode = children.shift();\n if (childNode) {\n const childIsProfileCall = Types.TraceEvents.isProfileCall(childNode.entry);\n if (/* Handle TraceEventSyntheticProfileCalls */ rootIsProfileCall && childIsProfileCall) {\n const rootNodeEntry = root.entry as Types.TraceEvents.TraceEventSyntheticProfileCall;\n const childNodeEntry = childNode.entry as Types.TraceEvents.TraceEventSyntheticProfileCall;\n\n if (Helpers.SamplesIntegrator.SamplesIntegrator.framesAreEqual(\n rootNodeEntry.callFrame, childNodeEntry.callFrame)) {\n repeatingNodes.push(childNode.entry);\n }\n } /* Handle SyntheticRendererEvents */ else if (!rootIsProfileCall && !childIsProfileCall) {\n if (root.entry.name === childNode.entry.name) {\n repeatingNodes.push(childNode.entry);\n }\n }\n children.push(...childNode.children);\n }\n }\n\n return repeatingNodes;\n }\n\n /**\n * Removes all of the entry children from the\n * invisible entries array to make them visible.\n **/\n #makeEntryChildrenVisible(entry: Types.TraceEvents.TraceEntry): void {\n const entryNode = this.#entryToNode.get(entry);\n if (!entryNode) {\n // Invalid node was given, just ignore and move on.\n return;\n }\n const ancestors = this.#findAllAncestorsOfNode(entryNode);\n\n /**\n * Filter out all ancestors of the node\n * from the invisible entries list.\n **/\n this.#invisibleEntries = this.#invisibleEntries.filter(entry => {\n if (ancestors.includes(entry)) {\n return false;\n }\n return true;\n });\n\n /**\n * Filter out all ancestors and entry from modified entries\n * list to not show that some entries below those are hidden.\n **/\n this.#modifiedVisibleEntries = this.#modifiedVisibleEntries.filter(iterEntry => {\n if (ancestors.includes(iterEntry) || iterEntry === entry) {\n return false;\n }\n return true;\n });\n }\n\n isEntryModified(event: Types.TraceEvents.TraceEventData): boolean {\n return this.#modifiedVisibleEntries.includes(event);\n }\n\n #isUserApplyFilterAction(action: UserFilterAction): action is UserApplyFilterAction {\n return filterApplyActionSet.has(action.type as FilterApplyAction);\n }\n\n #isFilterUndoAction(action: FilterAction): action is FilterUndoAction {\n return filterUndoActionSet.has(action as FilterUndoAction);\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>(\n array: readonly 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 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 = 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\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<TimeFormat extends MicroSeconds|MilliSeconds> {\n min: TimeFormat;\n max: TimeFormat;\n range: TimeFormat;\n}\n\nexport type TraceWindowMicroSeconds = TraceWindow<MicroSeconds>;\nexport type TraceWindowMilliSeconds = TraceWindow<MilliSeconds>;\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 // Trace events are inconsistent here sadly :(\n scriptId: number|string;\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: KnownEventName.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: MilliSeconds,\n processingStart: MilliSeconds,\n timeStamp: MilliSeconds,\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 ph: Phase.ASYNC_NESTABLE_START|Phase.ASYNC_NESTABLE_END;\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: KnownEventName.ThreadName;\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 gpuMemoryLimitKB?: number,\n },\n };\n}\n\nexport type TraceEventRendererEvent = TraceEventInstant|TraceEventComplete;\n\nexport interface TraceEventTracingStartedInBrowser extends TraceEventInstant {\n name: KnownEventName.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 TraceEventLayoutInvalidationTracking extends TraceEventInstant {\n name: KnownEventName.LayoutInvalidationTracking;\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 interface TraceEventScheduleStyleInvalidationTracking extends TraceEventInstant {\n name: KnownEventName.ScheduleStyleInvalidationTracking;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n nodeId: Protocol.DOM.BackendNodeId,\n invalidationSet?: string,\n invalidatedSelectorId?: string,\n reason?: LayoutInvalidationReason,\n changedClass?: string,\n changedAttribute?: string,\n changedId?: string,\n nodeName?: string,\n stackTrace?: TraceEventCallFrame[],\n },\n };\n}\nexport function isTraceEventScheduleStyleInvalidationTracking(event: TraceEventData):\n event is TraceEventScheduleStyleInvalidationTracking {\n return event.name === KnownEventName.ScheduleStyleInvalidationTracking;\n}\n\nexport const enum StyleRecalcInvalidationReason {\n ANIMATION = 'Animation',\n}\n\nexport interface TraceEventStyleRecalcInvalidationTracking extends TraceEventInstant {\n name: KnownEventName.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}\nexport function isTraceEventStyleRecalcInvalidationTracking(event: TraceEventData):\n event is TraceEventStyleRecalcInvalidationTracking {\n return event.name === KnownEventName.StyleRecalcInvalidationTracking;\n}\nexport interface TraceEventStyleInvalidatorInvalidationTracking extends TraceEventInstant {\n name: KnownEventName.StyleInvalidatorInvalidationTracking;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n nodeId: Protocol.DOM.BackendNodeId,\n reason: string,\n invalidationList: Array<{classes?: string[], id: string}>,\n subtree: boolean,\n nodeName?: string,\n extraData?: string,\n },\n };\n}\nexport function isTraceEventStyleInvalidatorInvalidationTracking(event: TraceEventData):\n event is TraceEventStyleInvalidatorInvalidationTracking {\n return event.name === KnownEventName.StyleInvalidatorInvalidationTracking;\n}\n\nexport interface TraceEventScheduleStyleRecalculation extends TraceEventInstant {\n name: KnownEventName.ScheduleStyleRecalculation;\n args: TraceEventArgs&{\n data: {\n frame: string,\n },\n };\n}\nexport function isTraceEventScheduleStyleRecalculation(event: TraceEventData):\n event is TraceEventScheduleStyleRecalculation {\n return event.name === KnownEventName.ScheduleStyleRecalculation;\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 // These values are provided in the startEvent's args.data field as\n // millisecond values, but during the handler phase we parse these into\n // microseconds and put them on the top level for easy access.\n processingStart: MicroSeconds;\n processingEnd: MicroSeconds;\n // These 3 values represent the breakdown of the parts of an interaction:\n // 1. inputDelay: time from the user clicking to the input being handled\n inputDelay: MicroSeconds;\n // 2. mainThreadHandling: time spent processing the event handler\n mainThreadHandling: MicroSeconds;\n // 3. presentationDelay: delay between the event being processed and the frame being rendered\n presentationDelay: 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\n// Events relating to frames.\n\nexport interface TraceEventDrawFrame extends TraceEventInstant {\n name: KnownEventName.DrawFrame;\n args: TraceEventArgs&{\n layerTreeId: number,\n frameSeqId: number,\n };\n}\n\nexport function isTraceEventDrawFrame(event: TraceEventData): event is TraceEventDrawFrame {\n // The extra check for INSTANT here is because in the past DrawFrame events had an ASYNC_NESTABLE_START and ASYNC_NESTABLE_END pair. We don't want to support those old events, so we have to check we are dealing with an instant event.\n return event.name === KnownEventName.DrawFrame && event.ph === Phase.INSTANT;\n}\nexport interface TraceEventLegacyDrawFrameBegin extends TraceEventAsync {\n name: KnownEventName.DrawFrame;\n ph: Phase.ASYNC_NESTABLE_START;\n args: TraceEventArgs&{\n layerTreeId: number,\n frameSeqId: number,\n };\n}\nexport function isLegacyTraceEventDrawFrameBegin(event: TraceEventData): event is TraceEventLegacyDrawFrameBegin {\n return event.name === KnownEventName.DrawFrame && event.ph === Phase.ASYNC_NESTABLE_START;\n}\n\nexport interface TraceEventBeginFrame extends TraceEventInstant {\n name: KnownEventName.BeginFrame;\n args: TraceEventArgs&{\n layerTreeId: number,\n frameSeqId: number,\n };\n}\nexport function isTraceEventBeginFrame(event: TraceEventData): event is TraceEventBeginFrame {\n // Old traces did not have frameSeqId; but we do not want to support these.\n return Boolean(event.name === KnownEventName.BeginFrame && event.args && 'frameSeqId' in event.args);\n}\n\nexport interface TraceEventDroppedFrame extends TraceEventInstant {\n name: KnownEventName.DroppedFrame;\n args: TraceEventArgs&{\n layerTreeId: number,\n frameSeqId: number,\n hasPartialUpdate?: boolean,\n };\n}\nexport function isTraceEventDroppedFrame(event: TraceEventData): event is TraceEventDroppedFrame {\n // Old traces did not have frameSeqId; but we do not want to support these.\n return Boolean(event.name === KnownEventName.DroppedFrame && event.args && 'frameSeqId' in event.args);\n}\n\nexport interface TraceEventRequestMainThreadFrame extends TraceEventInstant {\n name: KnownEventName.RequestMainThreadFrame;\n args: TraceEventArgs&{\n layerTreeId: number,\n };\n}\nexport function isTraceEventRequestMainThreadFrame(event: TraceEventData): event is TraceEventRequestMainThreadFrame {\n return event.name === KnownEventName.RequestMainThreadFrame;\n}\n\nexport interface TraceEventBeginMainThreadFrame extends TraceEventInstant {\n name: KnownEventName.BeginMainThreadFrame;\n args: TraceEventArgs&{\n layerTreeId: number,\n data: TraceEventArgsData&{\n frameId?: number,\n },\n };\n}\nexport function isTraceEventBeginMainThreadFrame(event: TraceEventData): event is TraceEventBeginMainThreadFrame {\n return event.name === KnownEventName.BeginMainThreadFrame;\n}\n\nexport interface TraceEventNeedsBeginFrameChanged extends TraceEventInstant {\n name: KnownEventName.NeedsBeginFrameChanged;\n args: TraceEventArgs&{\n layerTreeId: number,\n data: TraceEventArgsData&{\n needsBeginFrame: number,\n },\n };\n}\nexport function isTraceEventNeedsBeginFrameChanged(event: TraceEventData): event is TraceEventNeedsBeginFrameChanged {\n return event.name === KnownEventName.NeedsBeginFrameChanged;\n}\n\nexport interface TraceEventCommit extends TraceEventInstant {\n name: KnownEventName.Commit;\n args: TraceEventArgs&{\n layerTreeId: number,\n frameSeqId: number,\n };\n}\nexport function isTraceEventCommit(event: TraceEventData): event is TraceEventCommit {\n // Old traces did not have frameSeqId; but we do not want to support these.\n return Boolean(event.name === KnownEventName.Commit && event.args && 'frameSeqId' in event.args);\n}\n\nexport interface TraceEventRasterTask extends TraceEventComplete {\n name: KnownEventName.RasterTask;\n args: TraceEventArgs&{\n tileData?: {\n layerId: number,\n sourceFrameNumber: number,\n tileId: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n id_ref: string,\n },\n tileResolution: string,\n },\n };\n}\nexport function isTraceEventRasterTask(event: TraceEventData): event is TraceEventRasterTask {\n return event.name === KnownEventName.RasterTask;\n}\n\n// CompositeLayers has been replaced by \"Commit\", but we support both to not break old traces being imported.\nexport interface TraceEventCompositeLayers extends TraceEventInstant {\n name: KnownEventName.CompositeLayers;\n args: TraceEventArgs&{\n layerTreeId: number,\n };\n}\nexport function isTraceEventCompositeLayers(event: TraceEventData): event is TraceEventCompositeLayers {\n return event.name === KnownEventName.CompositeLayers;\n}\n\nexport interface TraceEventActivateLayerTree extends TraceEventInstant {\n name: KnownEventName.ActivateLayerTree;\n args: TraceEventArgs&{\n layerTreeId: number,\n frameId: number,\n };\n}\nexport function isTraceEventActivateLayerTree(event: TraceEventData): event is TraceEventActivateLayerTree {\n return event.name === KnownEventName.ActivateLayerTree;\n}\n\nexport interface SyntheticInvalidation extends TraceEventInstant {\n name: 'SyntheticInvalidation';\n nodeName?: string;\n rawEvent: TraceEventScheduleStyleInvalidationTracking|TraceEventStyleRecalcInvalidationTracking|\n TraceEventStyleInvalidatorInvalidationTracking|TraceEventLayoutInvalidationTracking;\n nodeId: Protocol.DOM.BackendNodeId;\n frame: string;\n reason?: string;\n stackTrace?: TraceEventCallFrame[];\n}\n\nexport function isTraceEventSyntheticInvalidation(event: TraceEventData): event is SyntheticInvalidation {\n return event.name === 'SyntheticInvalidation';\n}\n\nexport interface TraceEventUpdateLayoutTree extends TraceEventComplete {\n name: KnownEventName.UpdateLayoutTree;\n args: TraceEventArgs&{\n elementCount: number,\n beginData?: {\n frame: string,\n stackTrace?: TraceEventCallFrame[],\n },\n };\n}\nexport function isTraceEventUpdateLayoutTree(event: TraceEventData): event is TraceEventUpdateLayoutTree {\n return event.name === KnownEventName.UpdateLayoutTree;\n}\n\nexport interface TraceEventLayout extends TraceEventComplete {\n name: KnownEventName.Layout;\n args: TraceEventArgs&{\n beginData: {\n frame: string,\n dirtyObjects: number,\n partialLayout: boolean,\n totalObjects: number,\n },\n endData: {\n layoutRoots: Array<{\n depth: number,\n nodeId: Protocol.DOM.BackendNodeId,\n quads: number[][],\n }>,\n },\n };\n}\nexport function isTraceEventLayout(event: TraceEventData): event is TraceEventLayout {\n return event.name === KnownEventName.Layout;\n}\nexport interface TraceEventInvalidateLayout extends TraceEventInstant {\n name: KnownEventName.InvalidateLayout;\n args: TraceEventArgs&{\n data: {\n frame: string,\n nodeId: Protocol.DOM.BackendNodeId,\n },\n };\n}\nexport function isTraceEventInvalidateLayout(event: TraceEventData): event is TraceEventInvalidateLayout {\n return event.name === KnownEventName.InvalidateLayout;\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 === KnownEventName.ThreadName;\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 === KnownEventName.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 isTraceEventLayoutInvalidationTracking(\n traceEventData: TraceEventData,\n ): traceEventData is TraceEventLayoutInvalidationTracking {\n return traceEventData.name === KnownEventName.LayoutInvalidationTracking;\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\nexport interface TraceEventPaint extends TraceEventComplete {\n name: KnownEventName.Paint;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n clip: number[],\n frame: string,\n layerId: number,\n nodeId: number,\n },\n };\n}\n\nexport function isTraceEventPaint(event: TraceEventData): event is TraceEventPaint {\n return event.name === KnownEventName.Paint;\n}\n\nexport interface TraceEventSetLayerTreeId extends TraceEventInstant {\n name: KnownEventName.SetLayerTreeId;\n args: TraceEventArgs&{\n data: TraceEventArgsData & {\n frame: string,\n layerTreeId: number,\n },\n };\n}\nexport function isTraceEventSetLayerId(event: TraceEventData): event is TraceEventSetLayerTreeId {\n return event.name === KnownEventName.SetLayerTreeId;\n}\nexport interface TraceEventUpdateLayer extends TraceEventComplete {\n name: KnownEventName.UpdateLayer;\n args: TraceEventArgs&{\n layerId: number,\n layerTreeId: number,\n };\n}\nexport function isTraceEventUpdateLayer(event: TraceEventData): event is TraceEventUpdateLayer {\n return event.name === KnownEventName.UpdateLayer;\n}\n\nexport interface TraceEventDisplayItemListSnapshot extends TraceEventData {\n name: KnownEventName.DisplayItemListSnapshot;\n ph: Phase.OBJECT_SNAPSHOT;\n id2: {\n local?: string,\n };\n args: TraceEventArgs&{\n snapshot: {\n skp64: string,\n params?: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n layer_rect: [number, number, number, number],\n },\n },\n };\n}\nexport function isTraceEventDisplayListItemListSnapshot(event: TraceEventData):\n event is TraceEventDisplayItemListSnapshot {\n return event.name === KnownEventName.DisplayItemListSnapshot;\n}\n\nexport interface TraceEventLayerTreeHostImplSnapshot extends TraceEventData {\n name: KnownEventName.LayerTreeHostImplSnapshot;\n ph: Phase.OBJECT_SNAPSHOT;\n id: string;\n args: TraceEventArgs&{\n snapshot: {\n /* eslint-disable @typescript-eslint/naming-convention */\n active_tiles: Array<{\n id: string,\n layer_id: string,\n gpu_memory_usage: number,\n content_rect: number[],\n }>,\n device_viewport_size: {\n width: number,\n height: number,\n },\n active_tree: {\n root_layer: TraceLayer,\n layers: TraceLayer[],\n },\n /* eslint-enable @typescript-eslint/naming-convention */\n },\n };\n}\n\nexport function isTraceEventLayerTreeHostImplSnapshot(event: TraceEventData):\n event is TraceEventLayerTreeHostImplSnapshot {\n return event.name === KnownEventName.LayerTreeHostImplSnapshot;\n}\n/* eslint-disable @typescript-eslint/naming-convention */\nexport interface TraceLayer {\n bounds: {height: number, width: number};\n children: TraceLayer[];\n layer_id: number;\n position: number[];\n scroll_offset: number[];\n layer_quad: number[];\n draws_content: number;\n gpu_memory_usage: number;\n transform: number[];\n owner_node: Protocol.DOM.BackendNodeId;\n compositing_reasons: string[];\n compositing_reason_ids: string[];\n non_fast_scrollable_region: number[];\n touch_event_handler_region: number[];\n wheel_event_handler_region: number[];\n scroll_event_handler_region: number[];\n}\n\nexport interface TracingLayerTile {\n id: string;\n layer_id: string;\n gpu_memory_usage: number;\n content_rect: number[];\n}\n/* eslint-enable @typescript-eslint/naming-convention */\n\nexport interface TraceEventFireAnimationFrame extends TraceEventComplete {\n name: KnownEventName.FireAnimationFrame;\n args: TraceEventArgs&{\n data: {\n frame: string,\n id: number,\n },\n };\n}\nexport function isTraceEventFireAnimationFrame(event: TraceEventData): event is TraceEventFireAnimationFrame {\n return event.name === KnownEventName.FireAnimationFrame;\n}\n\nexport interface TraceEventRequestAnimationFrame extends TraceEventInstant {\n name: KnownEventName.RequestAnimationFrame;\n args: TraceEventArgs&{\n data: {\n frame: string,\n id: number,\n stackTrace?: TraceEventCallFrame,\n },\n };\n}\nexport function isTraceEventRequestAnimationFrame(event: TraceEventData): event is TraceEventRequestAnimationFrame {\n return event.name === KnownEventName.RequestAnimationFrame;\n}\n\nexport interface TraceEventTimerInstall extends TraceEventInstant {\n name: KnownEventName.TimerInstall;\n args: TraceEventArgs&{\n data: {\n frame: string,\n singleShot: boolean,\n stackTrace?: TraceEventCallFrame, timeout: number, timerId: number,\n },\n };\n}\nexport function isTraceEventTimerInstall(event: TraceEventData): event is TraceEventTimerInstall {\n return event.name === KnownEventName.TimerInstall;\n}\n\nexport interface TraceEventTimerFire extends TraceEventComplete {\n name: KnownEventName.TimerFire;\n args: TraceEventArgs&{\n data: {\n frame: string,\n timerId: number,\n },\n };\n}\nexport function isTraceEventTimerFire(event: TraceEventData): event is TraceEventTimerFire {\n return event.name === KnownEventName.TimerFire;\n}\n\nexport interface TraceEventRequestIdleCallback extends TraceEventInstant {\n name: KnownEventName.RequestIdleCallback;\n args: TraceEventArgs&{\n data: {\n frame: string,\n id: number,\n timeout: number,\n stackTrace?: TraceEventCallFrame,\n },\n\n };\n}\nexport function isTraceEventRequestIdleCallback(event: TraceEventData): event is TraceEventRequestIdleCallback {\n return event.name === KnownEventName.RequestIdleCallback;\n}\n\nexport interface TraceEventWebSocketCreate extends TraceEventInstant {\n name: KnownEventName.WebSocketCreate;\n args: TraceEventArgs&{\n data: {\n identifier: number,\n url: string,\n frame?: string,\n websocketProtocol?: string,\n stackTrace?: TraceEventCallFrame,\n },\n };\n}\nexport function isTraceEventWebSocketCreate(event: TraceEventData): event is TraceEventWebSocketCreate {\n return event.name === KnownEventName.WebSocketCreate;\n}\n\nexport interface TraceEventWebSocketSendHandshakeRequest extends TraceEventInstant {\n name: KnownEventName.WebSocketSendHandshakeRequest;\n args: TraceEventArgs&{\n data: {\n frame: string,\n identifier: number,\n },\n };\n}\nexport function isTraceEventWebSocketSendHandshakeRequest(event: TraceEventData):\n event is TraceEventWebSocketSendHandshakeRequest {\n return event.name === KnownEventName.WebSocketSendHandshakeRequest;\n}\n\nexport interface TraceEventWebSocketReceiveHandshakeResponse extends TraceEventInstant {\n name: KnownEventName.WebSocketReceiveHandshakeResponse;\n args: TraceEventArgs&{\n data: {\n frame: string,\n identifier: number,\n },\n };\n}\nexport function isTraceEventWebSocketReceiveHandshakeResponse(event: TraceEventData):\n event is TraceEventWebSocketReceiveHandshakeResponse {\n return event.name === KnownEventName.WebSocketReceiveHandshakeResponse;\n}\n\nexport interface TraceEventWebSocketDestroy extends TraceEventInstant {\n name: KnownEventName.WebSocketDestroy;\n args: TraceEventArgs&{\n data: {\n frame: string,\n identifier: number,\n },\n };\n}\nexport function isTraceEventWebSocketDestroy(event: TraceEventData): event is TraceEventWebSocketDestroy {\n return event.name === KnownEventName.WebSocketDestroy;\n}\n\nexport function isWebSocketTraceEvent(event: TraceEventData): event is TraceEventWebSocketCreate|\n TraceEventWebSocketDestroy|TraceEventWebSocketReceiveHandshakeResponse|TraceEventWebSocketSendHandshakeRequest {\n return isTraceEventWebSocketCreate(event) || isTraceEventWebSocketDestroy(event) ||\n isTraceEventWebSocketReceiveHandshakeResponse(event) || isTraceEventWebSocketSendHandshakeRequest(event);\n}\n\nexport interface TraceEventV8Compile extends TraceEventComplete {\n name: KnownEventName.Compile;\n args: TraceEventArgs&{\n data?: {\n url?: string,\n columnNumber?: number,\n lineNumber?: number,\n notStreamedReason?: string,\n streamed?: boolean,\n eager?: boolean,\n },\n fileName?: string,\n };\n}\nexport function isTraceEventV8Compile(event: TraceEventData): event is TraceEventV8Compile {\n return event.name === KnownEventName.Compile;\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 /* Metadata */\n ThreadName = 'thread_name',\n\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 CompileCode = 'V8.CompileCode',\n CompileModule = 'V8.CompileModule',\n // Although V8 emits the V8.CompileScript event, the event that actually\n // contains the useful information about the script (URL, etc), is contained\n // in the v8.compile event.\n // Yes, it is all lowercase compared to all the rest of the V8... events,\n // that is not a typo :)\n Compile = 'v8.compile',\n CompileScript = 'V8.CompileScript',\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 TracingStartedInBrowser = 'TracingStartedInBrowser',\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", "// 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.TraceWindowMicroSeconds,\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.TraceWindowMicroSeconds):\n 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.TraceWindowMicroSeconds {\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.TraceWindowMicroSeconds {\n const traceWindow: Types.Timing.TraceWindowMicroSeconds = {\n min: millisecondsToMicroseconds(min),\n max: millisecondsToMicroseconds(max),\n range: Types.Timing.MicroSeconds(millisecondsToMicroseconds(max) - millisecondsToMicroseconds(min)),\n };\n return traceWindow;\n}\n\nexport function traceWindowFromMicroSeconds(\n min: Types.Timing.MicroSeconds, max: Types.Timing.MicroSeconds): Types.Timing.TraceWindowMicroSeconds {\n const traceWindow: Types.Timing.TraceWindowMicroSeconds = {\n min,\n max,\n range: Types.Timing.MicroSeconds(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 stackTraceForEvent(event: Types.TraceEvents.TraceEventData): Types.TraceEvents.TraceEventCallFrame[]|\n null {\n if (Types.TraceEvents.isTraceEventSyntheticInvalidation(event)) {\n return event.stackTrace || null;\n }\n if (event.args?.data?.stackTrace) {\n return event.args.data.stackTrace;\n }\n if (Types.TraceEvents.isTraceEventUpdateLayoutTree(event)) {\n return event.args.beginData?.stackTrace || null;\n }\n return null;\n}\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|\n Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent): 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:\n Map<string,\n Map<Types.TraceEvents.ProcessID,\n {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindowMicroSeconds}[]>>): 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\nexport function matchBeginningAndEndEvents(unpairedEvents: Types.TraceEvents.TraceEventNestableAsync[]): 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 matchedPairs: 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 unpairedEvents) {\n const id = 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(matchedPairs, 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 = event;\n } else if (isEndEvent) {\n otherEventsWithID.end = event;\n }\n }\n\n return matchedPairs;\n}\n\nexport function createSortedSyntheticEvents(matchedPairs: Map<string, {\n begin: Types.TraceEvents.TraceEventNestableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventNestableAsyncEnd | null,\n}>): Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[] {\n const syntheticEvents: Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[] = [];\n for (const [id, eventsPair] of matchedPairs.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 // 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 syntheticEvents.push(event);\n }\n return syntheticEvents.sort((a, b) => a.ts - b.ts);\n}\n\nexport function createMatchedSortedSyntheticEvents(unpairedAsyncEvents: Types.TraceEvents.TraceEventNestableAsync[]):\n Types.TraceEvents.TraceEventSyntheticNestableAsyncEvent[] {\n const matchedPairs = matchBeginningAndEndEvents(unpairedAsyncEvents);\n const syntheticEvents = createSortedSyntheticEvents(matchedPairs);\n return syntheticEvents;\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\nlet nodeIdCount = 0;\nexport const makeTraceEntryNodeId = (): TraceEntryNodeId => (++nodeIdCount) as TraceEntryNodeId;\n\nexport const makeEmptyTraceEntryTree = (): TraceEntryTree => ({\n roots: new Set(),\n maxDepth: 0,\n});\n\nexport const makeEmptyTraceEntryNode = (entry: Types.TraceEvents.TraceEntry, id: TraceEntryNodeId): TraceEntryNode => ({\n entry,\n id,\n parent: null,\n children: [],\n depth: 0,\n});\n\nexport interface TraceEntryTree {\n roots: Set<TraceEntryNode>;\n maxDepth: number;\n}\n\nexport interface TraceEntryNode {\n entry: Types.TraceEvents.TraceEntry;\n depth: number;\n id: TraceEntryNodeId;\n parent: TraceEntryNode|null;\n children: 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\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.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 node.depth = stack.length;\n node.parent = parentNode;\n parentNode.children.push(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 */\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 traceWindowToInclude?: Types.Timing.TraceWindowMicroSeconds,\n minDuration?: Types.Timing.MicroSeconds,\n ): void {\n for (const rootNode of tree.roots) {\n walkTreeByNode(entryToNode, rootNode, onEntryStart, onEntryEnd, traceWindowToInclude, minDuration);\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 traceWindowToInclude?: Types.Timing.TraceWindowMicroSeconds,\n minDuration?: Types.Timing.MicroSeconds,\n ): void {\n if (traceWindowToInclude && !treeNodeIsInWindow(rootNode, traceWindowToInclude)) {\n // If this node is not within the provided window, we can skip it. We also\n // can skip all its children too, as we know they won't be in the window if\n // their parent is not.\n return;\n }\n\n if (typeof minDuration !== 'undefined') {\n const duration = Types.Timing.MicroSeconds(\n rootNode.entry.ts + Types.Timing.MicroSeconds(rootNode.entry.dur || 0),\n );\n if (duration < minDuration) {\n return;\n }\n }\n\n onEntryStart(rootNode.entry);\n for (const child of rootNode.children) {\n walkTreeByNode(entryToNode, child, onEntryStart, onEntryEnd, traceWindowToInclude, minDuration);\n }\n onEntryEnd(rootNode.entry);\n}\n\n/**\n * Returns true if the provided node is partially or fully within the trace\n * window. The entire node does not have to fit inside the window, but it does\n * have to partially intersect it.\n */\nfunction treeNodeIsInWindow(node: TraceEntryNode, traceWindow: Types.Timing.TraceWindowMicroSeconds): boolean {\n const startTime = node.entry.ts;\n const endTime = node.entry.ts + (node.entry.dur || 0);\n\n // Min ======= startTime ========= Max => node is within window\n if (startTime >= traceWindow.min && startTime < traceWindow.max) {\n return true;\n }\n\n // Min ======= endTime ========= Max => node is within window\n if (endTime > traceWindow.min && endTime <= traceWindow.max) {\n return true;\n }\n\n // startTime ==== Min ======== Max === endTime => node spans greater than the window so is in it.\n if (startTime <= traceWindow.min && endTime >= traceWindow.max) {\n return true;\n }\n\n return false;\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 EntriesFilter from './EntriesFilter.js';\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 RootCauses from './root-causes/root-causes.js';\nimport * as TracingManager from './TracingManager.js';\nimport * as Types from './types/types.js';\n\nexport {\n EntriesFilter,\n Extras,\n Handlers,\n Helpers,\n Legacy,\n Processor,\n RootCauses,\n TraceModel,\n TracingManager,\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 ModelHandlers from './ModelHandlers.js';\nexport * as Threads from './Threads.js';\nexport * as Types from './types.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\nexport * as Animations from './AnimationHandler.js';\nexport * as AuctionWorklets from './AuctionWorkletsHandler.js';\nexport * as Frames from './FramesHandler.js';\nexport * as GPU from './GPUHandler.js';\nexport * as Initiators from './InitiatorsHandler.js';\nexport * as Invalidations from './InvalidationsHandler.js';\nexport * as LargestImagePaint from './LargestImagePaintHandler.js';\nexport * as LargestTextPaint from './LargestTextPaintHandler.js';\nexport * as LayerTree from './LayerTreeHandler.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 Helpers from '../helpers/helpers.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 syntheticEvents = Helpers.Trace.createMatchedSortedSyntheticEvents(animations);\n animationsSyntheticEvents.push(...syntheticEvents);\n handlerState = HandlerState.FINALIZED;\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", "\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 * 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\n/**\n * Because you can run the trace engine with a subset of handlers enabled,\n * there can be times when you need to confirm if the trace contains all\n * handlers or not, because some parts of the engine expect to be given all\n * the handlers.\n */\nexport function handlerDataHasAllHandlers(data: Readonly<EnabledHandlerDataWithMeta<{}>>): data is TraceParseData {\n let isMissingHandler = false;\n for (const handlerName of Object.keys(ModelHandlers)) {\n if (handlerName in data === false) {\n isMissingHandler = true;\n break;\n }\n }\n return !isMissingHandler;\n}\n\ntype DeepWriteable<T> = {\n -readonly[P in keyof T]: DeepWriteable<T[P]>\n};\nexport type TraceParseDataMutable = DeepWriteable<TraceParseData>;\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 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\nimport {type AuctionWorkletsData, data as auctionWorkletsData} from './AuctionWorkletsHandler.js';\nimport {data as layerTreeHandlerData, type LayerTreeData} from './LayerTreeHandler.js';\nimport {data as metaHandlerData, type MetaHandlerData} from './MetaHandler.js';\nimport {data as rendererHandlerData, type RendererHandlerData} from './RendererHandler.js';\nimport * as Threads from './Threads.js';\nimport {HandlerState, type TraceEventHandlerName} from './types.js';\n\n/**\n * IMPORTANT: this handler is slightly different to the rest. This is because\n * it is an adaptation of the TimelineFrameModel that has been used in DevTools\n * for many years. Rather than re-implement all the logic from scratch, instead\n * this handler gathers up the events and instantitates the class in the\n * finalize() method. Once the class has parsed all events, it is used to then\n * return the array of frames.\n *\n * In time we expect to migrate this code to a more \"typical\" handler.\n */\nlet handlerState = HandlerState.UNINITIALIZED;\n\nconst allEvents: Types.TraceEvents.TraceEventData[] = [];\nlet model: TimelineFrameModel|null = null;\n\nexport function reset(): void {\n handlerState = HandlerState.UNINITIALIZED;\n allEvents.length = 0;\n}\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('FramesHandler was not reset before being initialized');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n allEvents.push(event);\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('FramesHandler is not initialized');\n }\n\n // Snapshot events can be emitted out of order, so we need to sort before\n // building the frames model.\n Helpers.Trace.sortTraceEventsInPlace(allEvents);\n\n const modelForTrace = new TimelineFrameModel(\n allEvents,\n rendererHandlerData(),\n auctionWorkletsData(),\n metaHandlerData(),\n layerTreeHandlerData(),\n );\n model = modelForTrace;\n}\n\nexport interface FramesData {\n frames: readonly TimelineFrame[];\n framesById: Readonly<Record<number, TimelineFrame|undefined>>;\n}\n\nexport function data(): FramesData {\n return {\n frames: model ? Array.from(model.frames()) : [],\n framesById: model ? {...model.framesById()} : {},\n };\n}\n\nexport function deps(): TraceEventHandlerName[] {\n return ['Meta', 'Renderer', 'AuctionWorklets', 'LayerTree'];\n}\n\ntype FrameEvent = Types.TraceEvents.TraceEventBeginFrame|Types.TraceEvents.TraceEventDroppedFrame|\n Types.TraceEvents.TraceEventRequestMainThreadFrame|\n Types.TraceEvents.TraceEventBeginMainThreadFrame|Types.TraceEvents.TraceEventCommit|\n Types.TraceEvents.TraceEventCompositeLayers|Types.TraceEvents.TraceEventActivateLayerTree|\n Types.TraceEvents.TraceEventNeedsBeginFrameChanged|Types.TraceEvents.TraceEventDrawFrame;\n\nfunction isFrameEvent(event: Types.TraceEvents.TraceEventData): event is FrameEvent {\n return (\n Types.TraceEvents.isTraceEventSetLayerId(event) || Types.TraceEvents.isTraceEventBeginFrame(event) ||\n Types.TraceEvents.isTraceEventDroppedFrame(event) ||\n Types.TraceEvents.isTraceEventRequestMainThreadFrame(event) ||\n Types.TraceEvents.isTraceEventBeginMainThreadFrame(event) ||\n Types.TraceEvents.isTraceEventNeedsBeginFrameChanged(event) ||\n // Note that \"Commit\" is the replacement for \"CompositeLayers\" so in a trace\n // we wouldn't expect to see a combination of these. All \"new\" trace\n // recordings use \"Commit\", but we can easily support \"CompositeLayers\" too\n // to not break older traces being imported.\n Types.TraceEvents.isTraceEventCommit(event) || Types.TraceEvents.isTraceEventCompositeLayers(event) ||\n Types.TraceEvents.isTraceEventActivateLayerTree(event) || Types.TraceEvents.isTraceEventDrawFrame(event));\n}\n\nfunction entryIsTopLevel(entry: Types.TraceEvents.TraceEventData): boolean {\n const devtoolsTimelineCategory = 'disabled-by-default-devtools.timeline';\n return entry.name === Types.TraceEvents.KnownEventName.RunTask && entry.cat.includes(devtoolsTimelineCategory);\n}\n\nexport class TimelineFrameModel {\n #frames: TimelineFrame[] = [];\n #frameById: {\n [x: number]: TimelineFrame,\n } = {};\n #beginFrameQueue: TimelineFrameBeginFrameQueue = new TimelineFrameBeginFrameQueue();\n #lastFrame: TimelineFrame|null = null;\n #mainFrameCommitted = false;\n #mainFrameRequested = false;\n #lastLayerTree: FrameLayerTreeData|null = null;\n #framePendingActivation: PendingFrame|null = null;\n #framePendingCommit: PendingFrame|null = null;\n #lastBeginFrame: number|null = null;\n #lastNeedsBeginFrame: number|null = null;\n #lastTaskBeginTime: Types.Timing.MicroSeconds|null = null;\n #layerTreeId: number|null = null;\n #activeProcessId: Types.TraceEvents.ProcessID|null = null;\n #activeThreadId: Types.TraceEvents.ThreadID|null = null;\n #layerTreeData: LayerTreeData;\n\n constructor(\n allEvents: readonly Types.TraceEvents.TraceEventData[], rendererData: RendererHandlerData,\n auctionWorkletsData: AuctionWorkletsData, metaData: MetaHandlerData, layerTreeData: LayerTreeData) {\n // We only care about getting threads from the Renderer, not Samples,\n // because Frames don't exist in a CPU Profile (which won't have Renderer\n // threads.)\n const mainThreads = Threads.threadsInRenderer(rendererData, auctionWorkletsData).filter(thread => {\n return thread.type === Threads.ThreadType.MAIN_THREAD && thread.processIsOnMainFrame;\n });\n const threadData = mainThreads.map(thread => {\n return {\n tid: thread.tid,\n pid: thread.pid,\n startTime: thread.entries[0].ts,\n };\n });\n\n this.#layerTreeData = layerTreeData;\n this.#addTraceEvents(allEvents, threadData, metaData.mainFrameId);\n }\n\n framesById(): Readonly<Record<number, TimelineFrame|undefined>> {\n return this.#frameById;\n }\n\n frames(): TimelineFrame[] {\n return this.#frames;\n }\n\n #handleBeginFrame(startTime: Types.Timing.MicroSeconds, seqId: number): void {\n if (!this.#lastFrame) {\n this.#startFrame(startTime, seqId);\n }\n this.#lastBeginFrame = startTime;\n\n this.#beginFrameQueue.addFrameIfNotExists(seqId, startTime, false, false);\n }\n\n #handleDroppedFrame(startTime: Types.Timing.MicroSeconds, seqId: number, isPartial: boolean): void {\n if (!this.#lastFrame) {\n this.#startFrame(startTime, seqId);\n }\n\n // This line handles the case where no BeginFrame event is issued for\n // the dropped frame. In this situation, add a BeginFrame to the queue\n // as if it actually occurred.\n this.#beginFrameQueue.addFrameIfNotExists(seqId, startTime, true, isPartial);\n this.#beginFrameQueue.setDropped(seqId, true);\n this.#beginFrameQueue.setPartial(seqId, isPartial);\n }\n\n #handleDrawFrame(startTime: Types.Timing.MicroSeconds, seqId: number): void {\n if (!this.#lastFrame) {\n this.#startFrame(startTime, seqId);\n return;\n }\n\n // - if it wasn't drawn, it didn't happen!\n // - only show frames that either did not wait for the main thread frame or had one committed.\n if (this.#mainFrameCommitted || !this.#mainFrameRequested) {\n if (this.#lastNeedsBeginFrame) {\n const idleTimeEnd = this.#framePendingActivation ? this.#framePendingActivation.triggerTime :\n (this.#lastBeginFrame || this.#lastNeedsBeginFrame);\n if (idleTimeEnd > this.#lastFrame.startTime) {\n this.#lastFrame.idle = true;\n this.#lastBeginFrame = null;\n }\n this.#lastNeedsBeginFrame = null;\n }\n\n const framesToVisualize = this.#beginFrameQueue.processPendingBeginFramesOnDrawFrame(seqId);\n\n // Visualize the current frame and all pending frames before it.\n for (const frame of framesToVisualize) {\n const isLastFrameIdle = this.#lastFrame.idle;\n\n // If |frame| is the first frame after an idle period, the CPU time\n // will be logged (\"committed\") under |frame| if applicable.\n this.#startFrame(frame.startTime, seqId);\n if (isLastFrameIdle && this.#framePendingActivation) {\n this.#commitPendingFrame();\n }\n if (frame.isDropped) {\n this.#lastFrame.dropped = true;\n }\n if (frame.isPartial) {\n this.#lastFrame.isPartial = true;\n }\n }\n }\n this.#mainFrameCommitted = false;\n }\n\n #handleActivateLayerTree(): void {\n if (!this.#lastFrame) {\n return;\n }\n if (this.#framePendingActivation && !this.#lastNeedsBeginFrame) {\n this.#commitPendingFrame();\n }\n }\n\n #handleRequestMainThreadFrame(): void {\n if (!this.#lastFrame) {\n return;\n }\n this.#mainFrameRequested = true;\n }\n\n #handleCommit(): void {\n if (!this.#framePendingCommit) {\n return;\n }\n this.#framePendingActivation = this.#framePendingCommit;\n this.#framePendingCommit = null;\n this.#mainFrameRequested = false;\n this.#mainFrameCommitted = true;\n }\n\n #handleLayerTreeSnapshot(layerTree: FrameLayerTreeData): void {\n this.#lastLayerTree = layerTree;\n }\n\n #handleNeedFrameChanged(startTime: Types.Timing.MicroSeconds, needsBeginFrame: boolean): void {\n if (needsBeginFrame) {\n this.#lastNeedsBeginFrame = startTime;\n }\n }\n\n #startFrame(startTime: Types.Timing.MicroSeconds, seqId: number): void {\n if (this.#lastFrame) {\n this.#flushFrame(this.#lastFrame, startTime);\n }\n this.#lastFrame =\n new TimelineFrame(seqId, startTime, Types.Timing.MicroSeconds(startTime - metaHandlerData().traceBounds.min));\n }\n\n #flushFrame(frame: TimelineFrame, endTime: Types.Timing.MicroSeconds): void {\n frame.setLayerTree(this.#lastLayerTree);\n frame.setEndTime(endTime);\n if (this.#lastLayerTree) {\n this.#lastLayerTree.paints = frame.paints;\n }\n const lastFrame = this.#frames[this.#frames.length - 1];\n if (this.#frames.length && lastFrame &&\n (frame.startTime !== lastFrame.endTime || frame.startTime > frame.endTime)) {\n console.assert(\n false, `Inconsistent frame time for frame ${this.#frames.length} (${frame.startTime} - ${frame.endTime})`);\n }\n this.#frames.push(frame);\n if (typeof frame.mainFrameId === 'number') {\n this.#frameById[frame.mainFrameId] = frame;\n }\n }\n\n #commitPendingFrame(): void {\n if (!this.#framePendingActivation || !this.#lastFrame) {\n return;\n }\n\n this.#lastFrame.paints = this.#framePendingActivation.paints;\n this.#lastFrame.mainFrameId = this.#framePendingActivation.mainFrameId;\n this.#framePendingActivation = null;\n }\n\n #addTraceEvents(\n events: readonly Types.TraceEvents.TraceEventData[], threadData: {\n pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID,\n startTime: Types.Timing.MicroSeconds,\n }[],\n mainFrameId: string): void {\n let j = 0;\n this.#activeThreadId = threadData.length && threadData[0].tid || null;\n this.#activeProcessId = threadData.length && threadData[0].pid || null;\n for (let i = 0; i < events.length; ++i) {\n while (j + 1 < threadData.length && threadData[j + 1].startTime <= events[i].ts) {\n this.#activeThreadId = threadData[++j].tid;\n this.#activeProcessId = threadData[j].pid;\n }\n this.#addTraceEvent(events[i], mainFrameId);\n }\n this.#activeThreadId = null;\n this.#activeProcessId = null;\n }\n\n #addTraceEvent(event: Types.TraceEvents.TraceEventData, mainFrameId: string): void {\n if (Types.TraceEvents.isTraceEventSetLayerId(event) && event.args.data.frame === mainFrameId) {\n this.#layerTreeId = event.args.data.layerTreeId;\n } else if (\n Types.TraceEvents.isTraceEventLayerTreeHostImplSnapshot(event) && Number(event.id) === this.#layerTreeId) {\n this.#handleLayerTreeSnapshot({\n entry: event,\n paints: [],\n });\n } else {\n if (isFrameEvent(event)) {\n this.#processCompositorEvents(event);\n }\n // Make sure we only use events from the main thread: we check the PID as\n // well in case two processes have a thread with the same TID.\n if (event.tid === this.#activeThreadId && event.pid === this.#activeProcessId) {\n this.#addMainThreadTraceEvent(event);\n }\n }\n }\n\n #processCompositorEvents(entry: FrameEvent): void {\n if (entry.args['layerTreeId'] !== this.#layerTreeId) {\n return;\n }\n if (Types.TraceEvents.isTraceEventBeginFrame(entry)) {\n this.#handleBeginFrame(entry.ts, entry.args['frameSeqId']);\n } else if (Types.TraceEvents.isTraceEventDrawFrame(entry)) {\n this.#handleDrawFrame(entry.ts, entry.args['frameSeqId']);\n } else if (Types.TraceEvents.isTraceEventActivateLayerTree(entry)) {\n this.#handleActivateLayerTree();\n } else if (Types.TraceEvents.isTraceEventRequestMainThreadFrame(entry)) {\n this.#handleRequestMainThreadFrame();\n } else if (Types.TraceEvents.isTraceEventNeedsBeginFrameChanged(entry)) {\n // needsBeginFrame property will either be 0 or 1, which represents\n // true/false in this case, hence the Boolean() wrapper.\n this.#handleNeedFrameChanged(entry.ts, entry.args['data'] && Boolean(entry.args['data']['needsBeginFrame']));\n } else if (Types.TraceEvents.isTraceEventDroppedFrame(entry)) {\n this.#handleDroppedFrame(entry.ts, entry.args['frameSeqId'], Boolean(entry.args['hasPartialUpdate']));\n }\n }\n\n #addMainThreadTraceEvent(entry: Types.TraceEvents.TraceEventData): void {\n if (entryIsTopLevel(entry)) {\n this.#lastTaskBeginTime = entry.ts;\n }\n if (!this.#framePendingCommit && MAIN_FRAME_MARKERS.has(entry.name as Types.TraceEvents.KnownEventName)) {\n this.#framePendingCommit = new PendingFrame(this.#lastTaskBeginTime || entry.ts);\n }\n if (!this.#framePendingCommit) {\n return;\n }\n\n if (Types.TraceEvents.isTraceEventBeginMainThreadFrame(entry) && entry.args.data.frameId) {\n this.#framePendingCommit.mainFrameId = entry.args.data.frameId;\n }\n if (Types.TraceEvents.isTraceEventPaint(entry)) {\n const snapshot = this.#layerTreeData.paintsToSnapshots.get(entry);\n if (snapshot) {\n this.#framePendingCommit.paints.push(new LayerPaintEvent(entry, snapshot));\n }\n }\n // Commit will be replacing CompositeLayers but CompositeLayers is kept\n // around for backwards compatibility.\n if ((Types.TraceEvents.isTraceEventCompositeLayers(entry) || Types.TraceEvents.isTraceEventCommit(entry)) &&\n entry.args['layerTreeId'] === this.#layerTreeId) {\n this.#handleCommit();\n }\n }\n}\n\nconst MAIN_FRAME_MARKERS = new Set<Types.TraceEvents.KnownEventName>([\n Types.TraceEvents.KnownEventName.ScheduleStyleRecalculation,\n Types.TraceEvents.KnownEventName.InvalidateLayout,\n Types.TraceEvents.KnownEventName.BeginMainThreadFrame,\n Types.TraceEvents.KnownEventName.ScrollLayer,\n]);\n\nexport interface FrameLayerTreeData {\n entry: Types.TraceEvents.TraceEventLayerTreeHostImplSnapshot;\n paints: LayerPaintEvent[];\n}\n\nexport class TimelineFrame {\n startTime: Types.Timing.MicroSeconds;\n startTimeOffset: Types.Timing.MicroSeconds;\n endTime: Types.Timing.MicroSeconds;\n duration: Types.Timing.MicroSeconds;\n idle: boolean;\n dropped: boolean;\n isPartial: boolean;\n layerTree: FrameLayerTreeData|null;\n paints: LayerPaintEvent[];\n mainFrameId: number|undefined;\n readonly seqId: number;\n\n constructor(seqId: number, startTime: Types.Timing.MicroSeconds, startTimeOffset: Types.Timing.MicroSeconds) {\n this.seqId = seqId;\n this.startTime = startTime;\n this.startTimeOffset = startTimeOffset;\n this.endTime = this.startTime;\n this.duration = Types.Timing.MicroSeconds(0);\n this.idle = false;\n this.dropped = false;\n this.isPartial = false;\n this.layerTree = null;\n this.paints = [];\n this.mainFrameId = undefined;\n }\n\n setEndTime(endTime: Types.Timing.MicroSeconds): void {\n this.endTime = endTime;\n this.duration = Types.Timing.MicroSeconds(this.endTime - this.startTime);\n }\n\n setLayerTree(layerTree: FrameLayerTreeData|null): void {\n this.layerTree = layerTree;\n }\n}\n\nexport interface LayerPaintEventPicture {\n rect: Array<number>;\n serializedPicture: string;\n}\nexport class LayerPaintEvent {\n readonly #event: Types.TraceEvents.TraceEventPaint;\n #snapshot: Types.TraceEvents.TraceEventDisplayItemListSnapshot;\n\n constructor(event: Types.TraceEvents.TraceEventPaint, snapshot: Types.TraceEvents.TraceEventDisplayItemListSnapshot) {\n this.#event = event;\n this.#snapshot = snapshot;\n }\n\n layerId(): number {\n return this.#event.args.data.layerId;\n }\n\n event(): Types.TraceEvents.TraceEventPaint {\n return this.#event;\n }\n\n picture(): LayerPaintEventPicture|null {\n const rect = this.#snapshot.args.snapshot.params?.layer_rect;\n const pictureData = this.#snapshot.args.snapshot.skp64;\n return rect && pictureData ? {rect: rect, serializedPicture: pictureData} : null;\n }\n}\n\nexport class PendingFrame {\n paints: LayerPaintEvent[];\n mainFrameId: number|undefined;\n triggerTime: number;\n constructor(triggerTime: number) {\n this.paints = [];\n this.mainFrameId = undefined;\n this.triggerTime = triggerTime;\n }\n}\n\n// The parameters of an impl-side BeginFrame.\nclass BeginFrameInfo {\n seqId: number;\n startTime: Types.Timing.MicroSeconds;\n isDropped: boolean;\n isPartial: boolean;\n constructor(seqId: number, startTime: Types.Timing.MicroSeconds, isDropped: boolean, isPartial: boolean) {\n this.seqId = seqId;\n this.startTime = startTime;\n this.isDropped = isDropped;\n this.isPartial = isPartial;\n }\n}\n\n// A queue of BeginFrames pending visualization.\n// BeginFrames are added into this queue as they occur; later when their\n// corresponding DrawFrames occur (or lack thereof), the BeginFrames are removed\n// from the queue and their timestamps are used for visualization.\nexport class TimelineFrameBeginFrameQueue {\n private queueFrames: number[] = [];\n\n // Maps frameSeqId to BeginFrameInfo.\n private mapFrames: {\n [x: number]: BeginFrameInfo,\n } = {};\n\n // Add a BeginFrame to the queue, if it does not already exit.\n addFrameIfNotExists(seqId: number, startTime: Types.Timing.MicroSeconds, isDropped: boolean, isPartial: boolean):\n void {\n if (!(seqId in this.mapFrames)) {\n this.mapFrames[seqId] = new BeginFrameInfo(seqId, startTime, isDropped, isPartial);\n this.queueFrames.push(seqId);\n }\n }\n\n // Set a BeginFrame in queue as dropped.\n setDropped(seqId: number, isDropped: boolean): void {\n if (seqId in this.mapFrames) {\n this.mapFrames[seqId].isDropped = isDropped;\n }\n }\n\n setPartial(seqId: number, isPartial: boolean): void {\n if (seqId in this.mapFrames) {\n this.mapFrames[seqId].isPartial = isPartial;\n }\n }\n\n processPendingBeginFramesOnDrawFrame(seqId: number): BeginFrameInfo[] {\n const framesToVisualize: BeginFrameInfo[] = [];\n\n // Do not visualize this frame in the rare case where the current DrawFrame\n // does not have a corresponding BeginFrame.\n if (seqId in this.mapFrames) {\n // Pop all BeginFrames before the current frame, and add only the dropped\n // ones in |frames_to_visualize|.\n // Non-dropped frames popped here are BeginFrames that are never\n // drawn (but not considered dropped either for some reason).\n // Those frames do not require an proactive visualization effort and will\n // be naturally presented as continuationss of other frames.\n while (this.queueFrames[0] !== seqId) {\n const currentSeqId = this.queueFrames[0];\n if (this.mapFrames[currentSeqId].isDropped) {\n framesToVisualize.push(this.mapFrames[currentSeqId]);\n }\n\n delete this.mapFrames[currentSeqId];\n this.queueFrames.shift();\n }\n\n // Pop the BeginFrame associated with the current DrawFrame.\n framesToVisualize.push(this.mapFrames[seqId]);\n delete this.mapFrames[seqId];\n this.queueFrames.shift();\n }\n return framesToVisualize;\n }\n}\n\nexport function framesWithinWindow(\n frames: readonly TimelineFrame[], startTime: Types.Timing.MicroSeconds,\n endTime: Types.Timing.MicroSeconds): TimelineFrame[] {\n const firstFrame = Platform.ArrayUtilities.lowerBound(frames, startTime || 0, (time, frame) => time - frame.endTime);\n const lastFrame =\n Platform.ArrayUtilities.lowerBound(frames, endTime || Infinity, (time, frame) => time - frame.startTime);\n return frames.slice(firstFrame, lastFrame);\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 Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport {HandlerState, type TraceEventHandlerName} from './types.js';\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\nconst paintEvents: Types.TraceEvents.TraceEventPaint[] = [];\nconst snapshotEvents: Types.TraceEvents.TraceEventDisplayItemListSnapshot[] = [];\nconst paintToSnapshotMap =\n new Map<Types.TraceEvents.TraceEventPaint, Types.TraceEvents.TraceEventDisplayItemListSnapshot>();\n\nlet lastPaintForLayerId: Record<number, Types.TraceEvents.TraceEventPaint> = {};\n\nlet currentMainFrameLayerTreeId: number|null = null;\nconst updateLayerEvents: Types.TraceEvents.TraceEventUpdateLayer[] = [];\n\ntype RelevantLayerTreeEvent = Types.TraceEvents.TraceEventPaint|\n Types.TraceEvents.TraceEventDisplayItemListSnapshot|\n Types.TraceEvents.TraceEventUpdateLayer|Types.TraceEvents.TraceEventSetLayerTreeId;\n\nconst relevantEvents: RelevantLayerTreeEvent[] = [];\nexport function reset(): void {\n handlerState = HandlerState.UNINITIALIZED;\n paintEvents.length = 0;\n snapshotEvents.length = 0;\n paintToSnapshotMap.clear();\n\n lastPaintForLayerId = {};\n currentMainFrameLayerTreeId = null;\n updateLayerEvents.length = 0;\n relevantEvents.length = 0;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('LayerTree Handler was not reset before being initialized');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n // We gather up the events here but do all the processing in finalize(). This\n // is because we need to have all the events before we process them, and we\n // need the Meta handler to be finalized() so we can use its data as we need\n // the mainFrameId to know which Layer(s) to care about.\n if (Types.TraceEvents.isTraceEventPaint(event) || Types.TraceEvents.isTraceEventDisplayListItemListSnapshot(event) ||\n Types.TraceEvents.isTraceEventUpdateLayer(event) || Types.TraceEvents.isTraceEventSetLayerId(event)) {\n relevantEvents.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('LayerTree Handler is not initialized');\n }\n\n const metaData = metaHandlerData();\n Helpers.Trace.sortTraceEventsInPlace(relevantEvents);\n\n for (const event of relevantEvents) {\n if (Types.TraceEvents.isTraceEventSetLayerId(event)) {\n if (metaData.mainFrameId !== event.args.data.frame) {\n // We only care about LayerId changes that affect the main frame.\n continue;\n }\n currentMainFrameLayerTreeId = event.args.data.layerTreeId;\n } else if (Types.TraceEvents.isTraceEventUpdateLayer(event)) {\n // We don't do anything with this event, but we need to store it because\n // the information in it determines if we need to care about future\n // snapshot events - we need to know what the active layer is when we see a\n // snapshot.\n updateLayerEvents.push(event);\n } else if (Types.TraceEvents.isTraceEventPaint(event)) {\n if (!event.args.data.layerId) {\n // Note that this check purposefully includes excluding an event with a layerId of 0.\n // 0 indicates that this paint was for a subframe - we do not want these\n // as we only care about paints for top level frames.\n continue;\n }\n paintEvents.push(event);\n lastPaintForLayerId[event.args.data.layerId] = event;\n continue;\n } else if (Types.TraceEvents.isTraceEventDisplayListItemListSnapshot(event)) {\n // First we figure out which layer is active for this event's thread. To\n // do this we work backwards through the list of UpdateLayerEvents,\n // finding the first one (i.e. the most recent one) with the same pid and\n // tid.\n let lastUpdateLayerEventForThread: Types.TraceEvents.TraceEventUpdateLayer|null = null;\n for (let i = updateLayerEvents.length - 1; i > -1; i--) {\n const updateEvent = updateLayerEvents[i];\n if (updateEvent.pid === event.pid && updateEvent.tid === event.tid) {\n lastUpdateLayerEventForThread = updateEvent;\n break;\n }\n }\n if (!lastUpdateLayerEventForThread) {\n // No active layer, so this snapshot is not relevant.\n continue;\n }\n if (lastUpdateLayerEventForThread.args.layerTreeId !== currentMainFrameLayerTreeId) {\n // Snapshot applies to a layer that is not the main frame, so discard.\n continue;\n }\n const paintEvent = lastPaintForLayerId[lastUpdateLayerEventForThread.args.layerId];\n if (!paintEvent) {\n // No paint event for this layer, so discard.\n continue;\n }\n snapshotEvents.push(event);\n\n // Store the relationship between the paint and the snapshot.\n paintToSnapshotMap.set(paintEvent, event);\n }\n }\n\n handlerState = HandlerState.FINALIZED;\n}\n\nexport interface LayerTreeData {\n paints: Types.TraceEvents.TraceEventPaint[];\n snapshots: Types.TraceEvents.TraceEventDisplayItemListSnapshot[];\n paintsToSnapshots: Map<Types.TraceEvents.TraceEventPaint, Types.TraceEvents.TraceEventDisplayItemListSnapshot>;\n}\n\nexport function data(): LayerTreeData {\n return {\n paints: Array.from(paintEvents),\n snapshots: Array.from(snapshotEvents),\n paintsToSnapshots: new Map(paintToSnapshotMap),\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 Helpers from '../helpers/helpers.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 processNames: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventProcessName> = new Map();\n\nconst topLevelRendererIds = new Set<Types.TraceEvents.ProcessID>();\nconst traceBounds: Types.Timing.TraceWindowMicroSeconds = {\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;\n// Tracks if the trace is a generic trace, which here means that it did not come from athe DevTools Performance Panel recording.\n// We assume a trace is generic, and mark it as not generic if we see any of:\n// - TracingStartedInPage\n// - TracingStartedInBrowser\n// - TracingSessionIdForWorker\n// These are all events which indicate this is a Chrome browser trace.\nlet traceIsGeneric = true;\nconst CHROME_WEB_TRACE_EVENTS = new Set([\n Types.TraceEvents.KnownEventName.TracingStartedInPage,\n Types.TraceEvents.KnownEventName.TracingSessionIdForWorker,\n Types.TraceEvents.KnownEventName.TracingStartedInBrowser,\n\n]);\n\nexport function reset(): void {\n navigationsByFrameId.clear();\n navigationsByNavigationId.clear();\n processNames.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 traceIsGeneric = true;\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,\n {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindowMicroSeconds}[]>());\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 (traceIsGeneric && CHROME_WEB_TRACE_EVENTS.has(event.name as Types.TraceEvents.KnownEventName)) {\n traceIsGeneric = false;\n }\n\n if (Types.TraceEvents.isProcessName(event)) {\n processNames.set(event.pid, event);\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 // (The filtering of empty URLs is done in the\n // isTraceEventNavigationStartWithURL check)\n if (Types.TraceEvents.isTraceEventNavigationStartWithURL(event) && event.args.data) {\n const navigationId = event.args.data.navigationId;\n if (navigationsByNavigationId.has(navigationId)) {\n // We have only ever seen this situation once, in crbug.com/1503982, where the user ran:\n // window.location.href = 'javascript:console.log(\"foo\")'\n // In this situation two identical navigationStart events are emitted with the same data, URL and ID.\n // So, in this situation we drop/ignore any subsequent navigations if we have already seen that ID.\n return;\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 // Sometimes in traces the TracingStartedInBrowser event can give us an\n // incorrect initial URL for the main frame's URL - about:blank or the URL of\n // the previous page. This doesn't matter too much except we often use this\n // URL as the visual name of the trace shown to the user (e.g. in the history\n // dropdown). We can be more accurate by finding the first main frame\n // navigaton, and using its URL, if we have it.\n // However, to avoid doing this in a case where the first navigation is far\n // into the trace's lifecycle, we only do this in situations where the first\n // navigation happened very soon (0.5 seconds) after the trace started\n // recording.\n const firstMainFrameNav = mainFrameNavigations.at(0);\n const firstNavTimeThreshold = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(0.5));\n if (firstMainFrameNav) {\n const navigationIsWithinThreshold = firstMainFrameNav.ts - traceBounds.min < firstNavTimeThreshold;\n if (firstMainFrameNav.args.data?.isOutermostMainFrame && firstMainFrameNav.args.data?.documentLoaderURL &&\n navigationIsWithinThreshold) {\n mainFrameURL = firstMainFrameNav.args.data.documentLoaderURL;\n }\n }\n\n handlerState = HandlerState.FINALIZED;\n}\n\nexport type MetaHandlerData = {\n traceIsGeneric: boolean,\n traceBounds: Types.Timing.TraceWindowMicroSeconds,\n browserProcessId: Types.TraceEvents.ProcessID,\n processNames: Map<Types.TraceEvents.ProcessID, Types.TraceEvents.TraceEventProcessName>,\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,\n {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindowMicroSeconds}[]>>;\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 processNames: new Map(processNames),\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 traceIsGeneric,\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 {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();\nlet allTraceEntries: Types.TraceEvents.TraceEntry[] = [];\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 allTraceEntries.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 allTraceEntries.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 allTraceEntries.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 Helpers.Trace.sortTraceEventsInPlace(allTraceEntries);\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 allTraceEntries: [...allTraceEntries],\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 [pid, process] of processes) {\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 * 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 const metaData = metaHandlerData();\n if (metaData.traceIsGeneric) {\n return;\n }\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 }\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 allTraceEntries = [...allTraceEntries, ...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 allTraceEntries: Types.TraceEvents.TraceEntry[];\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 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.parent = parentNode;\n parentNode.children.push(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?.length) {\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 AuctionWorkletsData} from './AuctionWorkletsHandler.js';\nimport type * as Renderer from './RendererHandler.js';\nimport {type TraceParseData} from './types.js';\n\nexport interface ThreadData {\n pid: Types.TraceEvents.ProcessID;\n tid: Types.TraceEvents.ThreadID;\n entries: readonly Types.TraceEvents.TraceEntry[];\n processIsOnMainFrame: boolean;\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 THREAD_POOL = 'THREAD_POOL',\n}\n\nfunction getThreadTypeForRendererThread(\n auctionWorkletsData: AuctionWorkletsData, pid: Types.TraceEvents.ProcessID,\n 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 (auctionWorkletsData.worklets.has(pid)) {\n threadType = ThreadType.AUCTION_WORKLET;\n } else if (thread.name?.startsWith('ThreadPool')) {\n // TODO(paulirish): perhaps exclude ThreadPoolServiceThread entirely\n threadType = ThreadType.THREAD_POOL;\n }\n return threadType;\n}\n\nexport function threadsInRenderer(\n rendererData: Renderer.RendererHandlerData, auctionWorkletsData: AuctionWorkletsData): 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 (rendererData.processes.size) {\n for (const [pid, process] of rendererData.processes) {\n for (const [tid, thread] of process.threads) {\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 const threadType = getThreadTypeForRendererThread(auctionWorkletsData, pid, thread);\n foundThreads.push({\n name: thread.name,\n pid,\n tid,\n processIsOnMainFrame: process.isOnMainFrame,\n entries: thread.entries,\n tree: thread.tree,\n type: threadType,\n entryToNode: rendererData.entryToNode,\n });\n }\n }\n }\n return foundThreads;\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: TraceParseData): readonly 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 const threadsFromRenderer = threadsInRenderer(traceParseData.Renderer, traceParseData.AuctionWorklets);\n if (threadsFromRenderer.length) {\n return threadsFromRenderer;\n }\n\n const foundThreads: ThreadData[] = [];\n if (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 // There is no concept of a \"Main Frame\" in a CPU profile.\n processIsOnMainFrame: false,\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 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 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 Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {HandlerState} from './types.js';\n\nlet handlerState = HandlerState.UNINITIALIZED;\n\nconst lastScheduleStyleRecalcByFrame = new Map<string, Types.TraceEvents.TraceEventScheduleStyleRecalculation>();\n\n// This tracks the last event that is considered to have invalidated the layout\n// for a given frame.\n// Note that although there is an InvalidateLayout event, there are also other\n// events (ScheduleStyleRecalculation) that could be the reason a layout was\n// invalidated.\nconst lastInvalidationEventForFrame = new Map<string, Types.TraceEvents.TraceEventData>();\n\n// Important: although the event is called UpdateLayoutTree, in the UI we\n// present these to the user as \"Recalculate Style\". So don't get confused!\n// These are the same - just UpdateLayoutTree is what the event from Chromium\n// is called.\nconst lastUpdateLayoutTreeByFrame = new Map<string, Types.TraceEvents.TraceEventUpdateLayoutTree>();\n\n// These two maps store the same data but in different directions.\n//\n// For a given event, tell me what its initiator was. An event can only have one initiator.\nconst eventToInitiatorMap = new Map<Types.TraceEvents.TraceEventData, Types.TraceEvents.TraceEventData>();\n// For a given event, tell me what events it initiated. An event can initiate\n// multiple events, hence why the value for this map is an array.\nconst initiatorToEventsMap = new Map<Types.TraceEvents.TraceEventData, Types.TraceEvents.TraceEventData[]>();\n\nconst requestAnimationFrameEventsById: Map<number, Types.TraceEvents.TraceEventRequestAnimationFrame> = new Map();\nconst timerInstallEventsById: Map<number, Types.TraceEvents.TraceEventTimerInstall> = new Map();\nconst requestIdleCallbackEventsById: Map<number, Types.TraceEvents.TraceEventRequestIdleCallback> = new Map();\nconst webSocketCreateEventsById: Map<number, Types.TraceEvents.TraceEventWebSocketCreate> = new Map();\n\nexport function reset(): void {\n lastScheduleStyleRecalcByFrame.clear();\n lastInvalidationEventForFrame.clear();\n lastUpdateLayoutTreeByFrame.clear();\n timerInstallEventsById.clear();\n eventToInitiatorMap.clear();\n initiatorToEventsMap.clear();\n requestAnimationFrameEventsById.clear();\n requestIdleCallbackEventsById.clear();\n webSocketCreateEventsById.clear();\n\n handlerState = HandlerState.UNINITIALIZED;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('InitiatorsHandler was not reset before being initialized');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nfunction storeInitiator(data: {initiator: Types.TraceEvents.TraceEventData, event: Types.TraceEvents.TraceEventData}):\n void {\n eventToInitiatorMap.set(data.event, data.initiator);\n const eventsForInitiator = initiatorToEventsMap.get(data.initiator) || [];\n eventsForInitiator.push(data.event);\n initiatorToEventsMap.set(data.initiator, eventsForInitiator);\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (Types.TraceEvents.isTraceEventScheduleStyleRecalculation(event)) {\n lastScheduleStyleRecalcByFrame.set(event.args.data.frame, event);\n } else if (Types.TraceEvents.isTraceEventUpdateLayoutTree(event)) {\n // IMPORTANT: although the trace event is called UpdateLayoutTree, this\n // represents a Styles Recalculation. This event in the timeline is shown to\n // the user as \"Recalculate Styles.\"\n if (event.args.beginData) {\n // Store the last UpdateLayout event: we use this when we see an\n // InvalidateLayout and try to figure out its initiator.\n lastUpdateLayoutTreeByFrame.set(event.args.beginData.frame, event);\n\n // If this frame has seen a ScheduleStyleRecalc event, then that event is\n // considered to be the initiator of this StylesRecalc.\n const scheduledStyleForFrame = lastScheduleStyleRecalcByFrame.get(event.args.beginData.frame);\n if (scheduledStyleForFrame) {\n storeInitiator({\n event,\n initiator: scheduledStyleForFrame,\n });\n }\n }\n } else if (Types.TraceEvents.isTraceEventInvalidateLayout(event)) {\n // By default, the InvalidateLayout event is what triggered the layout invalidation for this frame.\n let invalidationInitiator: Types.TraceEvents.TraceEventData = event;\n\n // However, if we have not had any prior invalidations for this frame, we\n // want to consider StyleRecalculation events as they might be the actual\n // cause of this layout invalidation.\n if (!lastInvalidationEventForFrame.has(event.args.data.frame)) {\n // 1. If we have not had an invalidation event for this frame\n // 2. AND we have had an UpdateLayoutTree for this frame\n // 3. AND the UpdateLayoutTree event ended AFTER the InvalidateLayout startTime\n // 4. AND we have an initiator for the UpdateLayoutTree event\n // 5. Then we set the last invalidation event for this frame to be the UpdateLayoutTree's initiator.\n const lastUpdateLayoutTreeForFrame = lastUpdateLayoutTreeByFrame.get(event.args.data.frame);\n if (lastUpdateLayoutTreeForFrame) {\n const {endTime} = Helpers.Timing.eventTimingsMicroSeconds(lastUpdateLayoutTreeForFrame);\n const initiatorOfUpdateLayout = eventToInitiatorMap.get(lastUpdateLayoutTreeForFrame);\n\n if (initiatorOfUpdateLayout && endTime && endTime > event.ts) {\n invalidationInitiator = initiatorOfUpdateLayout;\n }\n }\n }\n lastInvalidationEventForFrame.set(event.args.data.frame, invalidationInitiator);\n } else if (Types.TraceEvents.isTraceEventLayout(event)) {\n // The initiator of a Layout event is the last Invalidation event.\n const lastInvalidation = lastInvalidationEventForFrame.get(event.args.beginData.frame);\n if (lastInvalidation) {\n storeInitiator({\n event,\n initiator: lastInvalidation,\n });\n }\n // Now clear the last invalidation for the frame: the last invalidation has been linked to a Layout event, so it cannot be the initiator for any future layouts.\n lastInvalidationEventForFrame.delete(event.args.beginData.frame);\n } else if (Types.TraceEvents.isTraceEventRequestAnimationFrame(event)) {\n requestAnimationFrameEventsById.set(event.args.data.id, event);\n } else if (Types.TraceEvents.isTraceEventFireAnimationFrame(event)) {\n // If we get a fire event, that means we should have had the\n // RequestAnimationFrame event by now. If so, we can set that as the\n // initiator for the fire event.\n const matchingRequestEvent = requestAnimationFrameEventsById.get(event.args.data.id);\n if (matchingRequestEvent) {\n storeInitiator({\n event,\n initiator: matchingRequestEvent,\n });\n }\n } else if (Types.TraceEvents.isTraceEventTimerInstall(event)) {\n timerInstallEventsById.set(event.args.data.timerId, event);\n } else if (Types.TraceEvents.isTraceEventTimerFire(event)) {\n const matchingInstall = timerInstallEventsById.get(event.args.data.timerId);\n if (matchingInstall) {\n storeInitiator({event, initiator: matchingInstall});\n }\n } else if (Types.TraceEvents.isTraceEventRequestIdleCallback(event)) {\n requestIdleCallbackEventsById.set(event.args.data.id, event);\n } else if (Types.TraceEvents.isTraceEventFireIdleCallback(event)) {\n const matchingRequestEvent = requestIdleCallbackEventsById.get(event.args.data.id);\n if (matchingRequestEvent) {\n storeInitiator({\n event,\n initiator: matchingRequestEvent,\n });\n }\n } else if (Types.TraceEvents.isTraceEventWebSocketCreate(event)) {\n webSocketCreateEventsById.set(event.args.data.identifier, event);\n } else if (Types.TraceEvents.isTraceEventWebSocketSendHandshakeRequest(event)) {\n const matchingCreateEvent = webSocketCreateEventsById.get(event.args.data.identifier);\n if (matchingCreateEvent) {\n storeInitiator({\n event,\n initiator: matchingCreateEvent,\n });\n }\n } else if (\n Types.TraceEvents.isTraceEventWebSocketSendHandshakeRequest(event) ||\n Types.TraceEvents.isTraceEventWebSocketReceiveHandshakeResponse(event) ||\n Types.TraceEvents.isTraceEventWebSocketDestroy(event)) {\n const matchingCreateEvent = webSocketCreateEventsById.get(event.args.data.identifier);\n if (matchingCreateEvent) {\n storeInitiator({\n event,\n initiator: matchingCreateEvent,\n });\n }\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('InitiatorsHandler is not initialized');\n }\n\n handlerState = HandlerState.FINALIZED;\n}\n\nexport interface InitiatorsData {\n eventToInitiator: Map<Types.TraceEvents.TraceEventData, Types.TraceEvents.TraceEventData>;\n initiatorToEvents: Map<Types.TraceEvents.TraceEventData, Types.TraceEvents.TraceEventData[]>;\n}\nexport function data(): InitiatorsData {\n return {\n eventToInitiator: new Map(eventToInitiatorMap),\n initiatorToEvents: new Map(initiatorToEventsMap),\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\nlet handlerState = HandlerState.UNINITIALIZED;\n\nconst invalidationsForEvent = new Map<Types.TraceEvents.TraceEventData, Types.TraceEvents.SyntheticInvalidation[]>();\n\nlet lastRecalcStyleEvent: Types.TraceEvents.TraceEventUpdateLayoutTree|null = null;\n\n// Used to track paints so we track invalidations correctly per paint.\nlet hasPainted = false;\n\nconst allInvalidationTrackingEvents:\n Array<Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking|\n Types.TraceEvents.TraceEventStyleRecalcInvalidationTracking|Types.TraceEvents\n .TraceEventStyleInvalidatorInvalidationTracking|Types.TraceEvents.TraceEventLayoutInvalidationTracking> =\n [];\n\nexport function reset(): void {\n handlerState = HandlerState.UNINITIALIZED;\n invalidationsForEvent.clear();\n lastRecalcStyleEvent = null;\n allInvalidationTrackingEvents.length = 0;\n hasPainted = false;\n}\n\nexport function initialize(): void {\n if (handlerState !== HandlerState.UNINITIALIZED) {\n throw new Error('InvalidationsHandler was not reset before being initialized');\n }\n\n handlerState = HandlerState.INITIALIZED;\n}\n\nfunction addInvalidationToEvent(\n event: Types.TraceEvents.TraceEventData,\n invalidation: Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking|\n Types.TraceEvents.TraceEventStyleRecalcInvalidationTracking|\n Types.TraceEvents.TraceEventStyleInvalidatorInvalidationTracking|\n Types.TraceEvents.TraceEventLayoutInvalidationTracking): void {\n const existingInvalidations = invalidationsForEvent.get(event) || [];\n\n const syntheticInvalidation: Types.TraceEvents.SyntheticInvalidation = {\n ...invalidation,\n name: 'SyntheticInvalidation',\n frame: invalidation.args.data.frame,\n nodeId: invalidation.args.data.nodeId,\n rawEvent: invalidation,\n };\n\n if (invalidation.args.data.nodeName) {\n syntheticInvalidation.nodeName = invalidation.args.data.nodeName;\n }\n if (invalidation.args.data.reason) {\n syntheticInvalidation.reason = invalidation.args.data.reason;\n }\n if (invalidation.args.data.stackTrace) {\n syntheticInvalidation.stackTrace = invalidation.args.data.stackTrace;\n }\n\n existingInvalidations.push(syntheticInvalidation);\n invalidationsForEvent.set(event, existingInvalidations);\n}\n\nexport function handleEvent(event: Types.TraceEvents.TraceEventData): void {\n if (Types.TraceEvents.isTraceEventUpdateLayoutTree(event)) {\n lastRecalcStyleEvent = event;\n\n // Associate any prior invalidations with this recalc event.\n for (const invalidation of allInvalidationTrackingEvents) {\n if (Types.TraceEvents.isTraceEventLayoutInvalidationTracking(invalidation)) {\n // LayoutInvalidation events cannot be associated with a LayoutTree\n // event.\n continue;\n }\n\n const recalcFrameId = lastRecalcStyleEvent.args.beginData?.frame;\n\n if (recalcFrameId && invalidation.args.data.frame === recalcFrameId) {\n addInvalidationToEvent(event, invalidation);\n }\n }\n return;\n }\n\n if (Types.TraceEvents.isTraceEventScheduleStyleInvalidationTracking(event) ||\n Types.TraceEvents.isTraceEventStyleRecalcInvalidationTracking(event) ||\n Types.TraceEvents.isTraceEventStyleInvalidatorInvalidationTracking(event) ||\n Types.TraceEvents.isTraceEventLayoutInvalidationTracking(event)) {\n if (hasPainted) {\n // If we have painted, then we can clear out the list of all existing\n // invalidations, as we cannot associate them across frames.\n allInvalidationTrackingEvents.length = 0;\n lastRecalcStyleEvent = null;\n hasPainted = false;\n }\n\n // Style invalidation events can occur before and during recalc styles. When we get a recalc style event (aka TraceEventUpdateLayoutTree), we check and associate any prior invalidations with it.\n // But any invalidations that occur during a TraceEventUpdateLayoutTree\n // event would be reported in trace events after. So each time we get an\n // invalidation that might be due to a style recalc, we check if the\n // timings overlap and if so associate them.\n if (lastRecalcStyleEvent &&\n (Types.TraceEvents.isTraceEventScheduleStyleInvalidationTracking(event) ||\n Types.TraceEvents.isTraceEventStyleRecalcInvalidationTracking(event) ||\n Types.TraceEvents.isTraceEventStyleInvalidatorInvalidationTracking(event))) {\n const recalcEndTime = lastRecalcStyleEvent.ts + (lastRecalcStyleEvent.dur || 0);\n if (event.ts >= lastRecalcStyleEvent.ts && event.ts <= recalcEndTime &&\n lastRecalcStyleEvent.args.beginData?.frame === event.args.data.frame) {\n addInvalidationToEvent(lastRecalcStyleEvent, event);\n }\n }\n\n allInvalidationTrackingEvents.push(event);\n return;\n }\n\n if (Types.TraceEvents.isTraceEventPaint(event)) {\n // Used to ensure that we do not create relationships across frames.\n hasPainted = true;\n return;\n }\n\n if (Types.TraceEvents.isTraceEventLayout(event)) {\n const layoutFrame = event.args.beginData.frame;\n for (const invalidation of allInvalidationTrackingEvents) {\n // The only invalidations that cause a Layout are LayoutInvalidations :)\n if (!Types.TraceEvents.isTraceEventLayoutInvalidationTracking(invalidation)) {\n continue;\n }\n\n if (invalidation.args.data.frame === layoutFrame) {\n addInvalidationToEvent(event, invalidation);\n }\n }\n }\n}\n\nexport async function finalize(): Promise<void> {\n if (handlerState !== HandlerState.INITIALIZED) {\n throw new Error('InvalidationsHandler is not initialized');\n }\n\n handlerState = HandlerState.FINALIZED;\n}\n\ninterface InvalidationsData {\n invalidationsForEvent: Map<Types.TraceEvents.TraceEventData, Types.TraceEvents.SyntheticInvalidation[]>;\n}\n\nexport function data(): InvalidationsData {\n return {\n invalidationsForEvent: new Map(invalidationsForEvent),\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 type * as Protocol from '../../../generated/protocol.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport {ScoreClassification} from './PageLoadMetricsHandler.js';\nimport {data as screenshotsHandlerData} from './ScreenshotsHandler.js';\nimport {HandlerState, type TraceEventHandlerName} from './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.TraceEventLayoutInvalidationTracking[];\n scheduleStyleInvalidationEvents: Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking[];\n styleRecalcInvalidationEvents: Types.TraceEvents.TraceEventStyleRecalcInvalidationTracking[];\n scoreRecords: ScoreRecord[];\n backendNodeIds: Protocol.DOM.BackendNodeId[];\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.TraceEventLayoutInvalidationTracking[] = [];\nconst scheduleStyleInvalidationEvents: Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking[] = [];\nconst styleRecalcInvalidationEvents: Types.TraceEvents.TraceEventStyleRecalcInvalidationTracking[] = [];\n\nconst backendNodeIds = new Set<Protocol.DOM.BackendNodeId>();\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 scheduleStyleInvalidationEvents.length = 0;\n styleRecalcInvalidationEvents.length = 0;\n prePaintEvents.length = 0;\n backendNodeIds.clear();\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.isTraceEventLayoutInvalidationTracking(event)) {\n layoutInvalidationEvents.push(event);\n return;\n }\n if (Types.TraceEvents.isTraceEventScheduleStyleInvalidationTracking(event)) {\n scheduleStyleInvalidationEvents.push(event);\n }\n if (Types.TraceEvents.isTraceEventStyleRecalcInvalidationTracking(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.TraceWindowMicroSeconds {\n return {\n min: time,\n max: time,\n range: Types.Timing.MicroSeconds(0),\n };\n}\n\nfunction updateTraceWindowMax(\n traceWindow: Types.Timing.TraceWindowMicroSeconds, 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\n/**\n * Collects backend node ids coming from LayoutShift and LayoutInvalidation\n * events.\n */\nfunction collectNodes(): void {\n backendNodeIds.clear();\n\n // Collect the node ids present in the shifts.\n for (const layoutShift of layoutShiftEvents) {\n if (!layoutShift.args.data?.impacted_nodes) {\n continue;\n }\n for (const node of layoutShift.args.data.impacted_nodes) {\n backendNodeIds.add(node.node_id);\n }\n }\n\n // Collect the node ids present in LayoutInvalidation & scheduleStyleInvalidation events.\n for (const layoutInvalidation of layoutInvalidationEvents) {\n if (!layoutInvalidation.args.data?.nodeId) {\n continue;\n }\n backendNodeIds.add(layoutInvalidation.args.data.nodeId);\n }\n for (const scheduleStyleInvalidation of scheduleStyleInvalidationEvents) {\n if (!scheduleStyleInvalidation.args.data?.nodeId) {\n continue;\n }\n backendNodeIds.add(scheduleStyleInvalidation.args.data.nodeId);\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 collectNodes();\n handlerState = HandlerState.FINALIZED;\n}\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 scheduleStyleInvalidationEvents: [...scheduleStyleInvalidationEvents],\n styleRecalcInvalidationEvents: [],\n scoreRecords: [...scoreRecords],\n backendNodeIds: [...backendNodeIds],\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.TraceWindowMicroSeconds;\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.TraceWindowMicroSeconds,\n needsImprovement: Types.Timing.TraceWindowMicroSeconds|null,\n bad: Types.Timing.TraceWindowMicroSeconds|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 earliestEventForEndTime = earliestEventForEndTimePerCategory[category];\n const endTime = Types.Timing.MicroSeconds(interaction.ts + interaction.dur);\n\n const earliestCurrentEvent = earliestEventForEndTime.get(endTime);\n if (!earliestCurrentEvent) {\n earliestEventForEndTime.set(endTime, interaction);\n return;\n }\n if (interaction.ts < earliestCurrentEvent.ts) {\n earliestEventForEndTime.set(endTime, interaction);\n } else if (\n interaction.ts === earliestCurrentEvent.ts &&\n interaction.interactionId === earliestCurrentEvent.interactionId) {\n // We have seen in traces that the same interaction can have multiple\n // events (e.g. a 'click' and a 'pointerdown'). Often only one of these\n // events will have an event handler bound to it which caused delay on\n // the main thread, and the others will not. This leads to a situation\n // where if we pick one of the events that had no event handler, its\n // processing time (processingEnd - processingStart) will be 0, but if we\n // had picked the event that had the slow event handler, we would show\n // correctly the main thread delay due to the event handler.\n // So, if we find events with the same interactionId and the same\n // begin/end times, we pick the one with the largest (processingEnd -\n // processingStart) time in order to make sure we find the event with the\n // worst main thread delay, as that is the one the user should care\n // about.\n const currentEventProcessingTime = earliestCurrentEvent.processingEnd - earliestCurrentEvent.processingStart;\n const newEventProcessingTime = interaction.processingEnd - interaction.processingStart;\n\n // Use the new interaction if it has a longer processing time than the existing one.\n if (newEventProcessingTime > currentEventProcessingTime) {\n earliestEventForEndTime.set(endTime, interaction);\n }\n }\n\n // Maximize the processing time based on the \"children\" interactions.\n // We pick the earliest start processing time, and the latest end\n // processing time to avoid under-reporting.\n if (interaction.processingStart < earliestCurrentEvent.processingStart) {\n earliestCurrentEvent.processingStart = interaction.processingStart;\n writeSyntheticTimespans(earliestCurrentEvent);\n }\n if (interaction.processingEnd > earliestCurrentEvent.processingEnd) {\n earliestCurrentEvent.processingEnd = interaction.processingEnd;\n writeSyntheticTimespans(earliestCurrentEvent);\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\nfunction writeSyntheticTimespans(event: Types.TraceEvents.SyntheticInteractionEvent): void {\n const startEvent = event.args.data.beginEvent;\n const endEvent = event.args.data.endEvent;\n\n event.inputDelay = Types.Timing.MicroSeconds(event.processingStart - startEvent.ts);\n event.mainThreadHandling = Types.Timing.MicroSeconds(event.processingEnd - event.processingStart);\n event.presentationDelay = Types.Timing.MicroSeconds(endEvent.ts - event.processingEnd);\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 // In the future we will add microsecond timestamps to the trace events,\n // but until then we can use the millisecond precision values that are in\n // the trace event. To adjust them to be relative to the event.ts and the\n // trace timestamps, for both processingStart and processingEnd we subtract\n // the event timestamp (NOT event.ts, but the timeStamp millisecond value\n // emitted in args.data), and then add that value to the event.ts. This\n // will give us a processingStart and processingEnd time in microseconds\n // that is relative to event.ts, and can be used when drawing boxes.\n // There is some inaccuracy here as we are converting milliseconds to microseconds, but it is good enough until the backend emits more accurate numbers.\n const processingStartRelativeToTraceTime = Types.Timing.MicroSeconds(\n Helpers.Timing.millisecondsToMicroseconds(interactionStartEvent.args.data.processingStart) -\n Helpers.Timing.millisecondsToMicroseconds(interactionStartEvent.args.data.timeStamp) +\n interactionStartEvent.ts,\n );\n\n const processingEndRelativeToTraceTime = Types.Timing.MicroSeconds(\n (Helpers.Timing.millisecondsToMicroseconds(interactionStartEvent.args.data.processingEnd) -\n Helpers.Timing.millisecondsToMicroseconds(interactionStartEvent.args.data.timeStamp)) +\n interactionStartEvent.ts);\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 processingStart: processingStartRelativeToTraceTime,\n processingEnd: processingEndRelativeToTraceTime,\n // These will be set in writeSyntheticTimespans()\n inputDelay: Types.Timing.MicroSeconds(-1),\n mainThreadHandling: Types.Timing.MicroSeconds(-1),\n presentationDelay: Types.Timing.MicroSeconds(-1),\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 writeSyntheticTimespans(interactionEvent);\n\n interactionEvents.push(interactionEvent);\n }\n\n handlerState = HandlerState.FINALIZED;\n interactionEventsWithNoNesting.push(...removeNestedInteractions(interactionEvents));\n\n // Pick the longest interactions from the set that were not nested, as we\n // know those are the set of the largest interactions.\n for (const interactionEvent of interactionEventsWithNoNesting) {\n if (!longestInteractionEvent || longestInteractionEvent.dur < interactionEvent.dur) {\n longestInteractionEvent = interactionEvent;\n }\n }\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 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 asyncEvents = [...performanceMeasureEvents, ...consoleTimings];\n syntheticEvents.push(...Helpers.Trace.createMatchedSortedSyntheticEvents(asyncEvents));\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\nimport {type TraceEventHandlerName} from './types.js';\nimport {data as userInteractionsHandlerData} from './UserInteractionsHandler.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 events 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'|'LONG_INTERACTION';\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 deps(): TraceEventHandlerName[] {\n return ['UserInteractions'];\n}\n\nexport async function finalize(): Promise<void> {\n // These events do exist on the UserInteractionsHandler, but we also put\n // them into the WarningsHandler so that the warnings handler can be the\n // source of truth and the way to look up all warnings for a given event.\n // Otherwise, we would have to look up warnings across multiple handlers for\n // a given event, which will start to get messy very quickly.\n const longInteractions = userInteractionsHandlerData().interactionsOverThreshold;\n for (const interaction of longInteractions) {\n storeWarning(interaction, 'LONG_INTERACTION');\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 workerURLById.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 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\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 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.\n\nexport * as RootCauses from './RootCauses.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';\n\nimport {LayoutShiftRootCauses} from './LayoutShift.js';\n\nexport type RootCauseProtocolInterface = {\n getInitiatorForRequest(url: string): Protocol.Network.Initiator|null,\n pushNodesByBackendIdsToFrontend(backendNodeIds: Protocol.DOM.BackendNodeId[]): Promise<Protocol.DOM.NodeId[]>,\n getNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.DOM.Node>,\n getComputedStyleForNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.CSSComputedStyleProperty[]>,\n getMatchedStylesForNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.GetMatchedStylesForNodeResponse>,\n fontFaceForSource(url: string): Protocol.CSS.FontFace|undefined,\n};\n\nexport class RootCauses {\n readonly layoutShifts: LayoutShiftRootCauses;\n\n constructor(protocolInterface: RootCauseProtocolInterface) {\n this.layoutShifts = new LayoutShiftRootCauses(protocolInterface);\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 type * as Protocol from '../../../generated/protocol.js';\nimport {type TraceParseData} from '../handlers/types.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {type RootCauseProtocolInterface} from './RootCauses.js';\n\nexport type CSSDimensions = {\n width?: string,\n height?: string,\n aspectRatio?: string,\n};\n\nexport interface UnsizedMedia {\n node: Protocol.DOM.Node;\n authoredDimensions?: CSSDimensions;\n computedDimensions: CSSDimensions;\n}\n\nexport interface InjectedIframe {\n iframe: Protocol.DOM.Node;\n}\n\nexport interface RootCauseRequest {\n request: Types.TraceEvents.TraceEventSyntheticNetworkRequest;\n initiator?: Protocol.Network.Initiator;\n}\n\nexport interface FontChange extends RootCauseRequest {\n fontFace: Protocol.CSS.FontFace;\n}\n\nexport interface RenderBlockingRequest extends RootCauseRequest {}\n\nexport interface LayoutShiftRootCausesData {\n unsizedMedia: UnsizedMedia[];\n iframes: InjectedIframe[];\n fontChanges: FontChange[];\n renderBlockingRequests: RenderBlockingRequest[];\n scriptStackTrace: Types.TraceEvents.TraceEventCallFrame[];\n}\n\nconst fontRequestsByPrePaint = new Map<Types.TraceEvents.TraceEventPrePaint, FontChange[]|null>();\nconst renderBlocksByPrePaint = new Map<Types.TraceEvents.TraceEventPrePaint, RenderBlockingRequest[]|null>();\n\nfunction setDefaultValue(\n map: Map<Types.TraceEvents.TraceEventLayoutShift, LayoutShiftRootCausesData>,\n shift: Types.TraceEvents.TraceEventLayoutShift): void {\n Platform.MapUtilities.getWithDefault(map, shift, () => {\n return {\n unsizedMedia: [],\n iframes: [],\n fontChanges: [],\n renderBlockingRequests: [],\n scriptStackTrace: [],\n };\n });\n}\n\n// Important: we purposefully treat `potentially_blocking` as\n// non-render-blocking here because:\n// 1. An async script can run on the main thread at any point, including before\n// the page is loaded\n// 2. An async script will never block the parsing and rendering process of the\n// browser.\n// 3. Therefore, from a developer's point of view, there is nothing more they\n// can do if they've put `async` on, and within the context of Insights, we\n// shouldn't report an async script as render blocking.\n// In the future we may want to consider suggesting the use of `defer` over\n// `async`, as it doesn't have this concern, but for now we'll allow `async`\n// and not report it as an issue.\nconst NON_RENDER_BLOCKING_VALUES = new Set<Types.TraceEvents.RenderBlocking>([\n 'non_blocking',\n 'potentially_blocking',\n]);\nfunction networkRequestIsRenderBlockingInFrame(\n event: Types.TraceEvents.TraceEventSyntheticNetworkRequest, frameId: string): boolean {\n const isRenderBlocking = !NON_RENDER_BLOCKING_VALUES.has(event.args.data.renderBlocking);\n return isRenderBlocking && event.args.data.frame === frameId;\n}\n\nexport class LayoutShiftRootCauses {\n #protocolInterface: RootCauseProtocolInterface;\n #rootCauseCacheMap = new Map<Types.TraceEvents.TraceEventLayoutShift, LayoutShiftRootCausesData>();\n\n constructor(protocolInterface: RootCauseProtocolInterface) {\n this.#protocolInterface = protocolInterface;\n }\n\n /**\n * Calculates the potential root causes for a given layout shift event. Once\n * calculated, this data is cached.\n * Note: because you need all layout shift data at once to calculate these\n * correctly, this function will parse the root causes for _all_ layout shift\n * events the first time that it's called. That then populates the cache for\n * each shift, so any subsequent calls are just a constant lookup.\n */\n async rootCausesForEvent(modelData: TraceParseData, event: Types.TraceEvents.TraceEventLayoutShift):\n Promise<Readonly<LayoutShiftRootCausesData>|null> {\n const cachedResult = this.#rootCauseCacheMap.get(event);\n if (cachedResult) {\n return cachedResult;\n }\n\n const allLayoutShifts = modelData.LayoutShifts.clusters.flatMap(cluster => cluster.events);\n // Make sure a value in the cache is set even for shifts that don't have a root cause,\n // so that we don't have to recompute when no root causes are found. In case a cause\n // for a shift is found, the default value is replaced.\n allLayoutShifts.forEach(shift => setDefaultValue(this.#rootCauseCacheMap, shift));\n\n // Populate the cache\n await this.blameShifts(\n allLayoutShifts,\n modelData,\n );\n\n const resultForEvent = this.#rootCauseCacheMap.get(event);\n if (!resultForEvent) {\n // No root causes available for this layout shift.\n return null;\n }\n return resultForEvent;\n }\n\n /**\n * Determines potential root causes for shifts\n */\n async blameShifts(\n layoutShifts: Types.TraceEvents.TraceEventLayoutShift[],\n modelData: TraceParseData,\n ): Promise<void> {\n await this.linkShiftsToLayoutInvalidations(layoutShifts, modelData);\n this.linkShiftsToLayoutEvents(layoutShifts, modelData);\n }\n\n /**\n * \"LayoutInvalidations\" are a set of trace events dispatched in Blink under the name\n * \"layoutInvalidationTracking\", which track invalidations on the \"Layout\"stage of the\n * rendering pipeline. This function utilizes this event to flag potential root causes\n * to layout shifts.\n */\n async linkShiftsToLayoutInvalidations(\n layoutShifts: Types.TraceEvents.TraceEventLayoutShift[], modelData: TraceParseData): Promise<void> {\n const {prePaintEvents, layoutInvalidationEvents, scheduleStyleInvalidationEvents, backendNodeIds} =\n modelData.LayoutShifts;\n\n // For the purposes of determining root causes of layout shifts, we\n // consider scheduleStyleInvalidationTracking and\n // LayoutInvalidationTracking events as events that could have been the\n // cause of the layout shift.\n const eventsForLayoutInvalidation: Array<Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking> =\n [...layoutInvalidationEvents, ...scheduleStyleInvalidationEvents];\n\n const nodes = await this.#protocolInterface.pushNodesByBackendIdsToFrontend(backendNodeIds);\n const nodeIdsByBackendIdMap = new Map<Protocol.DOM.BackendNodeId, Protocol.DOM.NodeId>();\n for (let i = 0; i < backendNodeIds.length; i++) {\n nodeIdsByBackendIdMap.set(backendNodeIds[i], nodes[i]);\n }\n\n // Maps from PrePaint events to LayoutShifts that occured in each one.\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n for (const layoutInvalidation of eventsForLayoutInvalidation) {\n // Get the first PrePaint event that happened after the current LayoutInvalidation event.\n const nextPrePaintIndex = Platform.ArrayUtilities.nearestIndexFromBeginning(\n prePaintEvents, prePaint => prePaint.ts > layoutInvalidation.ts);\n if (nextPrePaintIndex === null) {\n // No PrePaint event registered after this LayoutInvalidation. Continue.\n continue;\n }\n const nextPrePaint = prePaintEvents[nextPrePaintIndex];\n const subsequentShifts = shiftsByPrePaint.get(nextPrePaint);\n if (!subsequentShifts) {\n // The PrePaint after the current LayoutInvalidation doesn't contain shifts.\n continue;\n }\n const fontChangeRootCause = this.getFontChangeRootCause(layoutInvalidation, nextPrePaint, modelData);\n const renderBlockRootCause = this.getRenderBlockRootCause(layoutInvalidation, nextPrePaint, modelData);\n const layoutInvalidationNodeId = nodeIdsByBackendIdMap.get(layoutInvalidation.args.data.nodeId);\n const layoutInvalidationNode = layoutInvalidationNodeId !== undefined ?\n await this.#protocolInterface.getNode(layoutInvalidationNodeId) :\n null;\n let unsizedMediaRootCause: UnsizedMedia|null = null;\n let iframeRootCause: InjectedIframe|null = null;\n if (layoutInvalidationNode && layoutInvalidation.args.data.reason) {\n unsizedMediaRootCause =\n await this.getUnsizedMediaRootCause(layoutInvalidation.args.data.reason, layoutInvalidationNode);\n iframeRootCause = this.getIframeRootCause(layoutInvalidation.args.data.reason, layoutInvalidationNode);\n }\n\n if (!unsizedMediaRootCause && !iframeRootCause && !fontChangeRootCause && !renderBlockRootCause) {\n continue;\n }\n\n // Add found potential root causes to all the shifts in this PrePaint and populate the cache.\n for (const shift of subsequentShifts) {\n const rootCausesForShift = Platform.MapUtilities.getWithDefault(this.#rootCauseCacheMap, shift, () => {\n return {\n unsizedMedia: [],\n iframes: [],\n fontChanges: [],\n renderBlockingRequests: [],\n scriptStackTrace: [],\n };\n });\n if (unsizedMediaRootCause &&\n !rootCausesForShift.unsizedMedia.some(media => media.node.nodeId === unsizedMediaRootCause?.node.nodeId) &&\n shift.args.frame === layoutInvalidation.args.data.frame) {\n rootCausesForShift.unsizedMedia.push(unsizedMediaRootCause);\n }\n if (iframeRootCause &&\n !rootCausesForShift.iframes.some(\n injectedIframe => injectedIframe.iframe.nodeId === iframeRootCause?.iframe.nodeId)) {\n rootCausesForShift.iframes.push(iframeRootCause);\n }\n if (fontChangeRootCause) {\n // Unlike other root causes, we calculate fonts causing a shift only once,\n // which means we assign the built array instead of appending new objects\n // to it.\n rootCausesForShift.fontChanges = fontChangeRootCause;\n }\n if (renderBlockRootCause) {\n rootCausesForShift.renderBlockingRequests = renderBlockRootCause;\n }\n }\n }\n }\n\n /**\n * For every shift looks up the initiator of its corresponding Layout event. This initiator\n * is assigned by the RendererHandler and contains the stack trace of the point in a script\n * that caused a style recalculation or a relayout. This stack trace is added to the shift's\n * potential root causes.\n * Note that a Layout cannot always be linked to a script, in that case, we cannot add a\n * \"script causing reflow\" as a potential root cause to the corresponding shift.\n */\n linkShiftsToLayoutEvents(layoutShifts: Types.TraceEvents.TraceEventLayoutShift[], modelData: TraceParseData): void {\n const {prePaintEvents} = modelData.LayoutShifts;\n // Maps from PrePaint events to LayoutShifts that occured in each one.\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n\n const eventTriggersLayout = ({name}: {name: string}): boolean => {\n const knownName = name as Types.TraceEvents.KnownEventName;\n return knownName === Types.TraceEvents.KnownEventName.Layout;\n };\n const layoutEvents = modelData.Renderer.allTraceEntries.filter(eventTriggersLayout);\n for (const layout of layoutEvents) {\n // Get the first PrePaint event that happened after the current layout event.\n const nextPrePaintIndex = Platform.ArrayUtilities.nearestIndexFromBeginning(\n prePaintEvents, prePaint => prePaint.ts > layout.ts + (layout.dur || 0));\n if (nextPrePaintIndex === null) {\n // No PrePaint event registered after this LayoutInvalidation. Continue.\n continue;\n }\n const nextPrePaint = prePaintEvents[nextPrePaintIndex];\n const subsequentShifts = shiftsByPrePaint.get(nextPrePaint);\n if (!subsequentShifts) {\n // The PrePaint after the current LayoutInvalidation doesn't contain shifts.\n continue;\n }\n const layoutNode = modelData.Renderer.entryToNode.get(layout);\n const initiator = layoutNode ? modelData.Initiators.eventToInitiator.get(layoutNode.entry) : null;\n const stackTrace = initiator?.args?.data?.stackTrace;\n if (!stackTrace) {\n continue;\n }\n // Add found potential root causes to all the shifts in this PrePaint and populate the cache.\n for (const shift of subsequentShifts) {\n const rootCausesForShift = Platform.MapUtilities.getWithDefault(this.#rootCauseCacheMap, shift, () => {\n return {\n unsizedMedia: [],\n iframes: [],\n fontChanges: [],\n renderBlockingRequests: [],\n scriptStackTrace: [],\n };\n });\n if (rootCausesForShift.scriptStackTrace.length === 0) {\n rootCausesForShift.scriptStackTrace = stackTrace;\n }\n }\n }\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it was dispatched\n * because a media element without dimensions was resized.\n */\n async getUnsizedMediaRootCause(\n reason: Types.TraceEvents.LayoutInvalidationReason,\n layoutInvalidationNode: Protocol.DOM.Node): Promise<UnsizedMedia|null> {\n // Filter events to resizes only.\n if (reason !== Types.TraceEvents.LayoutInvalidationReason.SIZE_CHANGED) {\n return null;\n }\n const computedStylesList = await this.#protocolInterface.getComputedStyleForNode(layoutInvalidationNode.nodeId);\n const computedStyles = new Map(computedStylesList.map(item => [item.name, item.value]));\n if (computedStyles && !(await nodeIsUnfixedMedia(layoutInvalidationNode, computedStyles))) {\n return null;\n }\n const authoredDimensions = await this.getNodeAuthoredDimensions(layoutInvalidationNode);\n if (dimensionsAreExplicit(authoredDimensions)) {\n return null;\n }\n const computedDimensions = computedStyles ? getNodeComputedDimensions(computedStyles) : {};\n\n return {node: layoutInvalidationNode, authoredDimensions, computedDimensions};\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it was dispatched\n * because a node, which is an ancestor to an iframe, was injected.\n */\n getIframeRootCause(reason: Types.TraceEvents.LayoutInvalidationReason, layoutInvalidationDOMNode: Protocol.DOM.Node):\n InjectedIframe|null {\n if (layoutInvalidationDOMNode.nodeName !== 'IFRAME' &&\n reason !== Types.TraceEvents.LayoutInvalidationReason.STYLE_CHANGED &&\n reason !== Types.TraceEvents.LayoutInvalidationReason.ADDED_TO_LAYOUT) {\n return null;\n }\n const iframe = firstIframeInDOMTree(layoutInvalidationDOMNode);\n if (!iframe) {\n return null;\n }\n return {iframe};\n }\n\n /**\n * Given a layout invalidation event and a sorted array, returns the subset of requests that arrived within a\n * 500ms window before the layout invalidation.\n */\n requestsInInvalidationWindow(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking,\n modelData: TraceParseData): RootCauseRequest[] {\n const requestsSortedByEndTime = modelData.NetworkRequests.byTime.sort((req1, req2) => {\n const req1EndTime = req1.ts + req1.dur;\n const req2EndTime = req2.ts + req2.dur;\n return req1EndTime - req2EndTime;\n });\n\n const lastRequestIndex = Platform.ArrayUtilities.nearestIndexFromEnd(\n requestsSortedByEndTime, request => request.ts + request.dur < layoutInvalidation.ts);\n if (lastRequestIndex === null) {\n return [];\n }\n\n const MAX_DELTA_FOR_FONT_REQUEST = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(0.5));\n\n const requestsInInvalidationWindow: RootCauseRequest[] = [];\n\n // Get all requests finished within the valid window.\n for (let i = lastRequestIndex; i > -1; i--) {\n const previousRequest = requestsSortedByEndTime[i];\n const previousRequestEndTime = previousRequest.ts + previousRequest.dur;\n if (layoutInvalidation.ts - previousRequestEndTime < MAX_DELTA_FOR_FONT_REQUEST) {\n const requestInInvalidationWindow: RootCauseRequest = {request: previousRequest};\n\n const initiator = this.#protocolInterface.getInitiatorForRequest(\n previousRequest.args.data.url as Platform.DevToolsPath.UrlString);\n requestInInvalidationWindow.initiator = initiator || undefined;\n requestsInInvalidationWindow.push(requestInInvalidationWindow);\n } else {\n // No more requests fit in the time window.\n break;\n }\n }\n return requestsInInvalidationWindow;\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it was dispatched\n * because fonts were changed and if so returns the information of all network\n * request with which the fonts were possibly fetched, if any. The computed\n * network requests are cached for the corresponding prepaint event, meaning\n * that other LayoutInvalidation events that correspond to the same prepaint\n * are not processed and the cached network requests for the prepaint is\n * returned instead.\n */\n getFontChangeRootCause(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking,\n nextPrePaint: Types.TraceEvents.TraceEventPrePaint, modelData: TraceParseData): FontChange[]|null {\n if (layoutInvalidation.args.data.reason !== Types.TraceEvents.LayoutInvalidationReason.FONTS_CHANGED) {\n return null;\n }\n // Prevent computing the result of this function multiple times per PrePaint event.\n const fontRequestsForPrepaint = fontRequestsByPrePaint.get(nextPrePaint);\n if (fontRequestsForPrepaint !== undefined) {\n return fontRequestsForPrepaint;\n }\n\n const fontRequestsInThisPrepaint =\n this.getFontRequestsInInvalidationWindow(this.requestsInInvalidationWindow(layoutInvalidation, modelData));\n fontRequestsByPrePaint.set(nextPrePaint, fontRequestsInThisPrepaint);\n return fontRequestsInThisPrepaint;\n }\n\n /**\n * Given the requests that arrived within a 500ms window before the layout invalidation, returns the font\n * requests of them.\n */\n getFontRequestsInInvalidationWindow(requestsInInvalidationWindow: RootCauseRequest[]): FontChange[] {\n const fontRequests: FontChange[] = [];\n\n // Get all requests finished within the valid window.\n for (let i = 0; i < requestsInInvalidationWindow.length; i++) {\n const fontRequest = requestsInInvalidationWindow[i] as FontChange;\n if (!fontRequest.request.args.data.mimeType.startsWith('font')) {\n continue;\n }\n\n const fontFace = this.#protocolInterface.fontFaceForSource(fontRequest.request.args.data.url);\n if (!fontFace || fontFace.fontDisplay === 'optional') {\n // Setting font-display to optional is part of what the developer\n // can do to avoid layout shifts due to FOIT/FOUT, as such we cannot\n // suggest any actionable insight here.\n continue;\n }\n fontRequest.fontFace = fontFace;\n fontRequests.push(fontRequest);\n }\n return fontRequests;\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it arrived within a 500ms window before the layout\n * invalidation and if so returns the information of all network request, if any. The computed network\n * requests are cached for the corresponding prepaint event, meaning that other LayoutInvalidation events\n * that correspond to the same prepaint are not processed and the cached network requests for the prepaint is\n * returned instead.\n */\n getRenderBlockRootCause(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking,\n nextPrePaint: Types.TraceEvents.TraceEventPrePaint, modelData: TraceParseData): RenderBlockingRequest[]|null {\n // Prevent computing the result of this function multiple times per PrePaint event.\n const renderBlocksInPrepaint = renderBlocksByPrePaint.get(nextPrePaint);\n if (renderBlocksInPrepaint !== undefined) {\n return renderBlocksInPrepaint;\n }\n\n const renderBlocksInThisPrepaint =\n getRenderBlockRequestsInInvalidationWindow(this.requestsInInvalidationWindow(layoutInvalidation, modelData));\n renderBlocksByPrePaint.set(nextPrePaint, renderBlocksInThisPrepaint);\n return renderBlocksInThisPrepaint;\n }\n\n /**\n * Returns a function that retrieves the active value of a given\n * CSS property within the matched styles of the param node.\n * The first occurence within the matched styles is returned and the\n * value is looked up in the following order, which follows CSS\n * specificity:\n * 1. Inline styles.\n * 2. CSS rules matching this node, from all applicable stylesheets.\n * 3. Attribute defined styles.\n */\n async nodeMatchedStylesPropertyGetter(node: Protocol.DOM.Node): Promise<((property: string) => string | null)> {\n const response = await this.#protocolInterface.getMatchedStylesForNode(node.nodeId);\n\n function cssPropertyValueGetter(cssProperty: string): string|null {\n let prop = response.inlineStyle?.cssProperties.find(prop => prop.name === cssProperty);\n if (prop) {\n return prop.value;\n }\n\n for (const {rule} of response.matchedCSSRules || []) {\n const prop = rule.style.cssProperties.find(prop => prop.name === cssProperty);\n if (prop) {\n return prop.value;\n }\n }\n\n prop = response.attributesStyle?.cssProperties.find(prop => prop.name === cssProperty);\n if (prop) {\n return prop.value;\n }\n\n return null;\n }\n return cssPropertyValueGetter;\n }\n\n /**\n * Returns the CSS dimensions set to the node from its matched styles.\n */\n async getNodeAuthoredDimensions(node: Protocol.DOM.Node): Promise<CSSDimensions> {\n const authoredDimensions: CSSDimensions = {};\n\n const cssMatchedRulesGetter = await this.nodeMatchedStylesPropertyGetter(node);\n if (!cssMatchedRulesGetter) {\n return authoredDimensions;\n }\n\n const attributesFlat = node.attributes || [];\n const attributes = [];\n for (let i = 0; i < attributesFlat.length; i += 2) {\n attributes.push({name: attributesFlat[i], value: attributesFlat[i + 1]});\n }\n\n const htmlHeight = attributes.find(attr => attr.name === 'height' && htmlAttributeIsExplicit(attr));\n const htmlWidth = attributes.find(attr => attr.name === 'width' && htmlAttributeIsExplicit(attr));\n\n const cssExplicitAspectRatio = cssMatchedRulesGetter('aspect-ratio') || undefined;\n\n if (htmlHeight && htmlWidth && cssExplicitAspectRatio) {\n return {height: htmlHeight.value, width: htmlWidth.value, aspectRatio: cssExplicitAspectRatio};\n }\n\n const cssHeight = cssMatchedRulesGetter('height') || undefined;\n const cssWidth = cssMatchedRulesGetter('width') || undefined;\n return {height: cssHeight, width: cssWidth, aspectRatio: cssExplicitAspectRatio};\n }\n}\n\n/**\n * Given the requests that arrived within a 500ms window before the layout invalidation, returns the render\n * block requests of them.\n */\nfunction getRenderBlockRequestsInInvalidationWindow(requestsInInvalidationWindow: RootCauseRequest[]):\n RenderBlockingRequest[] {\n const renderBlockingRequests: RenderBlockingRequest[] = [];\n\n // Get all requests finished within the valid window.\n for (let i = 0; i < requestsInInvalidationWindow.length; i++) {\n const mainFrameId = requestsInInvalidationWindow[i].request.args.data.frame;\n if (!networkRequestIsRenderBlockingInFrame(requestsInInvalidationWindow[i].request, mainFrameId)) {\n continue;\n }\n renderBlockingRequests.push(requestsInInvalidationWindow[i] as RenderBlockingRequest);\n }\n return renderBlockingRequests;\n}\n\nfunction firstIframeInDOMTree(root: Protocol.DOM.Node): Protocol.DOM.Node|null {\n if (root.nodeName === 'IFRAME') {\n return root;\n }\n const children = root.children;\n if (!children) {\n return null;\n }\n for (const child of children) {\n const iFrameInChild = firstIframeInDOMTree(child);\n if (iFrameInChild) {\n return iFrameInChild;\n }\n }\n return null;\n}\n\nfunction cssPropertyIsExplicitlySet(propertyValue: string): boolean {\n return !['auto', 'initial', 'unset', 'inherit'].includes(propertyValue);\n}\n\nfunction htmlAttributeIsExplicit(attr: {value: string}): boolean {\n return parseInt(attr.value, 10) >= 0;\n}\n\nfunction computedStyleHasBackroundImage(computedStyle: Map<string, string>): boolean {\n const CSS_URL_REGEX = /^url\\(\"([^\"]+)\"\\)$/;\n const backgroundImage = computedStyle.get('background-image');\n if (!backgroundImage) {\n return false;\n }\n return CSS_URL_REGEX.test(backgroundImage);\n}\n\nfunction computedStyleHasFixedPosition(computedStyle: Map<string, string>): boolean {\n const position = computedStyle.get('position');\n if (!position) {\n return false;\n }\n return position === 'fixed' || position === 'absolute';\n}\n\nfunction getNodeComputedDimensions(computedStyle: Map<string, string>): CSSDimensions {\n const computedDimensions: CSSDimensions = {};\n computedDimensions.height = computedStyle.get('height');\n computedDimensions.width = computedStyle.get('width');\n computedDimensions.aspectRatio = computedStyle.get('aspect-ratio');\n return computedDimensions;\n}\n\n/**\n * Determines if a node is a media element and is not fixed positioned\n * (i.e. \"position: fixed;\" or \"position: absolute;\")\n */\nasync function nodeIsUnfixedMedia(node: Protocol.DOM.Node, computedStyle: Map<string, string>): Promise<boolean> {\n const localName = node.localName;\n const isBackgroundImage = computedStyleHasBackroundImage(computedStyle);\n if (localName !== 'img' && localName !== 'video' && !isBackgroundImage) {\n // Not a media element.\n return false;\n }\n const isFixed = computedStyleHasFixedPosition(computedStyle);\n return !isFixed;\n}\n\n/**\n * Determines if a CSS dimensions object explicitly defines both width and height\n * (i.e. not set to auto, inherit, etc.)\n */\nfunction dimensionsAreExplicit(dimensions: CSSDimensions): boolean {\n const {height, width, aspectRatio} = dimensions;\n\n const explicitHeight = Boolean(height && cssPropertyIsExplicitlySet(height));\n const explicitWidth = Boolean(width && cssPropertyIsExplicitlySet(width));\n const explicitAspectRatio = Boolean(aspectRatio && cssPropertyIsExplicitlySet(aspectRatio));\n\n const explicitWithAR = (explicitHeight || explicitWidth) && explicitAspectRatio;\n return (explicitHeight && explicitWidth) || explicitWithAR;\n}\n\n/**\n * Given an array of layout shift and PrePaint events, returns a mapping from\n * PrePaint events to layout shifts dispatched within it.\n */\nfunction getShiftsByPrePaintEvents(\n layoutShifts: Types.TraceEvents.TraceEventLayoutShift[],\n prePaintEvents: Types.TraceEvents.TraceEventPrePaint[],\n ): Map<Types.TraceEvents.TraceEventPrePaint, Types.TraceEvents.TraceEventLayoutShift[]> {\n // Maps from PrePaint events to LayoutShifts that occured in each one.\n const shiftsByPrePaint = new Map<Types.TraceEvents.TraceEventPrePaint, Types.TraceEvents.TraceEventLayoutShift[]>();\n\n // Associate all shifts to their corresponding PrePaint.\n for (const prePaintEvent of prePaintEvents) {\n const firstShiftIndex =\n Platform.ArrayUtilities.nearestIndexFromBeginning(layoutShifts, shift => shift.ts >= prePaintEvent.ts);\n if (firstShiftIndex === null) {\n // No layout shifts registered after this PrePaint start. Continue.\n continue;\n }\n for (let i = firstShiftIndex; i < layoutShifts.length; i++) {\n const shift = layoutShifts[i];\n if (shift.ts >= prePaintEvent.ts && shift.ts <= prePaintEvent.ts + prePaintEvent.dur) {\n const shiftsInPrePaint = Platform.MapUtilities.getWithDefault(shiftsByPrePaint, prePaintEvent, () => []);\n shiftsInPrePaint.push(shift);\n }\n if (shift.ts > prePaintEvent.ts + prePaintEvent.dur) {\n // Reached the end of this PrePaint. Continue to the next one.\n break;\n }\n }\n }\n return shiftsByPrePaint;\n}\n"],
|
|
6
|
-
"mappings": "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",
|
|
7
|
-
"names": []
|
|
8
|
-
}
|