@paulirish/trace_engine 0.0.38 → 0.0.40

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.
Files changed (276) hide show
  1. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  2. package/core/platform/DevToolsPath.d.ts +30 -9
  3. package/core/platform/DevToolsPath.js +21 -0
  4. package/core/platform/DevToolsPath.js.map +1 -1
  5. package/core/platform/MapUtilities.js +1 -1
  6. package/core/platform/MapUtilities.js.map +1 -1
  7. package/core/platform/ServerTiming.d.ts +2 -2
  8. package/core/platform/ServerTiming.js.map +1 -1
  9. package/core/platform/StringUtilities.js +1 -1
  10. package/core/platform/StringUtilities.js.map +1 -1
  11. package/core/platform/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  12. package/core/platform/platform-tsconfig.json +2 -1
  13. package/generated/protocol.d.ts +203 -73
  14. package/locales/af.json +86 -0
  15. package/locales/am.json +86 -0
  16. package/locales/ar.json +86 -0
  17. package/locales/as.json +86 -0
  18. package/locales/az.json +86 -0
  19. package/locales/be.json +86 -0
  20. package/locales/bg.json +86 -0
  21. package/locales/bn.json +86 -0
  22. package/locales/bs.json +86 -0
  23. package/locales/ca.json +86 -0
  24. package/locales/cs.json +86 -0
  25. package/locales/cy.json +86 -0
  26. package/locales/da.json +86 -0
  27. package/locales/de.json +86 -0
  28. package/locales/el.json +86 -0
  29. package/locales/en-GB.json +86 -0
  30. package/locales/en-US.json +86 -0
  31. package/locales/en-XL.json +86 -0
  32. package/locales/es-419.json +86 -0
  33. package/locales/es.json +86 -0
  34. package/locales/et.json +86 -0
  35. package/locales/eu.json +86 -0
  36. package/locales/fa.json +86 -0
  37. package/locales/fi.json +86 -0
  38. package/locales/fil.json +86 -0
  39. package/locales/fr-CA.json +86 -0
  40. package/locales/fr.json +86 -0
  41. package/locales/gl.json +86 -0
  42. package/locales/gu.json +86 -0
  43. package/locales/he.json +86 -0
  44. package/locales/hi.json +86 -0
  45. package/locales/hr.json +86 -0
  46. package/locales/hu.json +86 -0
  47. package/locales/hy.json +86 -0
  48. package/locales/id.json +86 -0
  49. package/locales/is.json +86 -0
  50. package/locales/it.json +86 -0
  51. package/locales/ja.json +86 -0
  52. package/locales/ka.json +86 -0
  53. package/locales/kk.json +86 -0
  54. package/locales/km.json +86 -0
  55. package/locales/kn.json +86 -0
  56. package/locales/ko.json +86 -0
  57. package/locales/ky.json +86 -0
  58. package/locales/lo.json +86 -0
  59. package/locales/lt.json +86 -0
  60. package/locales/lv.json +86 -0
  61. package/locales/mk.json +86 -0
  62. package/locales/ml.json +86 -0
  63. package/locales/mn.json +86 -0
  64. package/locales/mr.json +86 -0
  65. package/locales/ms.json +86 -0
  66. package/locales/my.json +86 -0
  67. package/locales/ne.json +86 -0
  68. package/locales/nl.json +86 -0
  69. package/locales/no.json +86 -0
  70. package/locales/or.json +86 -0
  71. package/locales/pa.json +86 -0
  72. package/locales/pl.json +86 -0
  73. package/locales/pt-PT.json +86 -0
  74. package/locales/pt.json +86 -0
  75. package/locales/ro.json +86 -0
  76. package/locales/ru.json +86 -0
  77. package/locales/si.json +86 -0
  78. package/locales/sk.json +86 -0
  79. package/locales/sl.json +86 -0
  80. package/locales/sq.json +86 -0
  81. package/locales/sr-Latn.json +86 -0
  82. package/locales/sr.json +86 -0
  83. package/locales/sv.json +86 -0
  84. package/locales/sw.json +86 -0
  85. package/locales/ta.json +86 -0
  86. package/locales/te.json +86 -0
  87. package/locales/th.json +86 -0
  88. package/locales/tr.json +86 -0
  89. package/locales/uk.json +86 -0
  90. package/locales/ur.json +86 -0
  91. package/locales/uz.json +86 -0
  92. package/locales/vi.json +86 -0
  93. package/locales/zh-HK.json +86 -0
  94. package/locales/zh-TW.json +86 -0
  95. package/locales/zh.json +86 -0
  96. package/locales/zu.json +86 -0
  97. package/models/cpu_profile/ProfileTreeModel.js +0 -2
  98. package/models/cpu_profile/ProfileTreeModel.js.map +1 -1
  99. package/models/cpu_profile/cpu_profile-tsconfig.json +2 -1
  100. package/models/cpu_profile/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  101. package/models/trace/LanternComputationData.js +1 -1
  102. package/models/trace/LanternComputationData.js.map +1 -1
  103. package/models/trace/ModelImpl.d.ts +6 -6
  104. package/models/trace/ModelImpl.js +1 -0
  105. package/models/trace/ModelImpl.js.map +1 -1
  106. package/models/trace/Processor.d.ts +6 -0
  107. package/models/trace/Processor.js +90 -9
  108. package/models/trace/Processor.js.map +1 -1
  109. package/models/trace/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  110. package/models/trace/extras/StackTraceForEvent.d.ts +12 -0
  111. package/models/trace/extras/StackTraceForEvent.js +163 -0
  112. package/models/trace/extras/StackTraceForEvent.js.map +1 -0
  113. package/models/trace/extras/ThirdParties.d.ts +7 -4
  114. package/models/trace/extras/ThirdParties.js +56 -65
  115. package/models/trace/extras/ThirdParties.js.map +1 -1
  116. package/models/trace/extras/TraceTree.js +8 -8
  117. package/models/trace/extras/TraceTree.js.map +1 -1
  118. package/models/trace/extras/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  119. package/models/trace/extras/extras-tsconfig.json +3 -2
  120. package/models/trace/extras/extras.js.map +1 -1
  121. package/models/trace/handlers/AnimationFramesHandler.d.ts +11 -0
  122. package/models/trace/handlers/AnimationFramesHandler.js +102 -0
  123. package/models/trace/handlers/AnimationFramesHandler.js.map +1 -0
  124. package/models/trace/handlers/AsyncJSCallsHandler.d.ts +15 -0
  125. package/models/trace/handlers/AsyncJSCallsHandler.js +153 -0
  126. package/models/trace/handlers/AsyncJSCallsHandler.js.map +1 -0
  127. package/models/trace/handlers/DOMStatsHandler.d.ts +8 -0
  128. package/models/trace/handlers/DOMStatsHandler.js +22 -0
  129. package/models/trace/handlers/DOMStatsHandler.js.map +1 -0
  130. package/models/trace/handlers/ExtensionTraceDataHandler.d.ts +80 -2
  131. package/models/trace/handlers/ExtensionTraceDataHandler.js +163 -13
  132. package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
  133. package/models/trace/handlers/FlowsHandler.js +47 -55
  134. package/models/trace/handlers/FlowsHandler.js.map +1 -1
  135. package/models/trace/handlers/InitiatorsHandler.d.ts +11 -0
  136. package/models/trace/handlers/InitiatorsHandler.js +33 -25
  137. package/models/trace/handlers/InitiatorsHandler.js.map +1 -1
  138. package/models/trace/handlers/LargestImagePaintHandler.d.ts +0 -2
  139. package/models/trace/handlers/LargestImagePaintHandler.js +27 -24
  140. package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
  141. package/models/trace/handlers/LayoutShiftsHandler.d.ts +2 -2
  142. package/models/trace/handlers/LayoutShiftsHandler.js +3 -2
  143. package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
  144. package/models/trace/handlers/MetaHandler.d.ts +2 -2
  145. package/models/trace/handlers/MetaHandler.js +1 -1
  146. package/models/trace/handlers/MetaHandler.js.map +1 -1
  147. package/models/trace/handlers/ModelHandlers.d.ts +4 -1
  148. package/models/trace/handlers/ModelHandlers.js +4 -1
  149. package/models/trace/handlers/ModelHandlers.js.map +1 -1
  150. package/models/trace/handlers/NetworkRequestsHandler.d.ts +2 -0
  151. package/models/trace/handlers/NetworkRequestsHandler.js +21 -0
  152. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  153. package/models/trace/handlers/PageLoadMetricsHandler.d.ts +2 -2
  154. package/models/trace/handlers/PageLoadMetricsHandler.js +9 -9
  155. package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
  156. package/models/trace/handlers/RendererHandler.d.ts +4 -0
  157. package/models/trace/handlers/RendererHandler.js +33 -2
  158. package/models/trace/handlers/RendererHandler.js.map +1 -1
  159. package/models/trace/handlers/SamplesHandler.d.ts +2 -2
  160. package/models/trace/handlers/SamplesHandler.js +3 -3
  161. package/models/trace/handlers/SamplesHandler.js.map +1 -1
  162. package/models/trace/handlers/ServerTimingsHandler.js +2 -2
  163. package/models/trace/handlers/ServerTimingsHandler.js.map +1 -1
  164. package/models/trace/handlers/Threads.d.ts +1 -0
  165. package/models/trace/handlers/Threads.js +8 -0
  166. package/models/trace/handlers/Threads.js.map +1 -1
  167. package/models/trace/handlers/UserInteractionsHandler.js +5 -6
  168. package/models/trace/handlers/UserInteractionsHandler.js.map +1 -1
  169. package/models/trace/handlers/UserTimingsHandler.d.ts +1 -1
  170. package/models/trace/handlers/UserTimingsHandler.js +1 -1
  171. package/models/trace/handlers/UserTimingsHandler.js.map +1 -1
  172. package/models/trace/handlers/WarningsHandler.js +2 -2
  173. package/models/trace/handlers/WarningsHandler.js.map +1 -1
  174. package/models/trace/handlers/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  175. package/models/trace/handlers/handlers-tsconfig.json +9 -1
  176. package/models/trace/handlers/handlers.d.ts +1 -0
  177. package/models/trace/handlers/handlers.js +1 -0
  178. package/models/trace/handlers/handlers.js.map +1 -1
  179. package/models/trace/handlers/helpers.d.ts +19 -0
  180. package/models/trace/handlers/helpers.js +123 -0
  181. package/models/trace/handlers/helpers.js.map +1 -0
  182. package/models/trace/helpers/SamplesIntegrator.js +2 -2
  183. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  184. package/models/trace/helpers/SyntheticEvents.js +1 -1
  185. package/models/trace/helpers/SyntheticEvents.js.map +1 -1
  186. package/models/trace/helpers/Timing.d.ts +5 -6
  187. package/models/trace/helpers/Timing.js +22 -31
  188. package/models/trace/helpers/Timing.js.map +1 -1
  189. package/models/trace/helpers/Trace.d.ts +24 -10
  190. package/models/trace/helpers/Trace.js +53 -6
  191. package/models/trace/helpers/Trace.js.map +1 -1
  192. package/models/trace/helpers/TreeHelpers.d.ts +0 -31
  193. package/models/trace/helpers/TreeHelpers.js +1 -142
  194. package/models/trace/helpers/TreeHelpers.js.map +1 -1
  195. package/models/trace/helpers/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  196. package/models/trace/helpers/helpers-tsconfig.json +2 -1
  197. package/models/trace/insights/CLSCulprits.js +1 -2
  198. package/models/trace/insights/CLSCulprits.js.map +1 -1
  199. package/models/trace/insights/Common.d.ts +38 -1
  200. package/models/trace/insights/Common.js +123 -0
  201. package/models/trace/insights/Common.js.map +1 -1
  202. package/models/trace/insights/DOMSize.d.ts +9 -0
  203. package/models/trace/insights/DOMSize.js +102 -0
  204. package/models/trace/insights/DOMSize.js.map +1 -0
  205. package/models/trace/insights/DocumentLatency.js +1 -1
  206. package/models/trace/insights/DocumentLatency.js.map +1 -1
  207. package/models/trace/insights/FontDisplay.js +1 -1
  208. package/models/trace/insights/FontDisplay.js.map +1 -1
  209. package/models/trace/insights/ImageDelivery.d.ts +22 -4
  210. package/models/trace/insights/ImageDelivery.js +76 -6
  211. package/models/trace/insights/ImageDelivery.js.map +1 -1
  212. package/models/trace/insights/LCPDiscovery.js +2 -2
  213. package/models/trace/insights/LCPDiscovery.js.map +1 -1
  214. package/models/trace/insights/LCPPhases.js +7 -7
  215. package/models/trace/insights/LCPPhases.js.map +1 -1
  216. package/models/trace/insights/Models.d.ts +1 -0
  217. package/models/trace/insights/Models.js +1 -0
  218. package/models/trace/insights/Models.js.map +1 -1
  219. package/models/trace/insights/Statistics.d.ts +14 -0
  220. package/models/trace/insights/Statistics.js +86 -0
  221. package/models/trace/insights/Statistics.js.map +1 -0
  222. package/models/trace/insights/ThirdParties.d.ts +2 -2
  223. package/models/trace/insights/ThirdParties.js +5 -4
  224. package/models/trace/insights/ThirdParties.js.map +1 -1
  225. package/models/trace/insights/Viewport.js +2 -2
  226. package/models/trace/insights/Viewport.js.map +1 -1
  227. package/models/trace/insights/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  228. package/models/trace/insights/insights-tsconfig.json +4 -1
  229. package/models/trace/insights/insights.d.ts +1 -0
  230. package/models/trace/insights/insights.js +1 -0
  231. package/models/trace/insights/insights.js.map +1 -1
  232. package/models/trace/insights/types.d.ts +4 -3
  233. package/models/trace/insights/types.js.map +1 -1
  234. package/models/trace/lantern/core/NetworkAnalyzer.d.ts +2 -2
  235. package/models/trace/lantern/core/NetworkAnalyzer.js +2 -3
  236. package/models/trace/lantern/core/NetworkAnalyzer.js.map +1 -1
  237. package/models/trace/lantern/core/core-tsconfig.json +2 -1
  238. package/models/trace/lantern/core/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  239. package/models/trace/lantern/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  240. package/models/trace/lantern/graph/PageDependencyGraph.js +0 -1
  241. package/models/trace/lantern/graph/PageDependencyGraph.js.map +1 -1
  242. package/models/trace/lantern/graph/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  243. package/models/trace/lantern/graph/graph-tsconfig.json +2 -1
  244. package/models/trace/lantern/lantern-tsconfig.json +2 -1
  245. package/models/trace/lantern/metrics/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  246. package/models/trace/lantern/metrics/metrics-tsconfig.json +2 -1
  247. package/models/trace/lantern/simulation/DNSCache.d.ts +2 -2
  248. package/models/trace/lantern/simulation/DNSCache.js.map +1 -1
  249. package/models/trace/lantern/simulation/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  250. package/models/trace/lantern/simulation/simulation-tsconfig.json +2 -1
  251. package/models/trace/lantern/types/Lantern.d.ts +10 -10
  252. package/models/trace/lantern/types/Lantern.js.map +1 -1
  253. package/models/trace/lantern/types/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  254. package/models/trace/lantern/types/types-tsconfig.json +2 -1
  255. package/models/trace/root-causes/LayoutShift.d.ts +6 -6
  256. package/models/trace/root-causes/LayoutShift.js +1 -1
  257. package/models/trace/root-causes/LayoutShift.js.map +1 -1
  258. package/models/trace/root-causes/RootCauses.d.ts +2 -2
  259. package/models/trace/root-causes/RootCauses.js.map +1 -1
  260. package/models/trace/root-causes/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  261. package/models/trace/root-causes/root-causes-tsconfig.json +2 -1
  262. package/models/trace/trace-tsconfig.json +2 -1
  263. package/models/trace/types/Configuration.d.ts +2 -2
  264. package/models/trace/types/Configuration.js.map +1 -1
  265. package/models/trace/types/Extensions.d.ts +3 -3
  266. package/models/trace/types/Extensions.js.map +1 -1
  267. package/models/trace/types/File.d.ts +11 -11
  268. package/models/trace/types/File.js.map +1 -1
  269. package/models/trace/types/Timing.js.map +1 -1
  270. package/models/trace/types/TraceEvents.d.ts +107 -31
  271. package/models/trace/types/TraceEvents.js +34 -14
  272. package/models/trace/types/TraceEvents.js.map +1 -1
  273. package/models/trace/types/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -1
  274. package/models/trace/types/types-tsconfig.json +2 -1
  275. package/package.json +1 -1
  276. package/test/test-trace-engine.mjs +8 -7
