@paulirish/trace_engine 0.0.31 → 0.0.33

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 (283) hide show
  1. package/README.md +6 -10
  2. package/analyze-trace.mjs +9 -10
  3. package/core/platform/ArrayUtilities.js +1 -0
  4. package/core/platform/ArrayUtilities.js.map +1 -1
  5. package/core/platform/DevToolsPath.d.ts +1 -1
  6. package/core/platform/DevToolsPath.js.map +1 -1
  7. package/core/platform/MimeType.js +4 -2
  8. package/core/platform/MimeType.js.map +1 -1
  9. package/core/platform/NumberUtilities.js +8 -0
  10. package/core/platform/NumberUtilities.js.map +1 -1
  11. package/core/platform/ServerTiming.d.ts +31 -0
  12. package/core/platform/ServerTiming.js +212 -0
  13. package/core/platform/ServerTiming.js.map +1 -0
  14. package/core/platform/Timing.d.ts +1 -1
  15. package/core/platform/Timing.js.map +1 -1
  16. package/core/platform/TypescriptUtilities.d.ts +3 -0
  17. package/core/platform/TypescriptUtilities.js.map +1 -1
  18. package/core/platform/UIString.d.ts +1 -1
  19. package/core/platform/UIString.js.map +1 -1
  20. package/core/platform/UserVisibleError.d.ts +1 -1
  21. package/core/platform/UserVisibleError.js.map +1 -1
  22. package/core/platform/platform-tsconfig.json +1 -1
  23. package/core/platform/platform.d.ts +2 -2
  24. package/core/platform/platform.js +2 -2
  25. package/core/platform/platform.js.map +1 -1
  26. package/generated/protocol.d.ts +258 -14
  27. package/models/trace/LanternComputationData.d.ts +4 -4
  28. package/models/trace/LanternComputationData.js +22 -23
  29. package/models/trace/LanternComputationData.js.map +1 -1
  30. package/models/trace/ModelImpl.d.ts +11 -12
  31. package/models/trace/ModelImpl.js +22 -33
  32. package/models/trace/ModelImpl.js.map +1 -1
  33. package/models/trace/Processor.d.ts +21 -12
  34. package/models/trace/Processor.js +148 -67
  35. package/models/trace/Processor.js.map +1 -1
  36. package/models/trace/TracingManager.js.map +1 -1
  37. package/models/trace/extras/FetchNodes.d.ts +8 -8
  38. package/models/trace/extras/FetchNodes.js +16 -11
  39. package/models/trace/extras/FetchNodes.js.map +1 -1
  40. package/models/trace/extras/FilmStrip.d.ts +2 -2
  41. package/models/trace/extras/FilmStrip.js +8 -8
  42. package/models/trace/extras/FilmStrip.js.map +1 -1
  43. package/models/trace/extras/MainThreadActivity.d.ts +1 -1
  44. package/models/trace/extras/MainThreadActivity.js +1 -1
  45. package/models/trace/extras/MainThreadActivity.js.map +1 -1
  46. package/models/trace/extras/Metadata.js +2 -2
  47. package/models/trace/extras/Metadata.js.map +1 -1
  48. package/models/trace/extras/URLForEntry.d.ts +9 -1
  49. package/models/trace/extras/URLForEntry.js +18 -10
  50. package/models/trace/extras/URLForEntry.js.map +1 -1
  51. package/models/trace/extras/extras.js +1 -1
  52. package/models/trace/handlers/AnimationHandler.d.ts +2 -2
  53. package/models/trace/handlers/AnimationHandler.js +1 -1
  54. package/models/trace/handlers/AnimationHandler.js.map +1 -1
  55. package/models/trace/handlers/AuctionWorkletsHandler.d.ts +2 -2
  56. package/models/trace/handlers/AuctionWorkletsHandler.js +11 -11
  57. package/models/trace/handlers/AuctionWorkletsHandler.js.map +1 -1
  58. package/models/trace/handlers/ExtensionTraceDataHandler.d.ts +7 -5
  59. package/models/trace/handlers/ExtensionTraceDataHandler.js +16 -10
  60. package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
  61. package/models/trace/handlers/FramesHandler.d.ts +24 -19
  62. package/models/trace/handlers/FramesHandler.js +46 -25
  63. package/models/trace/handlers/FramesHandler.js.map +1 -1
  64. package/models/trace/handlers/GPUHandler.d.ts +4 -4
  65. package/models/trace/handlers/GPUHandler.js +3 -3
  66. package/models/trace/handlers/GPUHandler.js.map +1 -1
  67. package/models/trace/handlers/ImagePaintingHandler.d.ts +3 -3
  68. package/models/trace/handlers/ImagePaintingHandler.js +6 -8
  69. package/models/trace/handlers/ImagePaintingHandler.js.map +1 -1
  70. package/models/trace/handlers/InitiatorsHandler.d.ts +3 -3
  71. package/models/trace/handlers/InitiatorsHandler.js +14 -14
  72. package/models/trace/handlers/InitiatorsHandler.js.map +1 -1
  73. package/models/trace/handlers/InvalidationsHandler.d.ts +4 -2
  74. package/models/trace/handlers/InvalidationsHandler.js +29 -11
  75. package/models/trace/handlers/InvalidationsHandler.js.map +1 -1
  76. package/models/trace/handlers/LargestImagePaintHandler.d.ts +2 -2
  77. package/models/trace/handlers/LargestImagePaintHandler.js +1 -1
  78. package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
  79. package/models/trace/handlers/LargestTextPaintHandler.d.ts +2 -2
  80. package/models/trace/handlers/LargestTextPaintHandler.js +1 -1
  81. package/models/trace/handlers/LargestTextPaintHandler.js.map +1 -1
  82. package/models/trace/handlers/LayerTreeHandler.d.ts +6 -6
  83. package/models/trace/handlers/LayerTreeHandler.js +6 -6
  84. package/models/trace/handlers/LayerTreeHandler.js.map +1 -1
  85. package/models/trace/handlers/LayoutShiftsHandler.d.ts +12 -20
  86. package/models/trace/handlers/LayoutShiftsHandler.js +73 -12
  87. package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
  88. package/models/trace/handlers/MemoryHandler.d.ts +2 -2
  89. package/models/trace/handlers/MemoryHandler.js +1 -1
  90. package/models/trace/handlers/MemoryHandler.js.map +1 -1
  91. package/models/trace/handlers/MetaHandler.d.ts +15 -14
  92. package/models/trace/handlers/MetaHandler.js +32 -30
  93. package/models/trace/handlers/MetaHandler.js.map +1 -1
  94. package/models/trace/handlers/ModelHandlers.d.ts +1 -1
  95. package/models/trace/handlers/ModelHandlers.js +1 -1
  96. package/models/trace/handlers/ModelHandlers.js.map +1 -1
  97. package/models/trace/handlers/NetworkRequestsHandler.d.ts +13 -12
  98. package/models/trace/handlers/NetworkRequestsHandler.js +68 -66
  99. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  100. package/models/trace/handlers/PageFramesHandler.d.ts +2 -2
  101. package/models/trace/handlers/PageFramesHandler.js +2 -2
  102. package/models/trace/handlers/PageFramesHandler.js.map +1 -1
  103. package/models/trace/handlers/PageLoadMetricsHandler.d.ts +7 -7
  104. package/models/trace/handlers/PageLoadMetricsHandler.js +21 -24
  105. package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
  106. package/models/trace/handlers/RendererHandler.d.ts +19 -19
  107. package/models/trace/handlers/RendererHandler.js +5 -5
  108. package/models/trace/handlers/RendererHandler.js.map +1 -1
  109. package/models/trace/handlers/SamplesHandler.d.ts +6 -6
  110. package/models/trace/handlers/SamplesHandler.js +4 -4
  111. package/models/trace/handlers/SamplesHandler.js.map +1 -1
  112. package/models/trace/handlers/ScreenshotsHandler.d.ts +6 -4
  113. package/models/trace/handlers/ScreenshotsHandler.js +11 -9
  114. package/models/trace/handlers/ScreenshotsHandler.js.map +1 -1
  115. package/models/trace/handlers/SelectorStatsHandler.d.ts +3 -3
  116. package/models/trace/handlers/SelectorStatsHandler.js +2 -2
  117. package/models/trace/handlers/SelectorStatsHandler.js.map +1 -1
  118. package/models/trace/handlers/ServerTimingsHandler.d.ts +10 -0
  119. package/models/trace/handlers/ServerTimingsHandler.js +118 -0
  120. package/models/trace/handlers/ServerTimingsHandler.js.map +1 -0
  121. package/models/trace/handlers/Threads.d.ts +7 -7
  122. package/models/trace/handlers/Threads.js +5 -5
  123. package/models/trace/handlers/Threads.js.map +1 -1
  124. package/models/trace/handlers/UserInteractionsHandler.d.ts +13 -11
  125. package/models/trace/handlers/UserInteractionsHandler.js +13 -7
  126. package/models/trace/handlers/UserInteractionsHandler.js.map +1 -1
  127. package/models/trace/handlers/UserTimingsHandler.d.ts +5 -5
  128. package/models/trace/handlers/UserTimingsHandler.js +52 -9
  129. package/models/trace/handlers/UserTimingsHandler.js.map +1 -1
  130. package/models/trace/handlers/WarningsHandler.d.ts +5 -5
  131. package/models/trace/handlers/WarningsHandler.js +4 -5
  132. package/models/trace/handlers/WarningsHandler.js.map +1 -1
  133. package/models/trace/handlers/WorkersHandler.d.ts +4 -4
  134. package/models/trace/handlers/WorkersHandler.js +1 -1
  135. package/models/trace/handlers/WorkersHandler.js.map +1 -1
  136. package/models/trace/handlers/handlers-tsconfig.json +1 -1
  137. package/models/trace/handlers/types.d.ts +7 -7
  138. package/models/trace/handlers/types.js.map +1 -1
  139. package/models/trace/helpers/Extensions.d.ts +5 -1
  140. package/models/trace/helpers/Extensions.js +5 -3
  141. package/models/trace/helpers/Extensions.js.map +1 -1
  142. package/models/trace/helpers/Network.d.ts +2 -2
  143. package/models/trace/helpers/Network.js +19 -2
  144. package/models/trace/helpers/Network.js.map +1 -1
  145. package/models/trace/helpers/SamplesIntegrator.d.ts +5 -5
  146. package/models/trace/helpers/SamplesIntegrator.js +10 -11
  147. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  148. package/models/trace/helpers/SyntheticEvents.d.ts +8 -14
  149. package/models/trace/helpers/SyntheticEvents.js +20 -31
  150. package/models/trace/helpers/SyntheticEvents.js.map +1 -1
  151. package/models/trace/helpers/Timing.d.ts +16 -5
  152. package/models/trace/helpers/Timing.js +33 -7
  153. package/models/trace/helpers/Timing.js.map +1 -1
  154. package/models/trace/helpers/Trace.d.ts +46 -33
  155. package/models/trace/helpers/Trace.js +53 -38
  156. package/models/trace/helpers/Trace.js.map +1 -1
  157. package/models/trace/helpers/TreeHelpers.d.ts +30 -8
  158. package/models/trace/helpers/TreeHelpers.js +91 -23
  159. package/models/trace/helpers/TreeHelpers.js.map +1 -1
  160. package/models/trace/insights/Common.d.ts +8 -2
  161. package/models/trace/insights/Common.js +33 -7
  162. package/models/trace/insights/Common.js.map +1 -1
  163. package/models/trace/insights/CumulativeLayoutShift.d.ts +34 -13
  164. package/models/trace/insights/CumulativeLayoutShift.js +151 -59
  165. package/models/trace/insights/CumulativeLayoutShift.js.map +1 -1
  166. package/models/trace/insights/DocumentLatency.d.ts +9 -4
  167. package/models/trace/insights/DocumentLatency.js +82 -7
  168. package/models/trace/insights/DocumentLatency.js.map +1 -1
  169. package/models/trace/insights/FontDisplay.d.ts +11 -0
  170. package/models/trace/insights/FontDisplay.js +44 -0
  171. package/models/trace/insights/FontDisplay.js.map +1 -0
  172. package/models/trace/insights/InsightRunners.d.ts +3 -0
  173. package/models/trace/insights/InsightRunners.js +3 -0
  174. package/models/trace/insights/InsightRunners.js.map +1 -1
  175. package/models/trace/insights/InteractionToNextPaint.d.ts +4 -5
  176. package/models/trace/insights/InteractionToNextPaint.js +5 -3
  177. package/models/trace/insights/InteractionToNextPaint.js.map +1 -1
  178. package/models/trace/insights/LargestContentfulPaint.d.ts +20 -7
  179. package/models/trace/insights/LargestContentfulPaint.js +57 -37
  180. package/models/trace/insights/LargestContentfulPaint.js.map +1 -1
  181. package/models/trace/insights/RenderBlocking.d.ts +3 -3
  182. package/models/trace/insights/RenderBlocking.js +29 -24
  183. package/models/trace/insights/RenderBlocking.js.map +1 -1
  184. package/models/trace/insights/SlowCSSSelector.d.ts +11 -0
  185. package/models/trace/insights/SlowCSSSelector.js +67 -0
  186. package/models/trace/insights/SlowCSSSelector.js.map +1 -0
  187. package/models/trace/insights/ThirdPartyWeb.d.ts +18 -0
  188. package/models/trace/insights/ThirdPartyWeb.js +174 -0
  189. package/models/trace/insights/ThirdPartyWeb.js.map +1 -0
  190. package/models/trace/insights/Viewport.d.ts +5 -2
  191. package/models/trace/insights/Viewport.js +14 -9
  192. package/models/trace/insights/Viewport.js.map +1 -1
  193. package/models/trace/insights/insights-tsconfig.json +9 -0
  194. package/models/trace/insights/insights.d.ts +1 -0
  195. package/models/trace/insights/insights.js +1 -0
  196. package/models/trace/insights/insights.js.map +1 -1
  197. package/models/trace/insights/types.d.ts +43 -25
  198. package/models/trace/insights/types.js.map +1 -1
  199. package/models/trace/lantern/core/NetworkAnalyzer.d.ts +6 -6
  200. package/models/trace/lantern/core/NetworkAnalyzer.js +12 -12
  201. package/models/trace/lantern/core/NetworkAnalyzer.js.map +1 -1
  202. package/models/trace/lantern/graph/BaseNode.d.ts +4 -4
  203. package/models/trace/lantern/graph/BaseNode.js +21 -21
  204. package/models/trace/lantern/graph/BaseNode.js.map +1 -1
  205. package/models/trace/lantern/graph/CPUNode.d.ts +1 -1
  206. package/models/trace/lantern/graph/CPUNode.js +5 -5
  207. package/models/trace/lantern/graph/CPUNode.js.map +1 -1
  208. package/models/trace/lantern/graph/PageDependencyGraph.d.ts +4 -4
  209. package/models/trace/lantern/graph/PageDependencyGraph.js +5 -5
  210. package/models/trace/lantern/graph/PageDependencyGraph.js.map +1 -1
  211. package/models/trace/lantern/simulation/ConnectionPool.d.ts +7 -7
  212. package/models/trace/lantern/simulation/ConnectionPool.js +26 -26
  213. package/models/trace/lantern/simulation/ConnectionPool.js.map +1 -1
  214. package/models/trace/lantern/simulation/DNSCache.d.ts +3 -3
  215. package/models/trace/lantern/simulation/DNSCache.js +11 -11
  216. package/models/trace/lantern/simulation/DNSCache.js.map +1 -1
  217. package/models/trace/lantern/simulation/SimulationTimingMap.d.ts +1 -1
  218. package/models/trace/lantern/simulation/SimulationTimingMap.js +15 -15
  219. package/models/trace/lantern/simulation/SimulationTimingMap.js.map +1 -1
  220. package/models/trace/lantern/simulation/Simulator.d.ts +28 -28
  221. package/models/trace/lantern/simulation/Simulator.js +113 -113
  222. package/models/trace/lantern/simulation/Simulator.js.map +1 -1
  223. package/models/trace/lantern/simulation/TCPConnection.d.ts +9 -9
  224. package/models/trace/lantern/simulation/TCPConnection.js +36 -36
  225. package/models/trace/lantern/simulation/TCPConnection.js.map +1 -1
  226. package/models/trace/root-causes/LayoutShift.d.ts +13 -13
  227. package/models/trace/root-causes/LayoutShift.js +7 -25
  228. package/models/trace/root-causes/LayoutShift.js.map +1 -1
  229. package/models/trace/types/Configuration.d.ts +16 -0
  230. package/models/trace/types/Configuration.js +1 -0
  231. package/models/trace/types/Configuration.js.map +1 -1
  232. package/models/trace/types/Extensions.d.ts +9 -12
  233. package/models/trace/types/Extensions.js +2 -1
  234. package/models/trace/types/Extensions.js.map +1 -1
  235. package/models/trace/types/File.d.ts +68 -25
  236. package/models/trace/types/File.js +15 -3
  237. package/models/trace/types/File.js.map +1 -1
  238. package/models/trace/types/TraceEvents.d.ts +819 -730
  239. package/models/trace/types/TraceEvents.js +270 -280
  240. package/models/trace/types/TraceEvents.js.map +1 -1
  241. package/models/trace/types/types.d.ts +1 -1
  242. package/models/trace/types/types.js +1 -1
  243. package/models/trace/types/types.js.map +1 -1
  244. package/package.json +4 -2
  245. package/test/test-trace-engine.mjs +47 -2
  246. package/third_party/third-party-web/third-party-web.js +1 -0
  247. package/core/platform/PromiseUtilities.d.ts +0 -10
  248. package/core/platform/PromiseUtilities.js +0 -18
  249. package/core/platform/PromiseUtilities.js.map +0 -1
  250. package/core/platform/SetUtilities.d.ts +0 -2
  251. package/core/platform/SetUtilities.js +0 -23
  252. package/core/platform/SetUtilities.js.map +0 -1
  253. package/models/trace/EntriesFilter.d.ts +0 -72
  254. package/models/trace/EntriesFilter.js +0 -296
  255. package/models/trace/EntriesFilter.js.map +0 -1
  256. package/models/trace/LegacyTracingModel.js.map +0 -1
  257. package/models/trace/handlers/EnhancedTracesHandler.d.ts +0 -48
  258. package/models/trace/handlers/EnhancedTracesHandler.js +0 -165
  259. package/models/trace/handlers/EnhancedTracesHandler.js.map +0 -1
  260. package/models/trace/lantern/BaseNode.d.ts +0 -91
  261. package/models/trace/lantern/BaseNode.js +0 -268
  262. package/models/trace/lantern/BaseNode.js.map +0 -1
  263. package/models/trace/lantern/CPUNode.d.ts +0 -24
  264. package/models/trace/lantern/CPUNode.js +0 -64
  265. package/models/trace/lantern/CPUNode.js.map +0 -1
  266. package/models/trace/lantern/LanternError.d.ts +0 -3
  267. package/models/trace/lantern/LanternError.js +0 -7
  268. package/models/trace/lantern/LanternError.js.map +0 -1
  269. package/models/trace/lantern/MetricsModule.d.ts +0 -11
  270. package/models/trace/lantern/MetricsModule.js +0 -14
  271. package/models/trace/lantern/MetricsModule.js.map +0 -1
  272. package/models/trace/lantern/NetworkNode.d.ts +0 -22
  273. package/models/trace/lantern/NetworkNode.js +0 -83
  274. package/models/trace/lantern/NetworkNode.js.map +0 -1
  275. package/models/trace/lantern/PageDependencyGraph.d.ts +0 -43
  276. package/models/trace/lantern/PageDependencyGraph.js +0 -509
  277. package/models/trace/lantern/PageDependencyGraph.js.map +0 -1
  278. package/models/trace/lantern/SimulationModule.d.ts +0 -17
  279. package/models/trace/lantern/SimulationModule.js +0 -13
  280. package/models/trace/lantern/SimulationModule.js.map +0 -1
  281. package/models/trace/lantern/simulation/NetworkAnalyzer.d.ts +0 -112
  282. package/models/trace/lantern/simulation/NetworkAnalyzer.js +0 -486
  283. package/models/trace/lantern/simulation/NetworkAnalyzer.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Trace.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/helpers/Trace.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,QAAQ,MAAM,oCAAoC,CAAC;AAG/D,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAC,sBAAsB,EAAC,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAC,wBAAwB,EAAC,MAAM,aAAa,CAAC;AASrD;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,KAAuC;IACjE,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;IACpC,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,CAAC,4BAA4B,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,IAAI,IAAI,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,kBAA0B;IAC/D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACxC,IAAI,GAAG,EAAE,CAAC;QACR,0EAA0E;QAC1E,kEAAkE;QAClE,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAGD,qFAAqF;AACrF,qEAAqE;AACrE,MAAM,UAAU,uBAAuB,CACnC,KAAQ,EACR,qBAA0E;IAE5E,MAAM,EAAC,GAAG,EAAE,GAAG,EAAC,GAAG,KAAK,CAAC;IACzB,IAAI,cAAc,GAAG,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,cAAc,GAAG,IAAI,GAAG,EAAmC,CAAC;IAC9D,CAAC;IAED,IAAI,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,EAAE,CAAC;IACd,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnB,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACtC,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AACvD,CAAC;AAMD,MAAM,UAAU,mBAAmB,CAAC,CAAW,EAAE,CAAW;IAC1D,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC;IACxB,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC;IACxB,IAAI,UAAU,GAAG,UAAU,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAC,CAAC;IACZ,CAAC;IACD,IAAI,UAAU,GAAG,UAAU,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7B,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7B,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IACxC,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IACxC,IAAI,QAAQ,GAAG,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,CAAC,CAAC;IACZ,CAAC;IACD,IAAI,QAAQ,GAAG,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AACD;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAA0E;IAE/G,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UACN,kBAAkB,CACd,YAA2B,EAAE,YAA2B;IAC1D,MAAM,MAAM,GAAG,EAAE,CAAC;IAClB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,YAAY,CAAC,MAAM,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzD,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpB,CAAC,EAAE,CAAC;QACN,CAAC;QACD,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpB,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,0BAA0B,CACtC,KAAuC,EACvC,YAAoB,EACpB,oBAAgF;IAElF,MAAM,WAAW,GAAG,oBAAoB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC3D,IAAI,CAAC,WAAW,IAAI,YAAY,KAAK,EAAE,EAAE,CAAC;QACxC,qFAAqF;QACrF,gCAAgC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,oBAAoB,GACtB,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC;IAEtG,IAAI,oBAAoB,KAAK,IAAI,EAAE,CAAC;QAClC,sFAAsF;QACtF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,WAAW,CAAC,oBAAoB,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAC0D;IAClF,OAAO,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,GAAG,EAAE,MAAM,IAAI,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,uBAAuB,CACnC,OAAe,EAAE,IAA+B,EAChD,wBAGmG;IACrG,MAAM,WAAW,GAAG,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,MAAM,SAAS,IAAI,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;QAC7C,KAAK,MAAM,WAAW,IAAI,SAAS,EAAE,CAAC;YACpC,IAAI,WAAW,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC;gBACnE,SAAS;YACX,CAAC;YACD,OAAO,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC3B,IAA6C,EAAE,SAAsC,EAAE,WAAmB,EAC1G,EAA6B,EAAE,GAAgC,EAC/D,GAA+B;IACjC,OAAO;QACL,GAAG,EAAE,EAAE;QACP,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,IAAI,EAAE,EAAE;QACR,EAAE,4CAAkC;QACpC,GAAG;QACH,GAAG;QACH,EAAE;QACF,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;QACjC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;QACtC,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,WAAW;QACX,SAAS;KACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACnC,IAAY,EAAE,EAA6B,EAAE,GAAgC,EAC7E,GAA+B;IACjC,OAAO;QACL,GAAG,EAAE,EAAE;QACP,IAAI;QACJ,IAAI,EAAE,EAAE;QACR,EAAE,4CAAkC;QACpC,GAAG;QACH,GAAG;QACH,EAAE;QACF,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;QACjC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;KACvC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,cAA2D;IAErF,0CAA0C;IAC1C,MAAM,YAAY,GAA6C,IAAI,GAAG,EAAE,CAAC;IAEzE,4BAA4B;IAC5B,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,iEAAiE;QACjE,iEAAiE;QACjE,6CAA6C;QAC7C,MAAM,iBAAiB,GAAG,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,EAAE;YAC7F,OAAO,EAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,KAAK,CAAC,EAAE,2DAAiD,CAAC;QAC/E,MAAM,UAAU,GAAG,KAAK,CAAC,EAAE,yDAA+C,CAAC;QAC3E,MAAM,cAAc,GAAG,KAAK,CAAC,EAAE,6DAAmD,CAAC;QAEnF,IAAI,YAAY,EAAE,CAAC;YACjB,iBAAiB,CAAC,KAAK,GAAG,KAAuD,CAAC;QACpF,CAAC;aAAM,IAAI,UAAU,EAAE,CAAC;YACtB,iBAAiB,CAAC,GAAG,GAAG,KAAqD,CAAC;QAChF,CAAC;aAAM,IAAI,cAAc,EAAE,CAAC;YAC1B,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,CAAC;gBAC/B,iBAAiB,CAAC,OAAO,GAAG,EAAE,CAAC;YACjC,CAAC;YACD,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAyD,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,cAAc,CAAC,KAAgD;IACtE,MAAM,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5B,OAAO,EAAE,IAAI,GAAG,KAAK,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,2BAA2B,CACvC,YAIE,EACF,sBAAqE;IAEvE,MAAM,eAAe,GAAyB,EAAE,CAAC;IACjD,KAAK,MAAM,CAAC,EAAE,EAAE,aAAa,CAAC,IAAI,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC;QACzD,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,CAAC;QACvC,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC;QACnC,MAAM,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC;QAC5C,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,QAAQ,IAAI,aAAa,CAAC,EAAE,CAAC;YAChD,wEAAwE;YACxE,+FAA+F;YAC/F,gFAAgF;YAChF,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GAAG,EAAC,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAC,CAAC;QACtD;;;;WAIG;QACH,SAAS,iBAAiB,CAAC,IAI1B;YACC,MAAM,kBAAkB,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YAC/G,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACnF,OAAO,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,kBAAkB,IAAI,aAAa,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,SAAS;QACX,CAAC;QACD,MAAM,WAAW,GAAG,QAAQ,IAAI,UAAU,CAAC;QAE3C,MAAM,KAAK,GAAG,sBAAsB,CAAC,2BAA2B,CAAqB;YACnF,cAAc,EAAE,UAAU;YAC1B,GAAG,EAAE,WAAW,CAAC,GAAG;YACpB,EAAE,EAAE,WAAW,CAAC,EAAE;YAClB,GAAG,EAAE,WAAW,CAAC,GAAG;YACpB,GAAG,EAAE,WAAW,CAAC,GAAG;YACpB,EAAE;YACF,wEAAwE;YACxE,yBAAyB;YACzB,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC;YAC9D,EAAE,EAAE,UAAU,CAAC,EAAE;YACjB,IAAI,EAAE;gBACJ,IAAI,EAAE,OAAO;aACd;SACF,CAAC,CAAC;QAEH,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;YAClB,kEAAkE;YAClE,2EAA2E;YAC3E,oEAAoE;YACpE,oBAAoB;YACpB,SAAS;QACX,CAAC;QACD,sBAAsB,EAAE,CAAC,KAAK,CAAC,CAAC;QAChC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,kCAAkC,CAC9C,mBAAwB,EACxB,sBAAqE;IACvE,MAAM,YAAY,GAAG,WAAW,CAAC,mBAAmB,CAAC,CAAC;IACtD,MAAM,eAAe,GAAG,2BAA2B,CAAI,YAAY,EAAE,sBAAsB,CAAC,CAAC;IAC7F,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mCAAmC,CAAC,KAAuC;IAIzF,6EAA6E;IAC7E,2EAA2E;IAC3E,kEAAkE;IAClE,2EAA2E;IAC3E,SAAS;IACT,MAAM,OAAO,GAAG,kCAAkC,CAAC,KAAK,CAAC,CAAC;IAC1D,MAAM,EAAC,UAAU,EAAE,YAAY,EAAC,GAAG,OAAO,CAAC;IAE3C,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,uEAAuE;QACvE,mCAAmC;QACnC,wEAAmD;QACnD,4EAAqD;QACrD,iEAA8C;QAC9C,yEAAiD,CAAC,CAAC,CAAC;YAClD,OAAO;gBACL,UAAU,EAAE,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;gBACvE,YAAY,EAAE,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;aAC9E,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,CAAC,CAAC;YACR,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gCAAgC,CAAC,KAAuC;IAEtF,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;QAC3B,MAAM,mBAAmB,GAAG,EAAC,GAAG,SAAS,EAAC,CAAC;QAC3C,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,oGAAiE;YACjE,gFAAuD;YACvD,+EAAsD,CAAC,CAAC,CAAC;gBACvD,mBAAmB,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,IAAI,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;gBAClF,mBAAmB,CAAC,YAAY,GAAG,SAAS,CAAC,YAAY,IAAI,SAAS,CAAC,YAAY,GAAG,CAAC,CAAC;YAC1F,CAAC;QACH,CAAC;QACD,OAAO,mBAAmB,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;IAQI;AACJ,SAAS,kCAAkC,CAAC,KAAuC;IAIjF,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;QACtB,OAAO;YACL,UAAU,EAAE,SAAS;YACrB,YAAY,EAAE,SAAS;SACxB,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,GAAqB,SAAS,CAAC;IAC7C,IAAI,YAAY,GAAqB,SAAS,CAAC;IAC/C,IAAI,YAAY,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QACtF,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;IAC1C,CAAC;IACD,IAAI,cAAc,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC1F,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC;IAC9C,CAAC;IAED,OAAO,EAAC,UAAU,EAAE,YAAY,EAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAuC;IACrE,6EAA6E;IAC7E,qCAAqC;IACrC,4EAA4E;IAC5E,6DAA6D;IAC7D,yEAAyE;IACzE,uCAAuC;IACvC,IAAI,KAAK,CAAC,IAAI,IAAI,WAAW,IAAI,KAAK,CAAC,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,QAAQ;QACnF,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS;QAChE,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACnD,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;IACpC,CAAC;IACD,gDAAgD;IAChD,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IAC/B,CAAC;IAED,iCAAiC;IACjC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,6BAA6B,GAAG,uCAAuC,CAAC;AAC9E,MAAM,UAAU,eAAe,CAAC,KAAuC;IACrE,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;QACxD,wEAAwE;QACxE,yEAAyE;QACzE,kDAAkD;QAClD,8CAA8C;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,6BAA6B,CAAC,IAAI,KAAK,CAAC,IAAI,6DAA6C,CAAC;AACtH,CAAC;AAED,SAAS,6BAA6B,CAClC,MAA0C,EAAE,IAA+B;IAC7E,IAAI,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACnG,OAAO,KAAK,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACpD,KAAK,EAAE,CAAC;IACV,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC5B,CAAC;AACD,MAAM,UAAU,0BAA0B,CACtC,MAA0C,EAAE,SAAoC,EAChF,OAAmC;IACrC,MAAM,WAAW,GAAmD,EAAE,CAAC;IACvE,MAAM,eAAe,GAAG,6BAA6B,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzE,KAAK,IAAI,CAAC,GAAG,eAAe,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,4BAA4B,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,SAAS;QACX,CAAC;QACD,IAAI,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,EAAE,CAAC;YACtC,SAAS;QACX,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAaD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,YAAY,CACxB,MAA0C,EAC1C,MAA0B;IAE5B,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC5E,MAAM,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAE5E,MAAM,KAAK,GAAuC,EAAE,CAAC;IACrD,MAAM,eAAe,GAAG,6BAA6B,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC/E,KAAK,IAAI,CAAC,GAAG,eAAe,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrD,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,mBAAmB,GAAG,wBAAwB,CAAC,YAAY,CAAC,CAAC;QACnE,IAAI,mBAAmB,CAAC,OAAO,GAAG,eAAe,EAAE,CAAC;YAClD,SAAS;QACX,CAAC;QACD,IAAI,mBAAmB,CAAC,SAAS,GAAG,aAAa,EAAE,CAAC;YAClD,MAAM;QACR,CAAC;QAED,MAAM,mBAAmB,GAAG,iBAAiB,IAAI,KAAK,CAAC,WAAW,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACjG,IAAI,mBAAmB,IAAI,KAAK,CAAC,WAAW,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,CAAC;YAC1E,SAAS;QACX,CAAC;QAED,2EAA2E;QAC3E,qEAAqE;QACrE,IAAI,gBAAgB,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QACpG,OAAO,gBAAgB,IAAI,gBAAgB,IAAI,gBAAgB,IAAI,mBAAmB,CAAC,SAAS,EAAE,CAAC;YACjG,KAAK,CAAC,GAAG,EAAE,CAAC;YACZ,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACpC,gBAAgB,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAChC,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QAClG,CAAC;QAED,8FAA8F;QAC9F,IAAI,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAC5D,8EAA8E;YAC9E,SAAS;QACX,CAAC;QAED,IAAI,mBAAmB,CAAC,QAAQ,EAAE,CAAC;YACjC,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;YACjC,gDAAgD;YAChD,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,8CAA8C;IAC9C,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;AACH,CAAC;AAED,8DAA8D;AAC9D,gDAAgD;AAChD,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAuB,CAAC;AACxD,MAAM,UAAU,gBAAgB,CAAC,KAAuC,EAAE,QAAgB;IACxF,IAAI,wBAAwB,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/D,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAC9B,wBAAwB,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAkD;IAE3F,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;AACxC,CAAC","sourcesContent":["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\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 {SyntheticEventsManager} from './SyntheticEvents.js';\nimport {eventTimingsMicroSeconds} from './Timing.js';\n\ntype MatchedPairType<T extends Types.TraceEvents.TraceEventPairableAsync> = Types.TraceEvents.SyntheticEventPair<T>;\ntype MatchingPairableAsyncEvents = {\n begin: Types.TraceEvents.TraceEventPairableAsyncBegin|null,\n end: Types.TraceEvents.TraceEventPairableAsyncEnd|null,\n instant?: Types.TraceEvents.TraceEventPairableAsyncInstant[],\n};\n\n/**\n * Extracts the raw stack trace of known trace events. Most likely than\n * not you want to use `getZeroIndexedStackTraceForEvent`, which returns\n * the stack with zero based numbering. Since some trace events are\n * one based this function can yield unexpected results when used\n * indiscriminately.\n */\nfunction stackTraceForEvent(event: Types.TraceEvents.TraceEventData): Types.TraceEvents.TraceEventCallFrame[]|null {\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};\nexport function 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: readonly T1[], eventsArray2: readonly 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.TraceEventPairableAsync|\n MatchedPairType<Types.TraceEvents.TraceEventPairableAsync>): 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\n/**\n * @param node the node attached to the profile call. Here a node represents a function in the call tree.\n * @param profileId the profile ID that the sample came from that backs this call.\n * @param sampleIndex the index of the sample in the given profile that this call was created from\n * @param ts the timestamp of the profile call\n * @param pid the process ID of the profile call\n * @param tid the thread ID of the profile call\n *\n * See `panels/timeline/docs/profile_calls.md` for more context on how these events are created.\n */\nexport function makeProfileCall(\n node: CPUProfile.ProfileTreeModel.ProfileNode, profileId: Types.TraceEvents.ProfileID, sampleIndex: number,\n ts: Types.Timing.MicroSeconds, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID): Types.TraceEvents.SyntheticProfileCall {\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 sampleIndex,\n profileId,\n };\n}\n\nexport function makeSyntheticTraceEntry(\n name: string, ts: Types.Timing.MicroSeconds, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID): Types.TraceEvents.SyntheticTraceEntry {\n return {\n cat: '',\n name,\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 };\n}\n\n/**\n * Matches beginning events with TraceEventPairableAsyncEnd and TraceEventPairableAsyncInstant (ASYNC_NESTABLE_INSTANT)\n * if provided, though currently only coming from Animations. Traces may contain multiple instant events so we need to\n * account for that.\n *\n * @returns {Map<string, MatchingPairableAsyncEvents>} Map of the animation's ID to it's matching events.\n */\nexport function matchEvents(unpairedEvents: Types.TraceEvents.TraceEventPairableAsync[]):\n Map<string, MatchingPairableAsyncEvents> {\n // map to store begin and end of the event\n const matchedPairs: Map<string, MatchingPairableAsyncEvents> = new Map();\n\n // looking for start and end\n for (const event of unpairedEvents) {\n const syntheticId = getSyntheticId(event);\n if (syntheticId === 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 otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedPairs, syntheticId, () => {\n return {begin: null, end: null, instant: []};\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 const isInstantEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_INSTANT;\n\n if (isStartEvent) {\n otherEventsWithID.begin = event as Types.TraceEvents.TraceEventPairableAsyncBegin;\n } else if (isEndEvent) {\n otherEventsWithID.end = event as Types.TraceEvents.TraceEventPairableAsyncEnd;\n } else if (isInstantEvent) {\n if (!otherEventsWithID.instant) {\n otherEventsWithID.instant = [];\n }\n otherEventsWithID.instant.push(event as Types.TraceEvents.TraceEventPairableAsyncInstant);\n }\n }\n return matchedPairs;\n}\n\nfunction getSyntheticId(event: Types.TraceEvents.TraceEventPairableAsync): string|undefined {\n const id = extractId(event);\n return id && `${event.cat}:${id}:${event.name}`;\n}\n\nexport function createSortedSyntheticEvents<T extends Types.TraceEvents.TraceEventPairableAsync>(\n matchedPairs: Map<string, {\n begin: Types.TraceEvents.TraceEventPairableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventPairableAsyncEnd | null,\n instant?: Types.TraceEvents.TraceEventPairableAsyncInstant[],\n }>,\n syntheticEventCallback?: (syntheticEvent: MatchedPairType<T>) => void,\n ): MatchedPairType<T>[] {\n const syntheticEvents: MatchedPairType<T>[] = [];\n for (const [id, eventsTriplet] of matchedPairs.entries()) {\n const beginEvent = eventsTriplet.begin;\n const endEvent = eventsTriplet.end;\n const instantEvents = eventsTriplet.instant;\n if (!beginEvent || !(endEvent || instantEvents)) {\n // This should never happen, the backend only creates the events once it\n // has them both (beginEvent & endEvent/instantEvents), 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 const triplet = {beginEvent, endEvent, instantEvents};\n /**\n * When trying to pair events with instant events present, there are times when these\n * ASYNC_NESTABLE_INSTANT ('n') don't have a corresponding ASYNC_NESTABLE_END ('e') event.\n * In these cases, pair without needing the endEvent.\n */\n function eventsArePairable(data: {\n beginEvent: Types.TraceEvents.TraceEventPairableAsyncBegin,\n endEvent: Types.TraceEvents.TraceEventPairableAsyncEnd|null,\n instantEvents?: Types.TraceEvents.TraceEventPairableAsyncInstant[],\n }): data is MatchedPairType<T>['args']['data'] {\n const instantEventsMatch = data.instantEvents ? data.instantEvents.some(e => id === getSyntheticId(e)) : false;\n const endEventMatch = data.endEvent ? id === getSyntheticId(data.endEvent) : false;\n return Boolean(id) && (instantEventsMatch || endEventMatch);\n }\n if (!eventsArePairable(triplet)) {\n continue;\n }\n const targetEvent = endEvent || beginEvent;\n\n const event = SyntheticEventsManager.registerSyntheticBasedEvent<MatchedPairType<T>>({\n rawSourceEvent: beginEvent,\n cat: targetEvent.cat,\n ph: targetEvent.ph,\n pid: targetEvent.pid,\n tid: targetEvent.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: beginEvent.name,\n dur: Types.Timing.MicroSeconds(targetEvent.ts - beginEvent.ts),\n ts: beginEvent.ts,\n args: {\n data: triplet,\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 syntheticEventCallback?.(event);\n syntheticEvents.push(event);\n }\n return syntheticEvents.sort((a, b) => a.ts - b.ts);\n}\n\nexport function createMatchedSortedSyntheticEvents<T extends Types.TraceEvents.TraceEventPairableAsync>(\n unpairedAsyncEvents: T[],\n syntheticEventCallback?: (syntheticEvent: MatchedPairType<T>) => void): MatchedPairType<T>[] {\n const matchedPairs = matchEvents(unpairedAsyncEvents);\n const syntheticEvents = createSortedSyntheticEvents<T>(matchedPairs, syntheticEventCallback);\n return syntheticEvents;\n}\n\n/**\n * Different trace events return line/column numbers that are 1 or 0 indexed.\n * This function knows which events return 1 indexed numbers and normalizes\n * them. The UI expects 0 indexed line numbers, so that is what we return.\n */\nexport function getZeroIndexedLineAndColumnForEvent(event: Types.TraceEvents.TraceEventData): {\n lineNumber?: number,\n columnNumber?: number,\n} {\n // Some events emit line numbers that are 1 indexed, but the UI layer expects\n // numbers to be 0 indexed. So here, if the event matches a known 1-indexed\n // number event, we subtract one from the line and column numbers.\n // Otherwise, if the event has args.data.lineNumber/colNumber, we return it\n // as is.\n const numbers = getRawLineAndColumnNumbersForEvent(event);\n const {lineNumber, columnNumber} = numbers;\n\n switch (event.name) {\n // All these events have line/column numbers which are 1 indexed; so we\n // subtract to make them 0 indexed.\n case Types.TraceEvents.KnownEventName.FunctionCall:\n case Types.TraceEvents.KnownEventName.EvaluateScript:\n case Types.TraceEvents.KnownEventName.Compile:\n case Types.TraceEvents.KnownEventName.CacheScript: {\n return {\n lineNumber: typeof lineNumber === 'number' ? lineNumber - 1 : undefined,\n columnNumber: typeof columnNumber === 'number' ? columnNumber - 1 : undefined,\n };\n }\n default: {\n return numbers;\n }\n }\n}\n\n/**\n * Different trace events contain stack traces with line/column numbers\n * that are 1 or 0 indexed.\n * This function knows which events return 1 indexed numbers and normalizes\n * them. The UI expects 0 indexed line numbers, so that is what we return.\n */\nexport function getZeroIndexedStackTraceForEvent(event: Types.TraceEvents.TraceEventData):\n Types.TraceEvents.TraceEventCallFrame[]|null {\n const stack = stackTraceForEvent(event);\n if (!stack) {\n return null;\n }\n return stack.map(callFrame => {\n const normalizedCallFrame = {...callFrame};\n switch (event.name) {\n case Types.TraceEvents.KnownEventName.ScheduleStyleRecalculation:\n case Types.TraceEvents.KnownEventName.InvalidateLayout:\n case Types.TraceEvents.KnownEventName.UpdateLayoutTree: {\n normalizedCallFrame.lineNumber = callFrame.lineNumber && callFrame.lineNumber - 1;\n normalizedCallFrame.columnNumber = callFrame.columnNumber && callFrame.columnNumber - 1;\n }\n }\n return normalizedCallFrame;\n });\n}\n\n/**\n * NOTE: you probably do not want this function! (Which is why it is not exported).\n *\n * Some trace events have 0 indexed line/column numbers, and others have 1\n * indexed. This function does NOT normalize them, but\n * `getZeroIndexedLineAndColumnNumbersForEvent` does. It is best to use that!\n *\n * @see {@link getZeroIndexedLineAndColumnForEvent}\n **/\nfunction getRawLineAndColumnNumbersForEvent(event: Types.TraceEvents.TraceEventData): {\n lineNumber?: number,\n columnNumber?: number,\n} {\n if (!event.args?.data) {\n return {\n lineNumber: undefined,\n columnNumber: undefined,\n };\n }\n let lineNumber: number|undefined = undefined;\n let columnNumber: number|undefined = undefined;\n if ('lineNumber' in event.args.data && typeof event.args.data.lineNumber === 'number') {\n lineNumber = event.args.data.lineNumber;\n }\n if ('columnNumber' in event.args.data && typeof event.args.data.columnNumber === 'number') {\n columnNumber = event.args.data.columnNumber;\n }\n\n return {lineNumber, columnNumber};\n}\n\nexport function frameIDForEvent(event: Types.TraceEvents.TraceEventData): string|null {\n // There are a few events (for example UpdateLayoutTree, ParseHTML) that have\n // the frame stored in args.beginData\n // Rather than list them all we just check for the presence of the field, so\n // we are robust against future trace events also doing this.\n // This check seems very robust, but it also helps satisfy TypeScript and\n // prevents us against unexpected data.\n if (event.args && 'beginData' in event.args && typeof event.args.beginData === 'object' &&\n event.args.beginData !== null && 'frame' in event.args.beginData &&\n typeof event.args.beginData.frame === 'string') {\n return event.args.beginData.frame;\n }\n // Otherwise, we expect frame to be in args.data\n if (event.args?.data?.frame) {\n return event.args.data.frame;\n }\n\n // No known frame for this event.\n return null;\n}\n\nconst DevToolsTimelineEventCategory = 'disabled-by-default-devtools.timeline';\nexport function isTopLevelEvent(event: Types.TraceEvents.TraceEventData): boolean {\n if (event.name === 'JSRoot' && event.cat === 'toplevel') {\n // This is used in TimelineJSProfile to insert a fake event prior to the\n // CPU Profile in order to ensure the trace isn't truncated. So if we see\n // this, we want to treat it as a top level event.\n // TODO(crbug.com/341234884): do we need this?\n return true;\n }\n return event.cat.includes(DevToolsTimelineEventCategory) && event.name === Types.TraceEvents.KnownEventName.RunTask;\n}\n\nfunction topLevelEventIndexEndingAfter(\n events: Types.TraceEvents.TraceEventData[], time: Types.Timing.MicroSeconds): number {\n let index = Platform.ArrayUtilities.upperBound(events, time, (time, event) => time - event.ts) - 1;\n while (index > 0 && !isTopLevelEvent(events[index])) {\n index--;\n }\n return Math.max(index, 0);\n}\nexport function findUpdateLayoutTreeEvents(\n events: Types.TraceEvents.TraceEventData[], startTime: Types.Timing.MicroSeconds,\n endTime?: Types.Timing.MicroSeconds): Types.TraceEvents.TraceEventUpdateLayoutTree[] {\n const foundEvents: Types.TraceEvents.TraceEventUpdateLayoutTree[] = [];\n const startEventIndex = topLevelEventIndexEndingAfter(events, startTime);\n for (let i = startEventIndex; i < events.length; i++) {\n const event = events[i];\n if (!Types.TraceEvents.isTraceEventUpdateLayoutTree(event)) {\n continue;\n }\n if (event.ts >= (endTime || Infinity)) {\n continue;\n }\n foundEvents.push(event);\n }\n return foundEvents;\n}\n\nexport interface ForEachEventConfig {\n onStartEvent: (event: Types.TraceEvents.TraceEventData) => void;\n onEndEvent: (event: Types.TraceEvents.TraceEventData) => void;\n onInstantEvent?: (event: Types.TraceEvents.TraceEventData) => void;\n eventFilter?: (event: Types.TraceEvents.TraceEventData) => boolean;\n startTime?: Types.Timing.MicroSeconds;\n endTime?: Types.Timing.MicroSeconds;\n /* If async events should be skipped. Defaults to true */\n ignoreAsyncEvents?: boolean;\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 * dictated by the corresponding timestamp.\n *\n * Events are assumed to be in ascendent order by timestamp.\n *\n * Events with 0 duration are treated as instant events. These do not have a\n * begin and end, but will be passed to the config.onInstantEvent callback as\n * they are discovered. Do not provide this callback if you are not interested\n * in them.\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 * By default, async events are skipped. This behaviour can be\n * overriden making use of the config.ignoreAsyncEvents parameter.\n */\nexport function forEachEvent(\n events: Types.TraceEvents.TraceEventData[],\n config: ForEachEventConfig,\n ): void {\n const globalStartTime = config.startTime || Types.Timing.MicroSeconds(0);\n const globalEndTime = config.endTime || Types.Timing.MicroSeconds(Infinity);\n const ignoreAsyncEvents = config.ignoreAsyncEvents === false ? false : true;\n\n const stack: Types.TraceEvents.TraceEventData[] = [];\n const startEventIndex = topLevelEventIndexEndingAfter(events, globalStartTime);\n for (let i = startEventIndex; i < events.length; i++) {\n const currentEvent = events[i];\n const currentEventTimings = eventTimingsMicroSeconds(currentEvent);\n if (currentEventTimings.endTime < globalStartTime) {\n continue;\n }\n if (currentEventTimings.startTime > globalEndTime) {\n break;\n }\n\n const isIgnoredAsyncEvent = ignoreAsyncEvents && Types.TraceEvents.isAsyncPhase(currentEvent.ph);\n if (isIgnoredAsyncEvent || Types.TraceEvents.isFlowPhase(currentEvent.ph)) {\n continue;\n }\n\n // If we have now reached an event that is after a bunch of events, we need\n // to call the onEndEvent callback for those events before moving on.\n let lastEventOnStack = stack.at(-1);\n let lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;\n while (lastEventOnStack && lastEventEndTime && lastEventEndTime <= currentEventTimings.startTime) {\n stack.pop();\n config.onEndEvent(lastEventOnStack);\n lastEventOnStack = stack.at(-1);\n lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;\n }\n\n // Now we have dealt with all events prior to this one, see if we need to care about this one.\n if (config.eventFilter && !config.eventFilter(currentEvent)) {\n // The user has chosen to filter this event out, so continue on and do nothing\n continue;\n }\n\n if (currentEventTimings.duration) {\n config.onStartEvent(currentEvent);\n stack.push(currentEvent);\n } else if (config.onInstantEvent) {\n // An event with 0 duration is an instant event.\n config.onInstantEvent(currentEvent);\n }\n }\n\n // Now we have finished looping over all events; any events remaining on the\n // stack need to have their onEndEvent called.\n while (stack.length) {\n const last = stack.pop();\n if (last) {\n config.onEndEvent(last);\n }\n }\n}\n\n// Parsed categories are cached to prevent calling cat.split()\n// multiple times on the same categories string.\nconst parsedCategories = new Map<string, Set<string>>();\nexport function eventHasCategory(event: Types.TraceEvents.TraceEventData, category: string): boolean {\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 nodeIdForInvalidationEvent(event: Types.TraceEvents.InvalidationTrackingEvent):\n Protocol.DOM.BackendNodeId|null {\n return event.args.data.nodeId ?? null;\n}\n"]}
1
+ {"version":3,"file":"Trace.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/helpers/Trace.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\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 {SyntheticEventsManager} from './SyntheticEvents.js';\nimport {eventTimingsMicroSeconds} from './Timing.js';\n\ntype MatchedPairType<T extends Types.Events.PairableAsync> = Types.Events.SyntheticEventPair<T>;\ntype MatchingPairableAsyncEvents = {\n begin: Types.Events.PairableAsyncBegin|null,\n end: Types.Events.PairableAsyncEnd|null,\n instant?: Types.Events.PairableAsyncInstant[],\n};\n\n/**\n * Extracts the raw stack trace of known trace events. Most likely than\n * not you want to use `getZeroIndexedStackTraceForEvent`, which returns\n * the stack with zero based numbering. Since some trace events are\n * one based this function can yield unexpected results when used\n * indiscriminately.\n */\nexport function stackTraceForEvent(event: Types.Events.Event): Types.Events.CallFrame[]|null {\n if (event.args?.data?.stackTrace) {\n return event.args.data.stackTrace;\n }\n if (event.args?.stackTrace) {\n return event.args.stackTrace;\n }\n if (Types.Events.isUpdateLayoutTree(event)) {\n return event.args.beginData?.stackTrace || null;\n }\n if (Types.Extensions.isSyntheticExtensionEntry(event)) {\n return stackTraceForEvent(event.rawSourceEvent);\n }\n if (Types.Events.isSyntheticUserTiming(event)) {\n return stackTraceForEvent(event.rawSourceEvent);\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.Events.Event> = Map<Types.Events.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.Events.Event>(\n event: T,\n eventsInProcessThread: Map<Types.Events.ProcessID, EventsInThread<T>>,\n ): void {\n const {tid, pid} = event;\n let eventsInThread = eventsInProcessThread.get(pid);\n if (!eventsInThread) {\n eventsInThread = new Map<Types.Events.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\nexport type TimeSpan = {\n ts: Types.Timing.MicroSeconds,\n dur?: Types.Timing.MicroSeconds,\n};\nexport function 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 mergeEventsInOrder<T1 extends Types.Events.Event, T2 extends Types.Events.Event>(\n eventsArray1: readonly T1[], eventsArray2: readonly 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.Events.Event,\n eventFrameId: string,\n navigationsByFrameId: Map<string, Types.Events.NavigationStart[]>,\n ): Types.Events.NavigationStart|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.Events.PairableAsync|MatchedPairType<Types.Events.PairableAsync>): string|\n undefined {\n return event.id ?? event.id2?.global ?? event.id2?.local;\n}\n\nexport function activeURLForFrameAtTime(\n frameId: string, time: Types.Timing.MicroSeconds,\n rendererProcessesByFrame: Map<\n string,\n Map<Types.Events.ProcessID, {frame: Types.Events.TraceFrame, window: Types.Timing.TraceWindowMicroSeconds}[]>>):\n string|null {\n const processData = rendererProcessesByFrame.get(frameId);\n if (!processData) {\n return null;\n }\n for (const processes of processData.values()) {\n for (const processInfo of processes) {\n if (processInfo.window.min > time || processInfo.window.max < time) {\n continue;\n }\n return processInfo.frame.url;\n }\n }\n return null;\n}\n\n/**\n * @param node the node attached to the profile call. Here a node represents a function in the call tree.\n * @param profileId the profile ID that the sample came from that backs this call.\n * @param sampleIndex the index of the sample in the given profile that this call was created from\n * @param ts the timestamp of the profile call\n * @param pid the process ID of the profile call\n * @param tid the thread ID of the profile call\n *\n * See `panels/timeline/docs/profile_calls.md` for more context on how these events are created.\n */\nexport function makeProfileCall(\n node: CPUProfile.ProfileTreeModel.ProfileNode, profileId: Types.Events.ProfileID, sampleIndex: number,\n ts: Types.Timing.MicroSeconds, pid: Types.Events.ProcessID,\n tid: Types.Events.ThreadID): Types.Events.SyntheticProfileCall {\n return {\n cat: '',\n name: 'ProfileCall',\n nodeId: node.id,\n args: {},\n ph: Types.Events.Phase.COMPLETE,\n pid,\n tid,\n ts,\n dur: Types.Timing.MicroSeconds(0),\n callFrame: node.callFrame,\n sampleIndex,\n profileId,\n };\n}\n\n/**\n * Matches beginning events with PairableAsyncEnd and PairableAsyncInstant (ASYNC_NESTABLE_INSTANT)\n * if provided, though currently only coming from Animations. Traces may contain multiple instant events so we need to\n * account for that.\n *\n * @returns {Map<string, MatchingPairableAsyncEvents>} Map of the animation's ID to it's matching events.\n */\nexport function matchEvents(unpairedEvents: Types.Events.PairableAsync[]): Map<string, MatchingPairableAsyncEvents> {\n // map to store begin and end of the event\n const matchedPairs: Map<string, MatchingPairableAsyncEvents> = new Map();\n\n // looking for start and end\n for (const event of unpairedEvents) {\n const syntheticId = getSyntheticId(event);\n if (syntheticId === 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 otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedPairs, syntheticId, () => {\n return {begin: null, end: null, instant: []};\n });\n\n const isStartEvent = event.ph === Types.Events.Phase.ASYNC_NESTABLE_START;\n const isEndEvent = event.ph === Types.Events.Phase.ASYNC_NESTABLE_END;\n const isInstantEvent = event.ph === Types.Events.Phase.ASYNC_NESTABLE_INSTANT;\n\n if (isStartEvent) {\n otherEventsWithID.begin = event as Types.Events.PairableAsyncBegin;\n } else if (isEndEvent) {\n otherEventsWithID.end = event as Types.Events.PairableAsyncEnd;\n } else if (isInstantEvent) {\n if (!otherEventsWithID.instant) {\n otherEventsWithID.instant = [];\n }\n otherEventsWithID.instant.push(event as Types.Events.PairableAsyncInstant);\n }\n }\n return matchedPairs;\n}\n\nfunction getSyntheticId(event: Types.Events.PairableAsync): string|undefined {\n const id = extractId(event);\n return id && `${event.cat}:${id}:${event.name}`;\n}\n\nexport function createSortedSyntheticEvents<T extends Types.Events.PairableAsync>(\n matchedPairs: Map<string, {\n begin: Types.Events.PairableAsyncBegin | null,\n end: Types.Events.PairableAsyncEnd | null,\n instant?: Types.Events.PairableAsyncInstant[],\n }>,\n syntheticEventCallback?: (syntheticEvent: MatchedPairType<T>) => void,\n ): MatchedPairType<T>[] {\n const syntheticEvents: MatchedPairType<T>[] = [];\n for (const [id, eventsTriplet] of matchedPairs.entries()) {\n const beginEvent = eventsTriplet.begin;\n const endEvent = eventsTriplet.end;\n const instantEvents = eventsTriplet.instant;\n if (!beginEvent || !(endEvent || instantEvents)) {\n // This should never happen, the backend only creates the events once it\n // has them both (beginEvent & endEvent/instantEvents), 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 const triplet = {beginEvent, endEvent, instantEvents};\n /**\n * When trying to pair events with instant events present, there are times when these\n * ASYNC_NESTABLE_INSTANT ('n') don't have a corresponding ASYNC_NESTABLE_END ('e') event.\n * In these cases, pair without needing the endEvent.\n */\n function eventsArePairable(data: {\n beginEvent: Types.Events.PairableAsyncBegin,\n endEvent: Types.Events.PairableAsyncEnd|null,\n instantEvents?: Types.Events.PairableAsyncInstant[],\n }): data is MatchedPairType<T>['args']['data'] {\n const instantEventsMatch = data.instantEvents ? data.instantEvents.some(e => id === getSyntheticId(e)) : false;\n const endEventMatch = data.endEvent ? id === getSyntheticId(data.endEvent) : false;\n return Boolean(id) && (instantEventsMatch || endEventMatch);\n }\n if (!eventsArePairable(triplet)) {\n continue;\n }\n const targetEvent = endEvent || beginEvent;\n\n const event = SyntheticEventsManager.registerSyntheticEvent<MatchedPairType<T>>({\n rawSourceEvent: beginEvent,\n cat: targetEvent.cat,\n ph: targetEvent.ph,\n pid: targetEvent.pid,\n tid: targetEvent.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: beginEvent.name,\n dur: Types.Timing.MicroSeconds(targetEvent.ts - beginEvent.ts),\n ts: beginEvent.ts,\n args: {\n data: triplet,\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 syntheticEventCallback?.(event);\n syntheticEvents.push(event);\n }\n return syntheticEvents.sort((a, b) => a.ts - b.ts);\n}\n\nexport function createMatchedSortedSyntheticEvents<T extends Types.Events.PairableAsync>(\n unpairedAsyncEvents: T[],\n syntheticEventCallback?: (syntheticEvent: MatchedPairType<T>) => void): MatchedPairType<T>[] {\n const matchedPairs = matchEvents(unpairedAsyncEvents);\n const syntheticEvents = createSortedSyntheticEvents<T>(matchedPairs, syntheticEventCallback);\n return syntheticEvents;\n}\n\n/**\n * Different trace events return line/column numbers that are 1 or 0 indexed.\n * This function knows which events return 1 indexed numbers and normalizes\n * them. The UI expects 0 indexed line numbers, so that is what we return.\n */\nexport function getZeroIndexedLineAndColumnForEvent(event: Types.Events.Event): {\n lineNumber?: number,\n columnNumber?: number,\n} {\n // Some events emit line numbers that are 1 indexed, but the UI layer expects\n // numbers to be 0 indexed. So here, if the event matches a known 1-indexed\n // number event, we subtract one from the line and column numbers.\n // Otherwise, if the event has args.data.lineNumber/colNumber, we return it\n // as is.\n const numbers = getRawLineAndColumnNumbersForEvent(event);\n const {lineNumber, columnNumber} = numbers;\n\n switch (event.name) {\n // All these events have line/column numbers which are 1 indexed; so we\n // subtract to make them 0 indexed.\n case Types.Events.Name.FUNCTION_CALL:\n case Types.Events.Name.EVALUATE_SCRIPT:\n case Types.Events.Name.COMPILE:\n case Types.Events.Name.CACHE_SCRIPT: {\n return {\n lineNumber: typeof lineNumber === 'number' ? lineNumber - 1 : undefined,\n columnNumber: typeof columnNumber === 'number' ? columnNumber - 1 : undefined,\n };\n }\n default: {\n return numbers;\n }\n }\n}\n\n/**\n * Different trace events contain stack traces with line/column numbers\n * that are 1 or 0 indexed.\n * This function knows which events return 1 indexed numbers and normalizes\n * them. The UI expects 0 indexed line numbers, so that is what we return.\n */\nexport function getZeroIndexedStackTraceForEvent(event: Types.Events.Event): Types.Events.CallFrame[]|null {\n const stack = stackTraceForEvent(event);\n if (!stack) {\n return null;\n }\n return stack.map(callFrame => {\n switch (event.name) {\n case Types.Events.Name.SCHEDULE_STYLE_RECALCULATION:\n case Types.Events.Name.INVALIDATE_LAYOUT:\n case Types.Events.Name.UPDATE_LAYOUT_TREE: {\n return makeZeroBasedCallFrame(callFrame);\n }\n default: {\n if (Types.Events.isUserTiming(event) || Types.Extensions.isSyntheticExtensionEntry(event)) {\n return makeZeroBasedCallFrame(callFrame);\n }\n }\n }\n return callFrame;\n });\n}\n\n/**\n * Given a 1-based call frame creates a 0-based one.\n */\nexport function makeZeroBasedCallFrame(callFrame: Types.Events.CallFrame): Types.Events.CallFrame {\n const normalizedCallFrame = {...callFrame};\n\n normalizedCallFrame.lineNumber = callFrame.lineNumber && callFrame.lineNumber - 1;\n normalizedCallFrame.columnNumber = callFrame.columnNumber && callFrame.columnNumber - 1;\n return normalizedCallFrame;\n}\n\n/**\n * NOTE: you probably do not want this function! (Which is why it is not exported).\n *\n * Some trace events have 0 indexed line/column numbers, and others have 1\n * indexed. This function does NOT normalize them, but\n * `getZeroIndexedLineAndColumnNumbersForEvent` does. It is best to use that!\n *\n * @see {@link getZeroIndexedLineAndColumnForEvent}\n **/\nfunction getRawLineAndColumnNumbersForEvent(event: Types.Events.Event): {\n lineNumber?: number,\n columnNumber?: number,\n} {\n if (!event.args?.data) {\n return {\n lineNumber: undefined,\n columnNumber: undefined,\n };\n }\n let lineNumber: number|undefined = undefined;\n let columnNumber: number|undefined = undefined;\n if ('lineNumber' in event.args.data && typeof event.args.data.lineNumber === 'number') {\n lineNumber = event.args.data.lineNumber;\n }\n if ('columnNumber' in event.args.data && typeof event.args.data.columnNumber === 'number') {\n columnNumber = event.args.data.columnNumber;\n }\n\n return {lineNumber, columnNumber};\n}\n\nexport function frameIDForEvent(event: Types.Events.Event): string|null {\n // There are a few events (for example UpdateLayoutTree, ParseHTML) that have\n // the frame stored in args.beginData\n // Rather than list them all we just check for the presence of the field, so\n // we are robust against future trace events also doing this.\n // This check seems very robust, but it also helps satisfy TypeScript and\n // prevents us against unexpected data.\n if (event.args && 'beginData' in event.args && typeof event.args.beginData === 'object' &&\n event.args.beginData !== null && 'frame' in event.args.beginData &&\n typeof event.args.beginData.frame === 'string') {\n return event.args.beginData.frame;\n }\n // Otherwise, we expect frame to be in args.data\n if (event.args?.data?.frame) {\n return event.args.data.frame;\n }\n\n // No known frame for this event.\n return null;\n}\n\nconst DevToolsTimelineEventCategory = 'disabled-by-default-devtools.timeline';\nexport function isTopLevelEvent(event: Types.Events.Event): boolean {\n if (event.name === 'JSRoot' && event.cat === 'toplevel') {\n // This is used in TimelineJSProfile to insert a fake event prior to the\n // CPU Profile in order to ensure the trace isn't truncated. So if we see\n // this, we want to treat it as a top level event.\n // TODO(crbug.com/341234884): do we need this?\n return true;\n }\n return event.cat.includes(DevToolsTimelineEventCategory) && event.name === Types.Events.Name.RUN_TASK;\n}\n\nfunction topLevelEventIndexEndingAfter(events: Types.Events.Event[], time: Types.Timing.MicroSeconds): number {\n let index = Platform.ArrayUtilities.upperBound(events, time, (time, event) => time - event.ts) - 1;\n while (index > 0 && !isTopLevelEvent(events[index])) {\n index--;\n }\n return Math.max(index, 0);\n}\nexport function findUpdateLayoutTreeEvents(\n events: Types.Events.Event[], startTime: Types.Timing.MicroSeconds,\n endTime?: Types.Timing.MicroSeconds): Types.Events.UpdateLayoutTree[] {\n const foundEvents: Types.Events.UpdateLayoutTree[] = [];\n const startEventIndex = topLevelEventIndexEndingAfter(events, startTime);\n for (let i = startEventIndex; i < events.length; i++) {\n const event = events[i];\n if (!Types.Events.isUpdateLayoutTree(event)) {\n continue;\n }\n if (event.ts >= (endTime || Infinity)) {\n continue;\n }\n foundEvents.push(event);\n }\n return foundEvents;\n}\n\nexport function findNextEventAfterTimestamp<T extends Types.Events.Event>(\n candidates: T[], ts: Types.Timing.MicroSeconds): T|null {\n const index = Platform.ArrayUtilities.nearestIndexFromBeginning(candidates, candidate => ts < candidate.ts);\n return index === null ? null : candidates[index];\n}\n\nexport function findPreviousEventBeforeTimestamp<T extends Types.Events.Event>(\n candidates: T[], ts: Types.Timing.MicroSeconds): T|null {\n const index = Platform.ArrayUtilities.nearestIndexFromEnd(candidates, candidate => candidate.ts < ts);\n return index === null ? null : candidates[index];\n}\n\nexport interface ForEachEventConfig {\n onStartEvent: (event: Types.Events.Event) => void;\n onEndEvent: (event: Types.Events.Event) => void;\n onInstantEvent?: (event: Types.Events.Event) => void;\n eventFilter?: (event: Types.Events.Event) => boolean;\n startTime?: Types.Timing.MicroSeconds;\n endTime?: Types.Timing.MicroSeconds;\n /* If async events should be skipped. Defaults to true */\n ignoreAsyncEvents?: boolean;\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 * dictated by the corresponding timestamp.\n *\n * Events are assumed to be in ascendent order by timestamp.\n *\n * Events with 0 duration are treated as instant events. These do not have a\n * begin and end, but will be passed to the config.onInstantEvent callback as\n * they are discovered. Do not provide this callback if you are not interested\n * in them.\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 * By default, async events are skipped. This behaviour can be\n * overriden making use of the config.ignoreAsyncEvents parameter.\n */\nexport function forEachEvent(\n events: Types.Events.Event[],\n config: ForEachEventConfig,\n ): void {\n const globalStartTime = config.startTime ?? Types.Timing.MicroSeconds(0);\n const globalEndTime = config.endTime || Types.Timing.MicroSeconds(Infinity);\n const ignoreAsyncEvents = config.ignoreAsyncEvents === false ? false : true;\n\n const stack: Types.Events.Event[] = [];\n const startEventIndex = topLevelEventIndexEndingAfter(events, globalStartTime);\n for (let i = startEventIndex; i < events.length; i++) {\n const currentEvent = events[i];\n const currentEventTimings = eventTimingsMicroSeconds(currentEvent);\n if (currentEventTimings.endTime < globalStartTime) {\n continue;\n }\n if (currentEventTimings.startTime > globalEndTime) {\n break;\n }\n\n const isIgnoredAsyncEvent = ignoreAsyncEvents && Types.Events.isPhaseAsync(currentEvent.ph);\n if (isIgnoredAsyncEvent || Types.Events.isFlowPhase(currentEvent.ph)) {\n continue;\n }\n\n // If we have now reached an event that is after a bunch of events, we need\n // to call the onEndEvent callback for those events before moving on.\n let lastEventOnStack = stack.at(-1);\n let lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;\n while (lastEventOnStack && lastEventEndTime && lastEventEndTime <= currentEventTimings.startTime) {\n stack.pop();\n config.onEndEvent(lastEventOnStack);\n lastEventOnStack = stack.at(-1);\n lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;\n }\n\n // Now we have dealt with all events prior to this one, see if we need to care about this one.\n if (config.eventFilter && !config.eventFilter(currentEvent)) {\n // The user has chosen to filter this event out, so continue on and do nothing\n continue;\n }\n\n if (currentEventTimings.duration) {\n config.onStartEvent(currentEvent);\n stack.push(currentEvent);\n } else if (config.onInstantEvent) {\n // An event with 0 duration is an instant event.\n config.onInstantEvent(currentEvent);\n }\n }\n\n // Now we have finished looping over all events; any events remaining on the\n // stack need to have their onEndEvent called.\n while (stack.length) {\n const last = stack.pop();\n if (last) {\n config.onEndEvent(last);\n }\n }\n}\n\n// Parsed categories are cached to prevent calling cat.split()\n// multiple times on the same categories string.\nconst parsedCategories = new Map<string, Set<string>>();\nexport function eventHasCategory(event: Types.Events.Event, category: string): boolean {\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 nodeIdForInvalidationEvent(event: Types.Events.InvalidationTrackingEvent): Protocol.DOM.BackendNodeId|\n null {\n return event.args.data.nodeId ?? null;\n}\n"]}
@@ -1,18 +1,40 @@
1
1
  import * as Types from '../types/types.js';