@@ -0,0 +1,15 @@
1
+ import * as Types from '../types/types.js';
2
+ declare const schedulerToRunEntryPoints: Map<Types.Events.Event, Types.Events.Event[]>;
3
+ declare const asyncCallToScheduler: Map<Types.Events.SyntheticProfileCall, {
4
+ taskName: string;
5
+ scheduler: Types.Events.Event;
6
+ }>;
7
+ export declare function reset(): void;
8
+ export declare function handleEvent(_: Types.Events.Event): void;
9
+ export declare function finalize(): Promise<void>;
10
+ export declare function data(): {
11
+ schedulerToRunEntryPoints: typeof schedulerToRunEntryPoints;
12
+ asyncCallToScheduler: typeof asyncCallToScheduler;
13
+ };
14
+ export declare function deps(): ['Renderer', 'Flows'];
15
+ export {};
@@ -0,0 +1,153 @@
1
+ // Copyright 2024 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+ import * as Platform from '../../../core/platform/platform.js';
5
+ import * as Types from '../types/types.js';
6
+ import { data as flowsHandlerData } from './FlowsHandler.js';
7
+ import { data as rendererHandlerData } from './RendererHandler.js';
8
+ const schedulerToRunEntryPoints = new Map();
9
+ const asyncCallToScheduler = new Map();
10
+ export function reset() {
11
+ schedulerToRunEntryPoints.clear();
12
+ asyncCallToScheduler.clear();
13
+ }
14
+ export function handleEvent(_) {
15
+ }
16
+ export async function finalize() {
17
+ const { flows } = flowsHandlerData();
18
+ const { entryToNode } = rendererHandlerData();
19
+ // Process async task flows
20
+ for (const flow of flows) {
21
+ const asyncTaskScheduled = flow.at(0);
22
+ if (!asyncTaskScheduled || !Types.Events.isDebuggerAsyncTaskScheduled(asyncTaskScheduled)) {
23
+ continue;
24
+ }
25
+ const taskName = asyncTaskScheduled.args.taskName;
26
+ const asyncTaskRun = flow.at(1);
27
+ if (!asyncTaskRun || !Types.Events.isDebuggerAsyncTaskRun(asyncTaskRun)) {
28
+ // Unexpected flow shape, ignore.
29
+ continue;
30
+ }
31
+ const asyncCaller = findNearestJSAncestor(asyncTaskScheduled, entryToNode);
32
+ if (!asyncCaller) {
33
+ // Unexpected async call trace data shape, ignore.
34
+ continue;
35
+ }
36
+ const asyncEntryPoint = findFirstJsInvocationForAsyncTaskRun(asyncTaskRun, entryToNode);
37
+ if (!asyncEntryPoint) {
38
+ // Unexpected async call trace data shape, ignore.
39
+ continue;
40
+ }
41
+ // Set scheduler -> schedulee mapping.
42
+ // The schedulee being the JS entrypoint
43
+ const entryPoints = Platform.MapUtilities.getWithDefault(schedulerToRunEntryPoints, asyncCaller, () => []);
44
+ entryPoints.push(asyncEntryPoint);
45
+ // Set schedulee -> scheduler mapping.
46
+ // The schedulees being the JS calls (instead of the entrypoints as
47
+ // above, for usage ergonomics).
48
+ const scheduledProfileCalls = findFirstJSCallsForAsyncTaskRun(asyncTaskRun, entryToNode);
49
+ for (const call of scheduledProfileCalls) {
50
+ asyncCallToScheduler.set(call, { taskName, scheduler: asyncCaller });
51
+ }
52
+ }
53
+ }
54
+ /**
55
+ * Given a DebuggerAsyncTaskScheduled event, returns its closest
56
+ * ProfileCall or JS invocation ancestor, which represents the JS call
57
+ * that scheduled the async task.
58
+ */
59
+ function findNearestJSAncestor(asyncTaskScheduled, entryToNode) {
60
+ let node = entryToNode.get(asyncTaskScheduled)?.parent;
61
+ while (node) {
62
+ if (Types.Events.isProfileCall(node.entry) || acceptJSInvocationsPredicate(node.entry)) {
63
+ return node.entry;
64
+ }
65
+ node = node.parent;
66
+ }
67
+ return null;
68
+ }
69
+ /**
70
+ * Entrypoints to JS execution in the timeline. We ignore those starting
71
+ * with 'v8' because they aren't shown in the timeline, and ultimately
72
+ * this function's output results in "initiated" events, so ideally this
73
+ * returns events that end up in the flame chart.
74
+ */
75
+ function acceptJSInvocationsPredicate(event) {
76
+ const eventIsConsoleRunTask = Types.Events.isConsoleRunTask(event);
77
+ const eventIsV8EntryPoint = event.name.startsWith('v8') || event.name.startsWith('V8');
78
+ return Types.Events.isJSInvocationEvent(event) && (eventIsConsoleRunTask || !eventIsV8EntryPoint);
79
+ }
80
+ /**
81
+ * Given a DebuggerAsyncTaskRun event, returns its closest JS entry
82
+ * point descendant, which contains the task being scheduled.
83
+ */
84
+ function findFirstJsInvocationForAsyncTaskRun(asyncTaskRun, entryToNode) {
85
+ // Ignore descendants of other DebuggerAsyncTaskRuns since they
86
+ // are part of another async task and have to be handled separately
87
+ return findFirstDescendantsOfType(asyncTaskRun, entryToNode, acceptJSInvocationsPredicate, Types.Events.isDebuggerAsyncTaskRun)
88
+ .at(0);
89
+ }
90
+ /**
91
+ * Given an async task run event, returns the top level call frames
92
+ * (profile calls) directly called by the async task. This implies that
93
+ * any profile calls under another async task run event are ignored.
94
+ * These profile calls represent the JS task being scheduled, AKA
95
+ * the other part of the async stack.
96
+ *
97
+ * For example, here the profile calls "js 1", "js 2" and "js 4" would
98
+ * be returned:
99
+ *
100
+ * |------------------Async Task Run------------------|
101
+ * |--FunctionCall--| |--FunctionCall--|
102
+ * |-js 1-||-js 2-| |-js 4-|
103
+ * |-js 3-|
104
+ *
105
+ * But here, only "js 1" and "js 2" would be returned:
106
+ *
107
+ * |------------------Async Task Run------------------|
108
+ * |--FunctionCall--| |------------------------|
109
+ * |-js 1-||-js 2-| |---Async Task Run--|
110
+ * |-js 3-| |--FunctionCall--|
111
+ * |-js 4-|
112
+ */
113
+ function findFirstJSCallsForAsyncTaskRun(asyncTaskRun, entryToNode) {
114
+ // Ignore descendants of other DebuggerAsyncTaskRuns since they
115
+ // are part of another async task and have to be handled separately
116
+ return findFirstDescendantsOfType(asyncTaskRun, entryToNode, Types.Events.isProfileCall, Types.Events.isDebuggerAsyncTaskRun);
117
+ }
118
+ /**
119
+ * Given a root event returns all the first descendants that meet a
120
+ * predicate condition (predicateAccept) while ignoring subtrees whose
121
+ * top event meets an ignore condition (predicateIgnore).
122
+ */
123
+ function findFirstDescendantsOfType(root, entryToNode, predicateAccept, predicateIgnore) {
124
+ const node = entryToNode.get(root);
125
+ if (!node) {
126
+ return [];
127
+ }
128
+ const childrenGroups = [[...node.children]];
129
+ const firstDescendants = [];
130
+ for (let i = 0; i < childrenGroups.length; i++) {
131
+ const siblings = childrenGroups[i];
132
+ for (let j = 0; j < siblings.length; j++) {
133
+ const node = siblings[j];
134
+ if (predicateAccept(node.entry)) {
135
+ firstDescendants.push(node.entry);
136
+ }
137
+ else if (!predicateIgnore(node.entry)) {
138
+ childrenGroups.push([...node.children]);
139
+ }
140
+ }
141
+ }
142
+ return firstDescendants;
143
+ }
144
+ export function data() {
145
+ return {
146
+ schedulerToRunEntryPoints,
147
+ asyncCallToScheduler,
148
+ };
149
+ }
150
+ export function deps() {
151
+ return ['Renderer', 'Flows'];
152
+ }
153
+ //# sourceMappingURL=AsyncJSCallsHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AsyncJSCallsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/AsyncJSCallsHandler.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAC7B,OAAO,KAAK,QAAQ,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAC,IAAI,IAAI,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAC,IAAI,IAAI,mBAAmB,EAAC,MAAM,sBAAsB,CAAC;AAEjE,MAAM,yBAAyB,GAAkD,IAAI,GAAG,EAAE,CAAC;AAC3F,MAAM,oBAAoB,GACtB,IAAI,GAAG,EAAE,CAAC;AAEd,MAAM,UAAU,KAAK;IACnB,yBAAyB,CAAC,KAAK,EAAE,CAAC;IAClC,oBAAoB,CAAC,KAAK,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,CAAqB;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,EAAC,KAAK,EAAC,GAAG,gBAAgB,EAAE,CAAC;IACnC,MAAM,EAAC,WAAW,EAAC,GAAG,mBAAmB,EAAE,CAAC;IAC5C,2BAA2B;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,kBAAkB,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,kBAAkB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,4BAA4B,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC1F,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAClD,MAAM,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,YAAY,CAAC,EAAE,CAAC;YACxE,iCAAiC;YACjC,SAAS;QACX,CAAC;QACD,MAAM,WAAW,GAAG,qBAAqB,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC;QAC3E,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,kDAAkD;YAClD,SAAS;QACX,CAAC;QACD,MAAM,eAAe,GAAG,oCAAoC,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QACxF,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,kDAAkD;YAClD,SAAS;QACX,CAAC;QACD,sCAAsC;QACtC,wCAAwC;QACxC,MAAM,WAAW,GAAG,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,yBAAyB,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3G,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAElC,sCAAsC;QACtC,mEAAmE;QACnE,gCAAgC;QAChC,MAAM,qBAAqB,GAAG,+BAA+B,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QACzF,KAAK,MAAM,IAAI,IAAI,qBAAqB,EAAE,CAAC;YACzC,oBAAoB,CAAC,GAAG,CAAC,IAAI,EAAE,EAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAC,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;AACH,CAAC;AACD;;;;GAIG;AACH,SAAS,qBAAqB,CAC1B,kBAA2D,EAC3D,WAAwE;IAC1E,IAAI,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACvD,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACvF,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QACD,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AACD;;;;;GAKG;AACH,SAAS,4BAA4B,CAAC,KAAyB;IAC7D,MAAM,qBAAqB,GAAG,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACnE,MAAM,mBAAmB,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACvF,OAAO,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,IAAI,CAAC,mBAAmB,CAAC,CAAC;AACpG,CAAC;AAED;;;GAGG;AACH,SAAS,oCAAoC,CACzC,YAA+C,EAC/C,WAAwE;IAC1E,+DAA+D;IAC/D,mEAAmE;IACnE,OAAO,0BAA0B,CACtB,YAAY,EAAE,WAAW,EAAE,4BAA4B,EAAE,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC;SACnG,EAAE,CAAC,CAAC,CAAC,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAS,+BAA+B,CACpC,YAA+C,EAC/C,WAAwE;IAC1E,+DAA+D;IAC/D,mEAAmE;IACnE,OAAO,0BAA0B,CAC7B,YAAY,EAAE,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAClG,CAAC;AAED;;;;GAIG;AACH,SAAS,0BAA0B,CAC/B,IAAwB,EAAE,WAAwE,EAClG,eAA0D,EAC1D,eAAuD;IACzD,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,cAAc,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5C,MAAM,gBAAgB,GAAG,EAAE,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;iBAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,IAAI;IAWlB,OAAO;QACL,yBAAyB;QACzB,oBAAoB;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAC/B,CAAC","sourcesContent":["// Copyright 2024 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';\nimport type * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as flowsHandlerData} from './FlowsHandler.js';\nimport {data as rendererHandlerData} from './RendererHandler.js';\n\nconst schedulerToRunEntryPoints: Map<Types.Events.Event, Types.Events.Event[]> = new Map();\nconst asyncCallToScheduler: Map<Types.Events.SyntheticProfileCall, {taskName: string, scheduler: Types.Events.Event}> =\n new Map();\n\nexport function reset(): void {\n schedulerToRunEntryPoints.clear();\n asyncCallToScheduler.clear();\n}\n\nexport function handleEvent(_: Types.Events.Event): void {\n}\n\nexport async function finalize(): Promise<void> {\n const {flows} = flowsHandlerData();\n const {entryToNode} = rendererHandlerData();\n // Process async task flows\n for (const flow of flows) {\n const asyncTaskScheduled = flow.at(0);\n if (!asyncTaskScheduled || !Types.Events.isDebuggerAsyncTaskScheduled(asyncTaskScheduled)) {\n continue;\n }\n const taskName = asyncTaskScheduled.args.taskName;\n const asyncTaskRun = flow.at(1);\n if (!asyncTaskRun || !Types.Events.isDebuggerAsyncTaskRun(asyncTaskRun)) {\n // Unexpected flow shape, ignore.\n continue;\n }\n const asyncCaller = findNearestJSAncestor(asyncTaskScheduled, entryToNode);\n if (!asyncCaller) {\n // Unexpected async call trace data shape, ignore.\n continue;\n }\n const asyncEntryPoint = findFirstJsInvocationForAsyncTaskRun(asyncTaskRun, entryToNode);\n if (!asyncEntryPoint) {\n // Unexpected async call trace data shape, ignore.\n continue;\n }\n // Set scheduler -> schedulee mapping.\n // The schedulee being the JS entrypoint\n const entryPoints = Platform.MapUtilities.getWithDefault(schedulerToRunEntryPoints, asyncCaller, () => []);\n entryPoints.push(asyncEntryPoint);\n\n // Set schedulee -> scheduler mapping.\n // The schedulees being the JS calls (instead of the entrypoints as\n // above, for usage ergonomics).\n const scheduledProfileCalls = findFirstJSCallsForAsyncTaskRun(asyncTaskRun, entryToNode);\n for (const call of scheduledProfileCalls) {\n asyncCallToScheduler.set(call, {taskName, scheduler: asyncCaller});\n }\n }\n}\n/**\n * Given a DebuggerAsyncTaskScheduled event, returns its closest\n * ProfileCall or JS invocation ancestor, which represents the JS call\n * that scheduled the async task.\n */\nfunction findNearestJSAncestor(\n asyncTaskScheduled: Types.Events.DebuggerAsyncTaskScheduled,\n entryToNode: Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode>): Types.Events.Event|null {\n let node = entryToNode.get(asyncTaskScheduled)?.parent;\n while (node) {\n if (Types.Events.isProfileCall(node.entry) || acceptJSInvocationsPredicate(node.entry)) {\n return node.entry;\n }\n node = node.parent;\n }\n return null;\n}\n/**\n * Entrypoints to JS execution in the timeline. We ignore those starting\n * with 'v8' because they aren't shown in the timeline, and ultimately\n * this function's output results in \"initiated\" events, so ideally this\n * returns events that end up in the flame chart.\n */\nfunction acceptJSInvocationsPredicate(event: Types.Events.Event): event is Types.Events.Event {\n const eventIsConsoleRunTask = Types.Events.isConsoleRunTask(event);\n const eventIsV8EntryPoint = event.name.startsWith('v8') || event.name.startsWith('V8');\n return Types.Events.isJSInvocationEvent(event) && (eventIsConsoleRunTask || !eventIsV8EntryPoint);\n}\n\n/**\n * Given a DebuggerAsyncTaskRun event, returns its closest JS entry\n * point descendant, which contains the task being scheduled.\n */\nfunction findFirstJsInvocationForAsyncTaskRun(\n asyncTaskRun: Types.Events.DebuggerAsyncTaskRun,\n entryToNode: Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode>): Types.Events.Event|undefined {\n // Ignore descendants of other DebuggerAsyncTaskRuns since they\n // are part of another async task and have to be handled separately\n return findFirstDescendantsOfType(\n asyncTaskRun, entryToNode, acceptJSInvocationsPredicate, Types.Events.isDebuggerAsyncTaskRun)\n .at(0);\n}\n\n/**\n * Given an async task run event, returns the top level call frames\n * (profile calls) directly called by the async task. This implies that\n * any profile calls under another async task run event are ignored.\n * These profile calls represent the JS task being scheduled, AKA\n * the other part of the async stack.\n *\n * For example, here the profile calls \"js 1\", \"js 2\" and \"js 4\" would\n * be returned:\n *\n * |------------------Async Task Run------------------|\n * |--FunctionCall--| |--FunctionCall--|\n * |-js 1-||-js 2-| |-js 4-|\n * |-js 3-|\n *\n * But here, only \"js 1\" and \"js 2\" would be returned:\n *\n * |------------------Async Task Run------------------|\n * |--FunctionCall--| |------------------------|\n * |-js 1-||-js 2-| |---Async Task Run--|\n * |-js 3-| |--FunctionCall--|\n * |-js 4-|\n */\nfunction findFirstJSCallsForAsyncTaskRun(\n asyncTaskRun: Types.Events.DebuggerAsyncTaskRun,\n entryToNode: Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode>): Types.Events.SyntheticProfileCall[] {\n // Ignore descendants of other DebuggerAsyncTaskRuns since they\n // are part of another async task and have to be handled separately\n return findFirstDescendantsOfType(\n asyncTaskRun, entryToNode, Types.Events.isProfileCall, Types.Events.isDebuggerAsyncTaskRun);\n}\n\n/**\n * Given a root event returns all the first descendants that meet a\n * predicate condition (predicateAccept) while ignoring subtrees whose\n * top event meets an ignore condition (predicateIgnore).\n */\nfunction findFirstDescendantsOfType<T extends Types.Events.Event>(\n root: Types.Events.Event, entryToNode: Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode>,\n predicateAccept: (event: Types.Events.Event) => event is T,\n predicateIgnore: (event: Types.Events.Event) => boolean): T[] {\n const node = entryToNode.get(root);\n if (!node) {\n return [];\n }\n const childrenGroups = [[...node.children]];\n const firstDescendants = [];\n for (let i = 0; i < childrenGroups.length; i++) {\n const siblings = childrenGroups[i];\n for (let j = 0; j < siblings.length; j++) {\n const node = siblings[j];\n if (predicateAccept(node.entry)) {\n firstDescendants.push(node.entry);\n } else if (!predicateIgnore(node.entry)) {\n childrenGroups.push([...node.children]);\n }\n }\n }\n return firstDescendants;\n}\n\nexport function data(): {\n // Given a profile call, returns the JS entrypoint it scheduled (if any).\n // For example, given a setTimeout call, returns the JS entry point\n // trace event for the timeout callback run event (usually a\n // FunctionCall event).\n schedulerToRunEntryPoints: typeof schedulerToRunEntryPoints,\n // Given a profile call, returns the profile call that scheduled it.\n // For example given a timeout callback run event, returns its\n // setTimeout call event.\n asyncCallToScheduler: typeof asyncCallToScheduler,\n} {\n return {\n schedulerToRunEntryPoints,\n asyncCallToScheduler,\n };\n}\n\nexport function deps(): ['Renderer', 'Flows'] {\n return ['Renderer', 'Flows'];\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import * as Types from '../types/types.js';
2
+ export interface DOMStatsData {
3
+ domStatsByFrameId: Map<string, Types.Events.DOMStats[]>;
4
+ }
5
+ export declare function reset(): void;
6
+ export declare function handleEvent(event: Types.Events.Event): void;
7
+ export declare function finalize(): Promise<void>;
8
+ export declare function data(): DOMStatsData;
@@ -0,0 +1,22 @@
1
+ // Copyright 2025 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+ import * as Platform from '../../../core/platform/platform.js';
5
+ import * as Types from '../types/types.js';
6
+ const domStatsByFrameId = new Map();
7
+ export function reset() {
8
+ domStatsByFrameId.clear();
9
+ }
10
+ export function handleEvent(event) {
11
+ if (!Types.Events.isDOMStats(event)) {
12
+ return;
13
+ }
14
+ const domStatEvents = Platform.MapUtilities.getWithDefault(domStatsByFrameId, event.args.data.frame, () => []);
15
+ domStatEvents.push(event);
16
+ }
17
+ export async function finalize() {
18
+ }
19
+ export function data() {
20
+ return { domStatsByFrameId };
21
+ }
22
+ //# sourceMappingURL=DOMStatsHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DOMStatsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/DOMStatsHandler.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,QAAQ,MAAM,oCAAoC,CAAC;AAC/D,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAM3C,MAAM,iBAAiB,GAAsC,IAAI,GAAG,EAAE,CAAC;AAEvE,MAAM,UAAU,KAAK;IACnB,iBAAiB,CAAC,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAyB;IACnD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO;IACT,CAAC;IACD,MAAM,aAAa,GAAG,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,iBAAiB,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/G,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ;AAC9B,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,EAAC,iBAAiB,EAAC,CAAC;AAC7B,CAAC","sourcesContent":["// Copyright 2025 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 DOMStatsData {\n domStatsByFrameId: Map<string, Types.Events.DOMStats[]>;\n}\n\nconst domStatsByFrameId: DOMStatsData['domStatsByFrameId'] = new Map();\n\nexport function reset(): void {\n domStatsByFrameId.clear();\n}\n\nexport function handleEvent(event: Types.Events.Event): void {\n if (!Types.Events.isDOMStats(event)) {\n return;\n }\n const domStatEvents = Platform.MapUtilities.getWithDefault(domStatsByFrameId, event.args.data.frame, () => []);\n domStatEvents.push(event);\n}\n\nexport async function finalize(): Promise<void> {\n}\n\nexport function data(): DOMStatsData {\n return {domStatsByFrameId};\n}\n"]}
@@ -5,11 +5,89 @@ export interface ExtensionTraceData {
5
5
  extensionTrackData: readonly Types.Extensions.ExtensionTrackData[];
6
6
  extensionMarkers: readonly Types.Extensions.SyntheticExtensionMarker[];
7
7
  entryToNode: Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode>;
8
+ syntheticConsoleEntriesForTimingsTrack: Types.Events.SyntheticConsoleTimeStamp[];
8
9
  }
9
10
  export declare function handleEvent(_event: Types.Events.Event): void;
10
11
  export declare function reset(): void;
11
12
  export declare function finalize(): Promise<void>;
12
- export declare function extractExtensionEntries(timings: (Types.Events.SyntheticUserTimingPair | Types.Events.PerformanceMark)[]): void;
13
- export declare function extensionDataInTiming(timing: Types.Events.SyntheticUserTimingPair | Types.Events.PerformanceMark): Types.Extensions.ExtensionDataPayload | null;
13
+ /**
14
+ * Extracts extension entries from console.timeStamp events.
15
+ *
16
+ * Entries are built by pairing `console.timeStamp` events based on
17
+ * their names. When a `console.timeStamp` event includes a `start`
18
+ * argument (and optionally an `end` argument), it attempts to find
19
+ * previously recorded `console.timeStamp` events with names matching
20
+ * the `start` and `end` values. These matching events are then used to
21
+ * determine the start and end times of the new entry.
22
+ *
23
+ * If a `console.timeStamp` event includes data for a custom track
24
+ * (specified by the `track` argument), an extension track entry is
25
+ * created and added to the `extensionTrackEntries` array. These entries
26
+ * are used to visualize custom tracks in the Performance panel.
27
+ *
28
+ * If a `console.timeStamp` event includes data for a custom track
29
+ * (specified by the `track` argument), an extension track entry is
30
+ * created and added to the `extensionTrackEntries` array. These entries
31
+ * are used to visualize custom tracks in the Performance panel.
32
+ *
33
+ * If a `console.timeStamp` event does not specify a custom track but
34
+ * includes a start and/or end time (referencing other
35
+ * `console.timeStamp` names), a synthetic console time stamp entry is
36
+ * created and added to the `syntheticConsoleEntriesForTimingsTrack`
37
+ * array. These entries are displayed in the "Timings" track.
38
+ */
39
+ export declare function extractConsoleAPIExtensionEntries(): void;
40
+ /**
41
+ * Extracts extension entries from Performance API events (marks and
42
+ * measures).
43
+ * It specifically looks for events that contain extension-specific data
44
+ * within their `detail` property.
45
+ *
46
+ * If an event's `detail` property can be parsed as a JSON object and
47
+ * contains a `devtools` field with a valid extension payload, a
48
+ * synthetic extension entry is created. The type of extension entry
49
+ * created depends on the payload:
50
+ *
51
+ * - If the payload conforms to `ExtensionPayloadMarker`, a
52
+ * `SyntheticExtensionMarker` is created and added to the
53
+ * `extensionMarkers` array. These markers represent single points in
54
+ * time.
55
+ * - If the payload conforms to `ExtensionPayloadTrackEntry`, a
56
+ * `SyntheticExtensionTrackEntry` is created and added to the
57
+ * `extensionTrackEntries` array. These entries represent events with
58
+ * a duration and are displayed on custom tracks in the Performance
59
+ * panel.
60
+ *
61
+ * **Note:** Only events with a `detail` property that contains valid
62
+ * extension data are processed. Other `performance.mark` and
63
+ * `performance.measure` events are ignored.
64
+ *
65
+ * @param timings An array of `SyntheticUserTimingPair` or
66
+ * `PerformanceMark` events, typically obtained from the
67
+ * `UserTimingsHandler`.
68
+ */
69
+ export declare function extractPerformanceAPIExtensionEntries(timings: (Types.Events.SyntheticUserTimingPair | Types.Events.PerformanceMark)[]): void;
70
+ export declare function extensionDataInPerformanceTiming(timing: Types.Events.SyntheticUserTimingPair | Types.Events.PerformanceMark): Types.Extensions.ExtensionDataPayload | null;
71
+ /**
72
+ * Extracts extension data from a `console.timeStamp` event.
73
+ *
74
+ * Checks if a `console.timeStamp` event contains data intended for
75
+ * creating a custom track entry in the DevTools Performance panel. It
76
+ * specifically looks for a `track` argument within the event's data.
77
+ *
78
+ * If a `track` argument is present (and not an empty string), the
79
+ * function constructs an `ExtensionTrackEntryPayload` object containing
80
+ * the track name, an optional color, an optional track group. This
81
+ * payload is then used to create a `SyntheticExtensionTrackEntry`.
82
+ *
83
+ * **Note:** The `color` argument is optional and its type is validated
84
+ * against a predefined palette (see
85
+ * `ExtensionUI::extensionEntryColor`).
86
+ *
87
+ * @param timeStamp The `ConsoleTimeStamp` event to extract data from.
88
+ * @return An `ExtensionTrackEntryPayload` object if the event contains
89
+ * valid extension data for a track entry, or `null` otherwise.
90
+ */
91
+ export declare function extensionDataInConsoleTimeStamp(timeStamp: Types.Events.ConsoleTimeStamp): Types.Extensions.ExtensionTrackEntryPayload | null;
14
92
  export declare function data(): ExtensionTraceData;