2
2
  export declare const makeTraceEntryNodeId: () => TraceEntryNodeId;
3
3
  export declare const makeEmptyTraceEntryTree: () => TraceEntryTree;
4
- export declare const makeEmptyTraceEntryNode: (entry: Types.TraceEvents.SyntheticTraceEntry, id: TraceEntryNodeId) => TraceEntryNode;
4
+ export declare const makeEmptyTraceEntryNode: (entry: Types.Events.Event, id: TraceEntryNodeId) => TraceEntryNode;
5
5
  export interface TraceEntryTree {
6
6
  roots: Set<TraceEntryNode>;
7
7
  maxDepth: number;
8
8
  }
9
9
  export interface TraceEntryNode {
10
- entry: Types.TraceEvents.SyntheticTraceEntry;
10
+ entry: Types.Events.Event;
11
11
  depth: number;
12
+ selfTime?: Types.Timing.MicroSeconds;
12
13
  id: TraceEntryNodeId;
13
14
  parent: TraceEntryNode | null;
14
15
  children: TraceEntryNode[];
15
16
  }
17
+ /**
18
+ * Represents a node in a trace entry tree, simplified for AI Assistance processing.
19
+ */
20
+ export declare class TraceEntryNodeForAI {
21
+ #private;
22
+ type: string;
23
+ start: Types.Timing.MilliSeconds;
24
+ end?: Types.Timing.MilliSeconds | undefined;
25
+ totalTime?: Types.Timing.MilliSeconds | undefined;
26
+ selfTime?: Types.Timing.MilliSeconds | undefined;
27
+ id?: TraceEntryNodeId;
28
+ domain?: string;
29
+ line?: number;
30
+ column?: number;
31
+ function?: string;
32
+ children?: TraceEntryNodeForAI[];
33
+ selected?: boolean;
34
+ constructor(type: string, start: Types.Timing.MilliSeconds, end?: Types.Timing.MilliSeconds | undefined, totalTime?: Types.Timing.MilliSeconds | undefined, selfTime?: Types.Timing.MilliSeconds | undefined);
35
+ static fromSelectedEntryNode(selectedEntryNode: TraceEntryNode): TraceEntryNodeForAI;
36
+ static getSelectedNodeForTraceEntryTreeForAI(node: TraceEntryNodeForAI): TraceEntryNodeForAI | null;
37
+ }
16
38
  declare class TraceEntryNodeIdTag {
17
39
  #private;
18
40
  }