15
93
  export declare function deps(): HandlerName[];
@@ -4,18 +4,22 @@
4
4
  import * as Helpers from '../helpers/helpers.js';
5
5
  import * as Types from '../types/types.js';
6
6
  import { data as userTimingsData } from './UserTimingsHandler.js';
7
- const extensionFlameChartEntries = [];
7
+ const extensionTrackEntries = [];
8
8
  const extensionTrackData = [];
9
9
  const extensionMarkers = [];
10
10
  const entryToNode = new Map();
11
+ const timeStampByName = new Map();
12
+ const syntheticConsoleEntriesForTimingsTrack = [];
11
13
  export function handleEvent(_event) {
12
14
  // Implementation not needed because data is sourced from UserTimingsHandler
13
15
  }
14
16
  export function reset() {
15
- extensionFlameChartEntries.length = 0;
17
+ extensionTrackEntries.length = 0;
18
+ syntheticConsoleEntriesForTimingsTrack.length = 0;
16
19
  extensionTrackData.length = 0;
17
20
  extensionMarkers.length = 0;
18
21
  entryToNode.clear();
22
+ timeStampByName.clear();
19
23
  }
20
24
  export async function finalize() {
21
25
  createExtensionFlameChartEntries();
@@ -24,12 +28,122 @@ function createExtensionFlameChartEntries() {
24
28
  const pairedMeasures = userTimingsData().performanceMeasures;
25
29
  const marks = userTimingsData().performanceMarks;
26
30
  const mergedRawExtensionEvents = Helpers.Trace.mergeEventsInOrder(pairedMeasures, marks);
27
- extractExtensionEntries(mergedRawExtensionEvents);
28
- Helpers.Extensions.buildTrackDataFromExtensionEntries(extensionFlameChartEntries, extensionTrackData, entryToNode);
31
+ extractPerformanceAPIExtensionEntries(mergedRawExtensionEvents);
32
+ extractConsoleAPIExtensionEntries();
33
+ // extensionTrackEntries is filled by the above two calls.
34
+ Helpers.Trace.sortTraceEventsInPlace(extensionTrackEntries);
35
+ Helpers.Extensions.buildTrackDataFromExtensionEntries(extensionTrackEntries, extensionTrackData, entryToNode);
29
36
  }
30
- export function extractExtensionEntries(timings) {
37
+ /**
38
+ * Extracts extension entries from console.timeStamp events.
39
+ *
40
+ * Entries are built by pairing `console.timeStamp` events based on
41
+ * their names. When a `console.timeStamp` event includes a `start`
42
+ * argument (and optionally an `end` argument), it attempts to find
43
+ * previously recorded `console.timeStamp` events with names matching
44
+ * the `start` and `end` values. These matching events are then used to
45
+ * determine the start and end times of the new entry.
46
+ *
47
+ * If a `console.timeStamp` event includes data for a custom track
48
+ * (specified by the `track` argument), an extension track entry is
49
+ * created and added to the `extensionTrackEntries` array. These entries
50
+ * are used to visualize custom tracks in the Performance panel.
51
+ *
52
+ * If a `console.timeStamp` event includes data for a custom track
53
+ * (specified by the `track` argument), an extension track entry is
54
+ * created and added to the `extensionTrackEntries` array. These entries
55
+ * are used to visualize custom tracks in the Performance panel.
56
+ *
57
+ * If a `console.timeStamp` event does not specify a custom track but
58
+ * includes a start and/or end time (referencing other
59
+ * `console.timeStamp` names), a synthetic console time stamp entry is
60
+ * created and added to the `syntheticConsoleEntriesForTimingsTrack`
61
+ * array. These entries are displayed in the "Timings" track.
62
+ */
63
+ export function extractConsoleAPIExtensionEntries() {
64
+ const consoleTimeStamps = userTimingsData().timestampEvents;
65
+ for (const currentTimeStamp of consoleTimeStamps) {
66
+ const timeStampName = String(currentTimeStamp.args.data.name);
67
+ timeStampByName.set(timeStampName, currentTimeStamp);
68
+ const extensionData = extensionDataInConsoleTimeStamp(currentTimeStamp);
69
+ const startName = currentTimeStamp.args.data.start;
70
+ const endName = currentTimeStamp.args.data.end;
71
+ if (!extensionData && !startName && !endName) {
72
+ continue;
73
+ }
74
+ const startTimeStamp = startName ? timeStampByName.get(String(startName)) : undefined;
75
+ const endTimeStamp = endName ? timeStampByName.get(String(endName)) : undefined;
76
+ if (endTimeStamp && !startTimeStamp) {
77
+ // Invalid data
78
+ continue;
79
+ }
80
+ const entryStartTime = startTimeStamp?.ts ?? currentTimeStamp.ts;
81
+ const entryEndTime = endTimeStamp?.ts ?? currentTimeStamp.ts;
82
+ if (extensionData) {
83
+ const unregisteredExtensionEntry = {
84
+ ...currentTimeStamp,
85
+ name: timeStampName,
86
+ cat: 'devtools.extension',
87
+ args: extensionData,
88
+ rawSourceEvent: currentTimeStamp,
89
+ dur: Types.Timing.MicroSeconds(entryEndTime - entryStartTime),
90
+ ts: entryStartTime,
91
+ };
92
+ const extensionEntry = Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()
93
+ .registerSyntheticEvent(unregisteredExtensionEntry);
94
+ extensionTrackEntries.push(extensionEntry);
95
+ continue;
96
+ }
97
+ // If no extension data is found in the entry (no custom track name
98
+ // was passed), but the entry has a duration. we still save it here
99
+ // to be added in the timings track. Note that timings w/o duration
100
+ // and extension data are already handled by the UserTimingsHandler.
101
+ const unregisteredSyntheticTimeStamp = {
102
+ ...currentTimeStamp,
103
+ name: timeStampName,
104
+ cat: 'disabled-by-default-v8.inspector',
105
+ ph: "X" /* Types.Events.Phase.COMPLETE */,
106
+ ts: entryStartTime,
107
+ dur: Types.Timing.MicroSeconds(entryEndTime - entryStartTime),
108
+ rawSourceEvent: currentTimeStamp
109
+ };
110
+ const syntheticTimeStamp = Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()
111
+ .registerSyntheticEvent(unregisteredSyntheticTimeStamp);
112
+ syntheticConsoleEntriesForTimingsTrack.push(syntheticTimeStamp);
113
+ }
114
+ }
115
+ /**
116
+ * Extracts extension entries from Performance API events (marks and
117
+ * measures).
118
+ * It specifically looks for events that contain extension-specific data
119
+ * within their `detail` property.
120
+ *
121
+ * If an event's `detail` property can be parsed as a JSON object and
122
+ * contains a `devtools` field with a valid extension payload, a
123
+ * synthetic extension entry is created. The type of extension entry
124
+ * created depends on the payload:
125
+ *
126
+ * - If the payload conforms to `ExtensionPayloadMarker`, a
127
+ * `SyntheticExtensionMarker` is created and added to the
128
+ * `extensionMarkers` array. These markers represent single points in
129
+ * time.
130
+ * - If the payload conforms to `ExtensionPayloadTrackEntry`, a
131
+ * `SyntheticExtensionTrackEntry` is created and added to the
132
+ * `extensionTrackEntries` array. These entries represent events with
133
+ * a duration and are displayed on custom tracks in the Performance
134
+ * panel.
135
+ *
136
+ * **Note:** Only events with a `detail` property that contains valid
137
+ * extension data are processed. Other `performance.mark` and
138
+ * `performance.measure` events are ignored.
139
+ *
140
+ * @param timings An array of `SyntheticUserTimingPair` or
141
+ * `PerformanceMark` events, typically obtained from the
142
+ * `UserTimingsHandler`.
143
+ */
144
+ export function extractPerformanceAPIExtensionEntries(timings) {
31
145
  for (const timing of timings) {
32
- const extensionPayload = extensionDataInTiming(timing);
146
+ const extensionPayload = extensionDataInPerformanceTiming(timing);
33
147
  if (!extensionPayload) {
34
148
  // Not an extension user timing.
35
149
  continue;
@@ -37,8 +151,8 @@ export function extractExtensionEntries(timings) {
37
151
  const extensionSyntheticEntry = {
38
152
  name: timing.name,
39
153
  ph: "X" /* Types.Events.Phase.COMPLETE */,
40
- pid: Types.Events.ProcessID(0),
41
- tid: Types.Events.ThreadID(0),
154
+ pid: timing.pid,
155
+ tid: timing.tid,
42
156
  ts: timing.ts,
43
157
  dur: timing.dur,
44
158
  cat: 'devtools.extension',
@@ -54,12 +168,12 @@ export function extractExtensionEntries(timings) {
54
168
  if (Types.Extensions.isExtensionPayloadTrackEntry(extensionSyntheticEntry.args)) {
55
169
  const extensionTrackEntry = Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()
56
170
  .registerSyntheticEvent(extensionSyntheticEntry);
57
- extensionFlameChartEntries.push(extensionTrackEntry);
171
+ extensionTrackEntries.push(extensionTrackEntry);
58
172
  continue;
59
173
  }
60
174
  }
61
175
  }
62
- export function extensionDataInTiming(timing) {
176
+ export function extensionDataInPerformanceTiming(timing) {
63
177
  const timingDetail = Types.Events.isPerformanceMark(timing) ? timing.args.data?.detail : timing.args.data.beginEvent.args.detail;
64
178
  if (!timingDetail) {
65
179
  return null;
@@ -80,17 +194,53 @@ export function extensionDataInTiming(timing) {
80
194
  }
81
195
  return detailObj.devtools;
82
196
  }
83
- catch (e) {
197
+ catch {
84
198
  // No need to worry about this error, just discard this event and don't
85
199
  // treat it as having any useful information for the purposes of extensions
86
200
  return null;
87
201
  }
88
202
  }
203
+ /**
204
+ * Extracts extension data from a `console.timeStamp` event.
205
+ *
206
+ * Checks if a `console.timeStamp` event contains data intended for
207
+ * creating a custom track entry in the DevTools Performance panel. It
208
+ * specifically looks for a `track` argument within the event's data.
209
+ *
210
+ * If a `track` argument is present (and not an empty string), the
211
+ * function constructs an `ExtensionTrackEntryPayload` object containing
212
+ * the track name, an optional color, an optional track group. This
213
+ * payload is then used to create a `SyntheticExtensionTrackEntry`.
214
+ *
215
+ * **Note:** The `color` argument is optional and its type is validated
216
+ * against a predefined palette (see
217
+ * `ExtensionUI::extensionEntryColor`).
218
+ *
219
+ * @param timeStamp The `ConsoleTimeStamp` event to extract data from.
220
+ * @return An `ExtensionTrackEntryPayload` object if the event contains
221
+ * valid extension data for a track entry, or `null` otherwise.
222
+ */
223
+ export function extensionDataInConsoleTimeStamp(timeStamp) {
224
+ const trackName = timeStamp.args.data.track;
225
+ if (trackName === '' || trackName === undefined) {
226
+ return null;
227
+ }
228
+ return {
229
+ // the color is defaulted to primary if it's value isn't one from
230
+ // the defined palette (see ExtensionUI::extensionEntryColor) so
231
+ // we don't need to check the value is valid here.
232
+ color: String(timeStamp.args.data.color),
233
+ track: String(trackName),
234
+ dataType: 'track-entry',
235
+ trackGroup: timeStamp.args.data.trackGroup !== undefined ? String(timeStamp.args.data.trackGroup) : undefined
236
+ };
237
+ }
89
238
  export function data() {
90
239
  return {
91
240
  entryToNode,
92
- extensionTrackData: [...extensionTrackData],
93
- extensionMarkers: [...extensionMarkers],
241
+ extensionTrackData,
242
+ extensionMarkers,
243
+ syntheticConsoleEntriesForTimingsTrack,
94
244
  };
95
245
  }
96
246
  export function deps() {
@@ -1 +1 @@
1
- {"version":3,"file":"ExtensionTraceDataHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/ExtensionTraceDataHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 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 type {HandlerName} from './types.js';\nimport {data as userTimingsData} from './UserTimingsHandler.js';\n\nconst extensionFlameChartEntries: Types.Extensions.SyntheticExtensionTrackEntry[] = [];\nconst extensionTrackData: Types.Extensions.ExtensionTrackData[] = [];\nconst extensionMarkers: Types.Extensions.SyntheticExtensionMarker[] = [];\nconst entryToNode: Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode> = new Map();\n\nexport interface ExtensionTraceData {\n extensionTrackData: readonly Types.Extensions.ExtensionTrackData[];\n extensionMarkers: readonly Types.Extensions.SyntheticExtensionMarker[];\n entryToNode: Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode>;\n}\n\nexport function handleEvent(_event: Types.Events.Event): void {\n // Implementation not needed because data is sourced from UserTimingsHandler\n}\n\nexport function reset(): void {\n extensionFlameChartEntries.length = 0;\n extensionTrackData.length = 0;\n extensionMarkers.length = 0;\n entryToNode.clear();\n}\n\nexport async function finalize(): Promise<void> {\n createExtensionFlameChartEntries();\n}\n\nfunction createExtensionFlameChartEntries(): void {\n const pairedMeasures: readonly Types.Events.SyntheticUserTimingPair[] = userTimingsData().performanceMeasures;\n const marks: readonly Types.Events.PerformanceMark[] = userTimingsData().performanceMarks;\n const mergedRawExtensionEvents = Helpers.Trace.mergeEventsInOrder(pairedMeasures, marks);\n\n extractExtensionEntries(mergedRawExtensionEvents);\n Helpers.Extensions.buildTrackDataFromExtensionEntries(extensionFlameChartEntries, extensionTrackData, entryToNode);\n}\n\nexport function extractExtensionEntries(timings: (Types.Events.SyntheticUserTimingPair|Types.Events.PerformanceMark)[]):\n void {\n for (const timing of timings) {\n const extensionPayload = extensionDataInTiming(timing);\n if (!extensionPayload) {\n // Not an extension user timing.\n continue;\n }\n\n const extensionSyntheticEntry = {\n name: timing.name,\n ph: Types.Events.Phase.COMPLETE,\n pid: Types.Events.ProcessID(0),\n tid: Types.Events.ThreadID(0),\n ts: timing.ts,\n dur: timing.dur as Types.Timing.MicroSeconds,\n cat: 'devtools.extension',\n args: extensionPayload,\n rawSourceEvent: Types.Events.isSyntheticUserTiming(timing) ? timing.rawSourceEvent : timing,\n };\n\n if (Types.Extensions.isExtensionPayloadMarker(extensionPayload)) {\n const extensionMarker =\n Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()\n .registerSyntheticEvent<Types.Extensions.SyntheticExtensionMarker>(\n extensionSyntheticEntry as Omit<Types.Extensions.SyntheticExtensionMarker, '_tag'>);\n extensionMarkers.push(extensionMarker);\n continue;\n }\n\n if (Types.Extensions.isExtensionPayloadTrackEntry(extensionSyntheticEntry.args)) {\n const extensionTrackEntry =\n Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()\n .registerSyntheticEvent<Types.Extensions.SyntheticExtensionTrackEntry>(\n extensionSyntheticEntry as Omit<Types.Extensions.SyntheticExtensionTrackEntry, '_tag'>);\n extensionFlameChartEntries.push(extensionTrackEntry);\n continue;\n }\n }\n}\n\nexport function extensionDataInTiming(timing: Types.Events.SyntheticUserTimingPair|\n Types.Events.PerformanceMark): Types.Extensions.ExtensionDataPayload|null {\n const timingDetail =\n Types.Events.isPerformanceMark(timing) ? timing.args.data?.detail : timing.args.data.beginEvent.args.detail;\n if (!timingDetail) {\n return null;\n }\n try {\n // Attempt to parse the detail as an object that might be coming from a\n // DevTools Perf extension.\n // Wrapped in a try-catch because timingDetail might either:\n // 1. Not be `json.parse`-able (it should, but just in case...)\n // 2.Not be an object - in which case the `in` check will error.\n // If we hit either of these cases, we just ignore this mark and move on.\n const detailObj = JSON.parse(timingDetail);\n if (!('devtools' in detailObj)) {\n return null;\n }\n if (!Types.Extensions.isValidExtensionPayload(detailObj.devtools)) {\n return null;\n }\n return detailObj.devtools;\n } catch (e) {\n // No need to worry about this error, just discard this event and don't\n // treat it as having any useful information for the purposes of extensions\n return null;\n }\n}\n\nexport function data(): ExtensionTraceData {\n return {\n entryToNode,\n extensionTrackData: [...extensionTrackData],\n extensionMarkers: [...extensionMarkers],\n };\n}\n\nexport function deps(): HandlerName[] {\n return ['UserTimings'];\n}\n"]}
1
+ {"version":3,"file":"ExtensionTraceDataHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/ExtensionTraceDataHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 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 type {HandlerName} from './types.js';\nimport {data as userTimingsData} from './UserTimingsHandler.js';\n\nconst extensionTrackEntries: Types.Extensions.SyntheticExtensionTrackEntry[] = [];\nconst extensionTrackData: Types.Extensions.ExtensionTrackData[] = [];\nconst extensionMarkers: Types.Extensions.SyntheticExtensionMarker[] = [];\nconst entryToNode: Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode> = new Map();\nconst timeStampByName: Map<string, Types.Events.ConsoleTimeStamp> = new Map();\n\nconst syntheticConsoleEntriesForTimingsTrack: Types.Events.SyntheticConsoleTimeStamp[] = [];\n\nexport interface ExtensionTraceData {\n extensionTrackData: readonly Types.Extensions.ExtensionTrackData[];\n extensionMarkers: readonly Types.Extensions.SyntheticExtensionMarker[];\n entryToNode: Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode>;\n syntheticConsoleEntriesForTimingsTrack: Types.Events.SyntheticConsoleTimeStamp[];\n}\n\nexport function handleEvent(_event: Types.Events.Event): void {\n // Implementation not needed because data is sourced from UserTimingsHandler\n}\n\nexport function reset(): void {\n extensionTrackEntries.length = 0;\n syntheticConsoleEntriesForTimingsTrack.length = 0;\n extensionTrackData.length = 0;\n extensionMarkers.length = 0;\n entryToNode.clear();\n timeStampByName.clear();\n}\n\nexport async function finalize(): Promise<void> {\n createExtensionFlameChartEntries();\n}\n\nfunction createExtensionFlameChartEntries(): void {\n const pairedMeasures: readonly Types.Events.SyntheticUserTimingPair[] = userTimingsData().performanceMeasures;\n const marks: readonly Types.Events.PerformanceMark[] = userTimingsData().performanceMarks;\n const mergedRawExtensionEvents = Helpers.Trace.mergeEventsInOrder(pairedMeasures, marks);\n\n extractPerformanceAPIExtensionEntries(mergedRawExtensionEvents);\n extractConsoleAPIExtensionEntries();\n // extensionTrackEntries is filled by the above two calls.\n Helpers.Trace.sortTraceEventsInPlace(extensionTrackEntries);\n Helpers.Extensions.buildTrackDataFromExtensionEntries(extensionTrackEntries, extensionTrackData, entryToNode);\n}\n\n/**\n * Extracts extension entries from console.timeStamp events.\n *\n * Entries are built by pairing `console.timeStamp` events based on\n * their names. When a `console.timeStamp` event includes a `start`\n * argument (and optionally an `end` argument), it attempts to find\n * previously recorded `console.timeStamp` events with names matching\n * the `start` and `end` values. These matching events are then used to\n * determine the start and end times of the new entry.\n *\n * If a `console.timeStamp` event includes data for a custom track\n * (specified by the `track` argument), an extension track entry is\n * created and added to the `extensionTrackEntries` array. These entries\n * are used to visualize custom tracks in the Performance panel.\n *\n * If a `console.timeStamp` event includes data for a custom track\n * (specified by the `track` argument), an extension track entry is\n * created and added to the `extensionTrackEntries` array. These entries\n * are used to visualize custom tracks in the Performance panel.\n *\n * If a `console.timeStamp` event does not specify a custom track but\n * includes a start and/or end time (referencing other\n * `console.timeStamp` names), a synthetic console time stamp entry is\n * created and added to the `syntheticConsoleEntriesForTimingsTrack`\n * array. These entries are displayed in the \"Timings\" track.\n */\nexport function extractConsoleAPIExtensionEntries(): void {\n const consoleTimeStamps: readonly Types.Events.ConsoleTimeStamp[] = userTimingsData().timestampEvents;\n for (const currentTimeStamp of consoleTimeStamps) {\n const timeStampName = String(currentTimeStamp.args.data.name);\n timeStampByName.set(timeStampName, currentTimeStamp);\n const extensionData = extensionDataInConsoleTimeStamp(currentTimeStamp);\n const startName = currentTimeStamp.args.data.start;\n const endName = currentTimeStamp.args.data.end;\n if (!extensionData && !startName && !endName) {\n continue;\n }\n const startTimeStamp = startName ? timeStampByName.get(String(startName)) : undefined;\n const endTimeStamp = endName ? timeStampByName.get(String(endName)) : undefined;\n if (endTimeStamp && !startTimeStamp) {\n // Invalid data\n continue;\n }\n const entryStartTime = startTimeStamp?.ts ?? currentTimeStamp.ts;\n const entryEndTime = endTimeStamp?.ts ?? currentTimeStamp.ts;\n if (extensionData) {\n const unregisteredExtensionEntry: Omit<Types.Extensions.SyntheticExtensionTrackEntry, '_tag'> = {\n ...currentTimeStamp,\n name: timeStampName,\n cat: 'devtools.extension',\n args: extensionData,\n rawSourceEvent: currentTimeStamp,\n dur: Types.Timing.MicroSeconds(entryEndTime - entryStartTime),\n ts: entryStartTime,\n };\n const extensionEntry =\n Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()\n .registerSyntheticEvent<Types.Extensions.SyntheticExtensionTrackEntry>(unregisteredExtensionEntry);\n extensionTrackEntries.push(extensionEntry);\n continue;\n }\n // If no extension data is found in the entry (no custom track name\n // was passed), but the entry has a duration. we still save it here\n // to be added in the timings track. Note that timings w/o duration\n // and extension data are already handled by the UserTimingsHandler.\n const unregisteredSyntheticTimeStamp: Omit<Types.Events.SyntheticConsoleTimeStamp, '_tag'> = {\n ...currentTimeStamp,\n name: timeStampName,\n cat: 'disabled-by-default-v8.inspector',\n ph: Types.Events.Phase.COMPLETE,\n ts: entryStartTime,\n dur: Types.Timing.MicroSeconds(entryEndTime - entryStartTime),\n rawSourceEvent: currentTimeStamp\n };\n const syntheticTimeStamp =\n Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()\n .registerSyntheticEvent<Types.Events.SyntheticConsoleTimeStamp>(unregisteredSyntheticTimeStamp);\n syntheticConsoleEntriesForTimingsTrack.push(syntheticTimeStamp);\n }\n}\n\n/**\n * Extracts extension entries from Performance API events (marks and\n * measures).\n * It specifically looks for events that contain extension-specific data\n * within their `detail` property.\n *\n * If an event's `detail` property can be parsed as a JSON object and\n * contains a `devtools` field with a valid extension payload, a\n * synthetic extension entry is created. The type of extension entry\n * created depends on the payload:\n *\n * - If the payload conforms to `ExtensionPayloadMarker`, a\n * `SyntheticExtensionMarker` is created and added to the\n * `extensionMarkers` array. These markers represent single points in\n * time.\n * - If the payload conforms to `ExtensionPayloadTrackEntry`, a\n * `SyntheticExtensionTrackEntry` is created and added to the\n * `extensionTrackEntries` array. These entries represent events with\n * a duration and are displayed on custom tracks in the Performance\n * panel.\n *\n * **Note:** Only events with a `detail` property that contains valid\n * extension data are processed. Other `performance.mark` and\n * `performance.measure` events are ignored.\n *\n * @param timings An array of `SyntheticUserTimingPair` or\n * `PerformanceMark` events, typically obtained from the\n * `UserTimingsHandler`.\n */\nexport function extractPerformanceAPIExtensionEntries(\n timings: (Types.Events.SyntheticUserTimingPair|Types.Events.PerformanceMark)[]): void {\n for (const timing of timings) {\n const extensionPayload = extensionDataInPerformanceTiming(timing);\n if (!extensionPayload) {\n // Not an extension user timing.\n continue;\n }\n\n const extensionSyntheticEntry = {\n name: timing.name,\n ph: Types.Events.Phase.COMPLETE,\n pid: timing.pid,\n tid: timing.tid,\n ts: timing.ts,\n dur: timing.dur as Types.Timing.MicroSeconds,\n cat: 'devtools.extension',\n args: extensionPayload,\n rawSourceEvent: Types.Events.isSyntheticUserTiming(timing) ? timing.rawSourceEvent : timing,\n };\n\n if (Types.Extensions.isExtensionPayloadMarker(extensionPayload)) {\n const extensionMarker =\n Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()\n .registerSyntheticEvent<Types.Extensions.SyntheticExtensionMarker>(\n extensionSyntheticEntry as Omit<Types.Extensions.SyntheticExtensionMarker, '_tag'>);\n extensionMarkers.push(extensionMarker);\n continue;\n }\n\n if (Types.Extensions.isExtensionPayloadTrackEntry(extensionSyntheticEntry.args)) {\n const extensionTrackEntry =\n Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()\n .registerSyntheticEvent<Types.Extensions.SyntheticExtensionTrackEntry>(\n extensionSyntheticEntry as Omit<Types.Extensions.SyntheticExtensionTrackEntry, '_tag'>);\n extensionTrackEntries.push(extensionTrackEntry);\n continue;\n }\n }\n}\n\nexport function extensionDataInPerformanceTiming(timing: Types.Events.SyntheticUserTimingPair|\n Types.Events.PerformanceMark): Types.Extensions.ExtensionDataPayload|\n null {\n const timingDetail =\n Types.Events.isPerformanceMark(timing) ? timing.args.data?.detail : timing.args.data.beginEvent.args.detail;\n if (!timingDetail) {\n return null;\n }\n try {\n // Attempt to parse the detail as an object that might be coming from a\n // DevTools Perf extension.\n // Wrapped in a try-catch because timingDetail might either:\n // 1. Not be `json.parse`-able (it should, but just in case...)\n // 2.Not be an object - in which case the `in` check will error.\n // If we hit either of these cases, we just ignore this mark and move on.\n const detailObj = JSON.parse(timingDetail);\n if (!('devtools' in detailObj)) {\n return null;\n }\n if (!Types.Extensions.isValidExtensionPayload(detailObj.devtools)) {\n return null;\n }\n return detailObj.devtools;\n } catch {\n // No need to worry about this error, just discard this event and don't\n // treat it as having any useful information for the purposes of extensions\n return null;\n }\n}\n/**\n * Extracts extension data from a `console.timeStamp` event.\n *\n * Checks if a `console.timeStamp` event contains data intended for\n * creating a custom track entry in the DevTools Performance panel. It\n * specifically looks for a `track` argument within the event's data.\n *\n * If a `track` argument is present (and not an empty string), the\n * function constructs an `ExtensionTrackEntryPayload` object containing\n * the track name, an optional color, an optional track group. This\n * payload is then used to create a `SyntheticExtensionTrackEntry`.\n *\n * **Note:** The `color` argument is optional and its type is validated\n * against a predefined palette (see\n * `ExtensionUI::extensionEntryColor`).\n *\n * @param timeStamp The `ConsoleTimeStamp` event to extract data from.\n * @return An `ExtensionTrackEntryPayload` object if the event contains\n * valid extension data for a track entry, or `null` otherwise.\n */\nexport function extensionDataInConsoleTimeStamp(timeStamp: Types.Events.ConsoleTimeStamp):\n Types.Extensions.ExtensionTrackEntryPayload|null {\n const trackName = timeStamp.args.data.track;\n if (trackName === '' || trackName === undefined) {\n return null;\n }\n return {\n // the color is defaulted to primary if it's value isn't one from\n // the defined palette (see ExtensionUI::extensionEntryColor) so\n // we don't need to check the value is valid here.\n color: String(timeStamp.args.data.color) as Types.Extensions.ExtensionTrackEntryPayload['color'],\n track: String(trackName),\n dataType: 'track-entry',\n trackGroup: timeStamp.args.data.trackGroup !== undefined ? String(timeStamp.args.data.trackGroup) : undefined\n };\n}\n\nexport function data(): ExtensionTraceData {\n return {\n entryToNode,\n extensionTrackData,\n extensionMarkers,\n syntheticConsoleEntriesForTimingsTrack,\n };\n}\n\nexport function deps(): HandlerName[] {\n return ['UserTimings'];\n}\n"]}