@@ -33,13 +55,13 @@ export type TraceEntryNodeId = number & TraceEntryNodeIdTag;
33
55
  *
34
56
  * Complexity: O(n), where n = number of events
35
57
  */
36
- export declare function treify(entries: Types.TraceEvents.SyntheticTraceEntry[], options?: {
58
+ export declare function treify(entries: Types.Events.Event[], options?: {
37
59
  filter: {
38
- has: (name: Types.TraceEvents.KnownEventName) => boolean;
60
+ has: (name: Types.Events.Name) => boolean;
39
61
  };
40
62
  }): {
41
63
  tree: TraceEntryTree;
42
- entryToNode: Map<Types.TraceEvents.SyntheticTraceEntry, TraceEntryNode>;
64
+ entryToNode: Map<Types.Events.Event, TraceEntryNode>;
43
65
  };
44
66
  /**
45
67
  * Iterates events in a tree hierarchically, from top to bottom,
@@ -62,7 +84,7 @@ export declare function treify(entries: Types.TraceEvents.SyntheticTraceEntry[],
62
84
  * 9. End A
63
85
  *
64
86
  */
65
- export declare function walkTreeFromEntry(entryToNode: Map<Types.TraceEvents.SyntheticTraceEntry, TraceEntryNode>, rootEntry: Types.TraceEvents.SyntheticTraceEntry, onEntryStart: (entry: Types.TraceEvents.SyntheticTraceEntry) => void, onEntryEnd: (entry: Types.TraceEvents.SyntheticTraceEntry) => void): void;
87
+ export declare function walkTreeFromEntry(entryToNode: Map<Types.Events.Event, TraceEntryNode>, rootEntry: Types.Events.Event, onEntryStart: (entry: Types.Events.Event) => void, onEntryEnd: (entry: Types.Events.Event) => void): void;
66
88
  /**
67
89
  * Given a Helpers.TreeHelpers.RendererTree, this will iterates events in hierarchically, visiting
68
90
  * each root node and working from top to bottom, calling back on every event's
@@ -86,7 +108,7 @@ export declare function walkTreeFromEntry(entryToNode: Map<Types.TraceEvents.Syn
86
108
  * 11. End E
87
109
  *
88
110
  */
89
- export declare function walkEntireTree(entryToNode: Map<Types.TraceEvents.SyntheticTraceEntry, TraceEntryNode>, tree: TraceEntryTree, onEntryStart: (entry: Types.TraceEvents.SyntheticTraceEntry) => void, onEntryEnd: (entry: Types.TraceEvents.SyntheticTraceEntry) => void, traceWindowToInclude?: Types.Timing.TraceWindowMicroSeconds, minDuration?: Types.Timing.MicroSeconds): void;
111
+ export declare function walkEntireTree(entryToNode: Map<Types.Events.Event, TraceEntryNode>, tree: TraceEntryTree, onEntryStart: (entry: Types.Events.Event) => void, onEntryEnd: (entry: Types.Events.Event) => void, traceWindowToInclude?: Types.Timing.TraceWindowMicroSeconds, minDuration?: Types.Timing.MicroSeconds): void;
90
112
  /**
91
113
  * Determines if the given events, which are assumed to be ordered can
92
114
  * be organized into tree structures.
@@ -106,5 +128,5 @@ export declare function walkEntireTree(entryToNode: Map<Types.TraceEvents.Synthe
106
128
  * Note that this will also return true if multiple trees can be
107
129
  * built, for example if none of the events overlap with each other.
108
130
  */
109
- export declare function canBuildTreesFromEvents(events: readonly Types.TraceEvents.TraceEventData[]): boolean;
131
+ export declare function canBuildTreesFromEvents(events: readonly Types.Events.Event[]): boolean;
110
132
  export {};
@@ -2,6 +2,7 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
  import * as Types from '../types/types.js';
5
+ import { eventIsInBounds, microSecondsToMilliseconds } from './Timing.js';
5
6
  let nodeIdCount = 0;
6
7
  export const makeTraceEntryNodeId = () => (++nodeIdCount);
7
8
  export const makeEmptyTraceEntryTree = () => ({
@@ -15,6 +16,87 @@ export const makeEmptyTraceEntryNode = (entry, id) => ({
15
16
  children: [],
16
17
  depth: 0,
17
18
  });
19
+ /**
20
+ * Represents a node in a trace entry tree, simplified for AI Assistance processing.
21
+ */
22
+ export class TraceEntryNodeForAI {
23
+ type;
24
+ start;
25
+ end;
26
+ totalTime;
27
+ selfTime;
28
+ id;
29
+ domain;
30
+ line;
31
+ column;
32
+ function;
33
+ children;
34
+ selected;
35
+ constructor(type, start, end, totalTime, selfTime) {
36
+ this.type = type;
37
+ this.start = start;
38
+ this.end = end;
39
+ this.totalTime = totalTime;
40
+ this.selfTime = selfTime;
41
+ }
42
+ static #fromTraceEvent(event) {
43
+ const start = microSecondsToMilliseconds(event.ts);
44
+ const duration = event.dur === undefined ? undefined : microSecondsToMilliseconds(event.dur);
45
+ const nodeForAI = new TraceEntryNodeForAI(event.name, start, duration);
46
+ if (Types.Events.isProfileCall(event)) {
47
+ nodeForAI.function = event.callFrame.functionName || '(anonymous)';
48
+ try {
49
+ const url = new URL(event.callFrame.url);
50
+ nodeForAI.domain = url.origin;
51
+ nodeForAI.line = event.callFrame.lineNumber;
52
+ nodeForAI.column = event.callFrame.columnNumber;
53
+ }
54
+ catch (e) {
55
+ }
56
+ }
57
+ return nodeForAI;
58
+ }
59
+ /**
60
+ * Builds a TraceEntryNodeForAI tree from a TraceEntryNode tree and marks the selected node.
61
+ */
62
+ static #fromTraceEntryTree(node, selectedEntryNode) {
63
+ const nodeForAI = TraceEntryNodeForAI.#fromTraceEvent(node.entry);
64
+ nodeForAI.id = node.id;
65
+ if (node === selectedEntryNode) {
66
+ nodeForAI.selected = true;
67
+ }
68
+ nodeForAI.selfTime = node.selfTime === undefined ? undefined : microSecondsToMilliseconds(node.selfTime);
69
+ for (const child of node.children) {
70
+ nodeForAI.children ??= [];
71
+ nodeForAI.children.push(TraceEntryNodeForAI.#fromTraceEntryTree(child, selectedEntryNode));
72
+ }
73
+ return nodeForAI;
74
+ }
75
+ static fromSelectedEntryNode(selectedEntryNode) {
76
+ function getRoot(node) {
77
+ if (node.parent) {
78
+ return getRoot(node.parent);
79
+ }
80
+ return node;
81
+ }
82
+ return TraceEntryNodeForAI.#fromTraceEntryTree(getRoot(selectedEntryNode), selectedEntryNode);
83
+ }
84
+ static getSelectedNodeForTraceEntryTreeForAI(node) {
85
+ if (node.selected) {
86
+ return node;
87
+ }
88
+ if (!node.children) {
89
+ return null;
90
+ }
91
+ for (const child of node.children) {
92
+ const returnedNode = TraceEntryNodeForAI.getSelectedNodeForTraceEntryTreeForAI(child);
93
+ if (returnedNode) {
94
+ return returnedNode;
95
+ }
96
+ }
97
+ return null;
98
+ }
99
+ }
18
100
  class TraceEntryNodeIdTag {
19
101
  /* eslint-disable-next-line no-unused-private-class-members */
20
102
  #tag;
@@ -58,7 +140,7 @@ export function treify(entries, options) {
58
140
  // node for it, mark it as a root, then proceed with the next event.
59
141
  if (stack.length === 0) {
60
142
  tree.roots.add(node);
61
- event.selfTime = Types.Timing.MicroSeconds(duration);
143
+ node.selfTime = Types.Timing.MicroSeconds(duration);
62
144
  stack.push(node);
63
145
  tree.maxDepth = Math.max(tree.maxDepth, stack.length);
64
146
  entryToNode.set(event, node);
@@ -112,9 +194,9 @@ export function treify(entries, options) {
112
194
  node.depth = stack.length;
113
195
  node.parent = parentNode;
114
196
  parentNode.children.push(node);
115
- event.selfTime = Types.Timing.MicroSeconds(duration);
116
- if (parentEvent.selfTime !== undefined) {
117
- parentEvent.selfTime = Types.Timing.MicroSeconds(parentEvent.selfTime - (event.dur || 0));
197
+ node.selfTime = Types.Timing.MicroSeconds(duration);
198
+ if (parentNode.selfTime !== undefined) {
199
+ parentNode.selfTime = Types.Timing.MicroSeconds(parentNode.selfTime - (event.dur || 0));
118
200
  }
119
201
  stack.push(node);
120
202
  tree.maxDepth = Math.max(tree.maxDepth, stack.length);
@@ -186,7 +268,7 @@ function walkTreeByNode(entryToNode, rootNode, onEntryStart, onEntryEnd, traceWi
186
268
  return;
187
269
  }
188
270
  if (typeof minDuration !== 'undefined') {
189
- const duration = Types.Timing.MicroSeconds(rootNode.entry.ts + Types.Timing.MicroSeconds(rootNode.entry.dur || 0));
271
+ const duration = Types.Timing.MicroSeconds(rootNode.entry.ts + Types.Timing.MicroSeconds(rootNode.entry.dur ?? 0));
190
272
  if (duration < minDuration) {
191
273
  return;
192
274
  }
@@ -203,21 +285,7 @@ function walkTreeByNode(entryToNode, rootNode, onEntryStart, onEntryEnd, traceWi
203
285
  * have to partially intersect it.
204
286
  */
205
287
  function treeNodeIsInWindow(node, traceWindow) {
206
- const startTime = node.entry.ts;
207
- const endTime = node.entry.ts + (node.entry.dur || 0);
208
- // Min ======= startTime ========= Max => node is within window
209
- if (startTime >= traceWindow.min && startTime < traceWindow.max) {
210
- return true;
211
- }
212
- // Min ======= endTime ========= Max => node is within window
213
- if (endTime > traceWindow.min && endTime <= traceWindow.max) {
214
- return true;
215
- }
216
- // startTime ==== Min ======== Max === endTime => node spans greater than the window so is in it.
217
- if (startTime <= traceWindow.min && endTime >= traceWindow.max) {
218
- return true;
219
- }
220
- return false;
288
+ return eventIsInBounds(node.entry, traceWindow);
221
289
  }
222
290
  /**
223
291
  * Determines if the given events, which are assumed to be ordered can
@@ -242,13 +310,13 @@ export function canBuildTreesFromEvents(events) {
242
310
  const stack = [];
243
311
  for (const event of events) {
244
312
  const startTime = event.ts;
245
- const endTime = event.ts + (event.dur || 0);
313
+ const endTime = event.ts + (event.dur ?? 0);
246
314
  let parent = stack.at(-1);
247
315
  if (parent === undefined) {
248
316
  stack.push(event);
249
317
  continue;
250
318
  }
251
- let parentEndTime = parent.ts + (parent.dur || 0);
319
+ let parentEndTime = parent.ts + (parent.dur ?? 0);
252
320
  // Discard events that are not parents for this event. The parent
253
321
  // is one whose end time is after this event start time.
254
322
  while (stack.length && startTime >= parentEndTime) {
@@ -257,7 +325,7 @@ export function canBuildTreesFromEvents(events) {
257
325
  if (parent === undefined) {
258
326
  break;
259
327
  }
260
- parentEndTime = parent.ts + (parent.dur || 0);
328
+ parentEndTime = parent.ts + (parent.dur ?? 0);
261
329
  }
262
330
  if (stack.length && endTime > parentEndTime) {
263
331
  // If such an event exists but its end time is before this
@@ -1 +1 @@
1
- {"version":3,"file":"TreeHelpers.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/helpers/TreeHelpers.ts"],"names":[],"mappings":"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","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.\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 =\n (entry: Types.TraceEvents.SyntheticTraceEntry, 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.SyntheticTraceEntry;\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.SyntheticTraceEntry[], options?: {\n filter: {has: (name: Types.TraceEvents.KnownEventName) => boolean},\n}): {tree: TraceEntryTree, entryToNode: Map<Types.TraceEvents.SyntheticTraceEntry, 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.SyntheticTraceEntry, 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.SyntheticTraceEntry, TraceEntryNode>,\n rootEntry: Types.TraceEvents.SyntheticTraceEntry,\n onEntryStart: (entry: Types.TraceEvents.SyntheticTraceEntry) => void,\n onEntryEnd: (entry: Types.TraceEvents.SyntheticTraceEntry) => 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.SyntheticTraceEntry, TraceEntryNode>,\n tree: TraceEntryTree,\n onEntryStart: (entry: Types.TraceEvents.SyntheticTraceEntry) => void,\n onEntryEnd: (entry: Types.TraceEvents.SyntheticTraceEntry) => 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.SyntheticTraceEntry, TraceEntryNode>,\n rootNode: TraceEntryNode,\n onEntryStart: (entry: Types.TraceEvents.SyntheticTraceEntry) => void,\n onEntryEnd: (entry: Types.TraceEvents.SyntheticTraceEntry) => 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\n/**\n * Determines if the given events, which are assumed to be ordered can\n * be organized into tree structures.\n * This condition is met if there is *not* a pair of async events\n * e1 and e2 where:\n *\n * e1.startTime < e2.startTime && e1.endTime > e2.startTime && e1.endTime < e2.endTime.\n * or, graphically:\n * |------- e1 ------|\n * |------- e2 --------|\n *\n * Because a parent-child relationship cannot be made from the example\n * above, a tree cannot be made from the set of events.\n *\n * Sync events from the same thread are tree-able by definition.\n *\n * Note that this will also return true if multiple trees can be\n * built, for example if none of the events overlap with each other.\n */\nexport function canBuildTreesFromEvents(events: readonly Types.TraceEvents.TraceEventData[]): boolean {\n const stack: Types.TraceEvents.TraceEventData[] = [];\n for (const event of events) {\n const startTime = event.ts;\n const endTime = event.ts + (event.dur || 0);\n let parent = stack.at(-1);\n if (parent === undefined) {\n stack.push(event);\n continue;\n }\n let parentEndTime = parent.ts + (parent.dur || 0);\n // Discard events that are not parents for this event. The parent\n // is one whose end time is after this event start time.\n while (stack.length && startTime >= parentEndTime) {\n stack.pop();\n parent = stack.at(-1);\n\n if (parent === undefined) {\n break;\n }\n parentEndTime = parent.ts + (parent.dur || 0);\n }\n if (stack.length && endTime > parentEndTime) {\n // If such an event exists but its end time is before this\n // event's end time, then a tree cannot be made using this\n // events.\n return false;\n }\n stack.push(event);\n }\n return true;\n}\n"]}
1
+ {"version":3,"file":"TreeHelpers.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/helpers/TreeHelpers.ts"],"names":[],"mappings":"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","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.\n\nimport * as Types from '../types/types.js';\n\nimport {eventIsInBounds, microSecondsToMilliseconds} from './Timing.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.Events.Event, 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.Events.Event;\n depth: number;\n selfTime?: Types.Timing.MicroSeconds;\n id: TraceEntryNodeId;\n parent: TraceEntryNode|null;\n children: TraceEntryNode[];\n}\n\n/**\n * Represents a node in a trace entry tree, simplified for AI Assistance processing.\n */\nexport class TraceEntryNodeForAI {\n id?: TraceEntryNodeId;\n domain?: string;\n line?: number;\n column?: number;\n function?: string;\n children?: TraceEntryNodeForAI[];\n selected?: boolean;\n\n constructor(\n public type: string, public start: Types.Timing.MilliSeconds, public end?: Types.Timing.MilliSeconds,\n public totalTime?: Types.Timing.MilliSeconds, public selfTime?: Types.Timing.MilliSeconds) {\n }\n\n static #fromTraceEvent(event: Types.Events.Event): TraceEntryNodeForAI {\n const start = microSecondsToMilliseconds(event.ts);\n const duration = event.dur === undefined ? undefined : microSecondsToMilliseconds(event.dur);\n const nodeForAI = new TraceEntryNodeForAI(event.name, start, duration);\n if (Types.Events.isProfileCall(event)) {\n nodeForAI.function = event.callFrame.functionName || '(anonymous)';\n try {\n const url = new URL(event.callFrame.url);\n nodeForAI.domain = url.origin;\n nodeForAI.line = event.callFrame.lineNumber;\n nodeForAI.column = event.callFrame.columnNumber;\n } catch (e) {\n }\n }\n return nodeForAI;\n }\n\n /**\n * Builds a TraceEntryNodeForAI tree from a TraceEntryNode tree and marks the selected node.\n */\n static #fromTraceEntryTree(node: TraceEntryNode, selectedEntryNode: TraceEntryNode): TraceEntryNodeForAI {\n const nodeForAI = TraceEntryNodeForAI.#fromTraceEvent(node.entry);\n nodeForAI.id = node.id;\n if (node === selectedEntryNode) {\n nodeForAI.selected = true;\n }\n nodeForAI.selfTime = node.selfTime === undefined ? undefined : microSecondsToMilliseconds(node.selfTime);\n for (const child of node.children) {\n nodeForAI.children ??= [];\n nodeForAI.children.push(TraceEntryNodeForAI.#fromTraceEntryTree(child, selectedEntryNode));\n }\n return nodeForAI;\n }\n\n static fromSelectedEntryNode(selectedEntryNode: TraceEntryNode): TraceEntryNodeForAI {\n function getRoot(node: TraceEntryNode): TraceEntryNode {\n if (node.parent) {\n return getRoot(node.parent);\n }\n return node;\n }\n\n return TraceEntryNodeForAI.#fromTraceEntryTree(getRoot(selectedEntryNode), selectedEntryNode);\n }\n\n static getSelectedNodeForTraceEntryTreeForAI(node: TraceEntryNodeForAI): TraceEntryNodeForAI|null {\n if (node.selected) {\n return node;\n }\n if (!node.children) {\n return null;\n }\n for (const child of node.children) {\n const returnedNode = TraceEntryNodeForAI.getSelectedNodeForTraceEntryTreeForAI(child);\n if (returnedNode) {\n return returnedNode;\n }\n }\n return null;\n }\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.Events.Event[], options?: {\n filter: {has: (name: Types.Events.Name) => boolean},\n}): {tree: TraceEntryTree, entryToNode: Map<Types.Events.Event, 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.Events.Event, 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.Events.Name)) {\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 node.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 node.selfTime = Types.Timing.MicroSeconds(duration);\n if (parentNode.selfTime !== undefined) {\n parentNode.selfTime = Types.Timing.MicroSeconds(parentNode.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.Events.Event, TraceEntryNode>,\n rootEntry: Types.Events.Event,\n onEntryStart: (entry: Types.Events.Event) => void,\n onEntryEnd: (entry: Types.Events.Event) => 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.Events.Event, TraceEntryNode>,\n tree: TraceEntryTree,\n onEntryStart: (entry: Types.Events.Event) => void,\n onEntryEnd: (entry: Types.Events.Event) => 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.Events.Event, TraceEntryNode>,\n rootNode: TraceEntryNode,\n onEntryStart: (entry: Types.Events.Event) => void,\n onEntryEnd: (entry: Types.Events.Event) => 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 return eventIsInBounds(node.entry, traceWindow);\n}\n\n/**\n * Determines if the given events, which are assumed to be ordered can\n * be organized into tree structures.\n * This condition is met if there is *not* a pair of async events\n * e1 and e2 where:\n *\n * e1.startTime < e2.startTime && e1.endTime > e2.startTime && e1.endTime < e2.endTime.\n * or, graphically:\n * |------- e1 ------|\n * |------- e2 --------|\n *\n * Because a parent-child relationship cannot be made from the example\n * above, a tree cannot be made from the set of events.\n *\n * Sync events from the same thread are tree-able by definition.\n *\n * Note that this will also return true if multiple trees can be\n * built, for example if none of the events overlap with each other.\n */\nexport function canBuildTreesFromEvents(events: readonly Types.Events.Event[]): boolean {\n const stack: Types.Events.Event[] = [];\n for (const event of events) {\n const startTime = event.ts;\n const endTime = event.ts + (event.dur ?? 0);\n let parent = stack.at(-1);\n if (parent === undefined) {\n stack.push(event);\n continue;\n }\n let parentEndTime = parent.ts + (parent.dur ?? 0);\n // Discard events that are not parents for this event. The parent\n // is one whose end time is after this event start time.\n while (stack.length && startTime >= parentEndTime) {\n stack.pop();\n parent = stack.at(-1);\n\n if (parent === undefined) {\n break;\n }\n parentEndTime = parent.ts + (parent.dur ?? 0);\n }\n if (stack.length && endTime > parentEndTime) {\n // If such an event exists but its end time is before this\n // event's end time, then a tree cannot be made using this\n // events.\n return false;\n }\n stack.push(event);\n }\n return true;\n}\n"]}
@@ -1,4 +1,10 @@
1
1
  import type * as Handlers from '../handlers/handlers.js';
2
2
  import type * as Types from '../types/types.js';
3
- import { type NavigationInsightContext } from './types.js';
4
- export declare function findLCPRequest(traceData: Pick<Handlers.Types.TraceParseData, 'Meta' | 'NetworkRequests' | 'LargestImagePaint'>, context: NavigationInsightContext, lcpEvent: Types.TraceEvents.TraceEventLargestContentfulPaintCandidate): Types.TraceEvents.SyntheticNetworkRequest | null;
3
+ import type { InsightResults, InsightSetContextWithNavigation, TraceInsightSets } from './types.js';
4
+ export declare function getInsight<InsightName extends keyof InsightResults>(insightName: InsightName, insights: TraceInsightSets | null, key: string | null): InsightResults[InsightName] | null;
5
+ /**
6
+ * Finds a network request given a navigation context and URL.
7
+ * Considers redirects.
8
+ */
9
+ export declare function findRequest(parsedTrace: Pick<Handlers.Types.ParsedTrace, 'Meta' | 'NetworkRequests'>, context: InsightSetContextWithNavigation, url: string): Types.Events.SyntheticNetworkRequest | null;
10
+ export declare function findLCPRequest(parsedTrace: Pick<Handlers.Types.ParsedTrace, 'Meta' | 'NetworkRequests' | 'LargestImagePaint'>, context: InsightSetContextWithNavigation, lcpEvent: Types.Events.LargestContentfulPaintCandidate): Types.Events.SyntheticNetworkRequest | null;
@@ -2,12 +2,42 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
  import * as Helpers from '../helpers/helpers.js';
5
- export function findLCPRequest(traceData, context, lcpEvent) {
5
+ export function getInsight(insightName, insights, key) {
6
+ if (!insights || !key) {
7
+ return null;
8
+ }
9
+ const insightSets = insights.get(key);
10
+ if (!insightSets) {
11
+ return null;
12
+ }
13
+ const insight = insightSets.data[insightName];
14
+ if (insight instanceof Error) {
15
+ return null;
16
+ }
17
+ // For some reason typescript won't narrow the type by removing Error, so do it manually.
18
+ return insight;
19
+ }
20
+ /**
21
+ * Finds a network request given a navigation context and URL.
22
+ * Considers redirects.
23
+ */
24
+ export function findRequest(parsedTrace, context, url) {
25
+ const request = parsedTrace.NetworkRequests.byTime.find(req => {
26
+ const urlMatch = req.args.data.url === url || req.args.data.redirects.some(r => r.url === url);
27
+ if (!urlMatch) {
28
+ return false;
29
+ }
30
+ const nav = Helpers.Trace.getNavigationForTraceEvent(req, context.frameId, parsedTrace.Meta.navigationsByFrameId);
31
+ return nav === context.navigation;
32
+ });
33
+ return request ?? null;
34
+ }
35
+ export function findLCPRequest(parsedTrace, context, lcpEvent) {
6
36
  const lcpNodeId = lcpEvent.args.data?.nodeId;
7
37
  if (!lcpNodeId) {
8
38
  throw new Error('no lcp node id');
9
39
  }
10
- const imagePaint = traceData.LargestImagePaint.get(lcpNodeId);
40
+ const imagePaint = parsedTrace.LargestImagePaint.get(lcpNodeId);
11
41
  if (!imagePaint) {
12
42
  return null;
13
43
  }
@@ -15,11 +45,7 @@ export function findLCPRequest(traceData, context, lcpEvent) {
15
45
  if (!lcpUrl) {
16
46
  throw new Error('no lcp url');
17
47
  }
18
- // Look for the LCP request.
19
- const lcpRequest = traceData.NetworkRequests.byTime.find(req => {
20
- const nav = Helpers.Trace.getNavigationForTraceEvent(req, context.frameId, traceData.Meta.navigationsByFrameId);
21
- return (nav?.args.data?.navigationId === context.navigationId) && (req.args.data.url === lcpUrl);
22
- });
48
+ const lcpRequest = findRequest(parsedTrace, context, lcpUrl);
23
49
  if (!lcpRequest) {
24
50
  throw new Error('no lcp request found');
25
51
  }