@paulirish/trace_engine 0.0.47 → 0.0.49

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 (169) hide show
  1. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  2. package/core/platform/MimeType.js +3 -0
  3. package/core/platform/MimeType.js.map +1 -1
  4. package/core/platform/TypedArrayUtilities.d.ts +2 -1
  5. package/core/platform/TypedArrayUtilities.js +9 -4
  6. package/core/platform/TypedArrayUtilities.js.map +1 -1
  7. package/generated/protocol.d.ts +25 -2
  8. package/locales/af.json +229 -16
  9. package/locales/am.json +231 -18
  10. package/locales/ar.json +229 -16
  11. package/locales/as.json +231 -18
  12. package/locales/az.json +231 -18
  13. package/locales/be.json +228 -15
  14. package/locales/bg.json +229 -16
  15. package/locales/bn.json +229 -16
  16. package/locales/bs.json +229 -16
  17. package/locales/ca.json +229 -16
  18. package/locales/cs.json +228 -15
  19. package/locales/cy.json +231 -18
  20. package/locales/da.json +230 -17
  21. package/locales/de.json +228 -15
  22. package/locales/el.json +229 -16
  23. package/locales/en-GB.json +229 -16
  24. package/locales/en-US.json +30 -3
  25. package/locales/en-XL.json +30 -3
  26. package/locales/es-419.json +229 -16
  27. package/locales/es.json +228 -15
  28. package/locales/et.json +230 -17
  29. package/locales/eu.json +231 -18
  30. package/locales/fa.json +230 -17
  31. package/locales/fi.json +229 -16
  32. package/locales/fil.json +231 -18
  33. package/locales/fr-CA.json +230 -17
  34. package/locales/fr.json +230 -17
  35. package/locales/gl.json +228 -15
  36. package/locales/gu.json +230 -17
  37. package/locales/he.json +229 -16
  38. package/locales/hi.json +230 -17
  39. package/locales/hr.json +229 -16
  40. package/locales/hu.json +229 -16
  41. package/locales/hy.json +228 -15
  42. package/locales/id.json +228 -15
  43. package/locales/is.json +229 -16
  44. package/locales/it.json +232 -19
  45. package/locales/ja.json +228 -15
  46. package/locales/ka.json +230 -17
  47. package/locales/kk.json +230 -17
  48. package/locales/km.json +231 -18
  49. package/locales/kn.json +228 -15
  50. package/locales/ko.json +229 -16
  51. package/locales/ky.json +230 -17
  52. package/locales/lo.json +229 -16
  53. package/locales/lt.json +229 -16
  54. package/locales/lv.json +230 -17
  55. package/locales/mk.json +229 -16
  56. package/locales/ml.json +230 -17
  57. package/locales/mn.json +229 -16
  58. package/locales/mr.json +230 -17
  59. package/locales/ms.json +229 -16
  60. package/locales/my.json +231 -18
  61. package/locales/ne.json +229 -16
  62. package/locales/nl.json +229 -16
  63. package/locales/no.json +229 -16
  64. package/locales/or.json +231 -18
  65. package/locales/pa.json +228 -15
  66. package/locales/pl.json +230 -17
  67. package/locales/pt-PT.json +229 -16
  68. package/locales/pt.json +229 -16
  69. package/locales/ro.json +228 -15
  70. package/locales/ru.json +230 -17
  71. package/locales/si.json +231 -18
  72. package/locales/sk.json +229 -16
  73. package/locales/sl.json +230 -17
  74. package/locales/sq.json +229 -16
  75. package/locales/sr-Latn.json +229 -16
  76. package/locales/sr.json +229 -16
  77. package/locales/sv.json +229 -16
  78. package/locales/sw.json +231 -18
  79. package/locales/ta.json +230 -17
  80. package/locales/te.json +231 -18
  81. package/locales/th.json +229 -16
  82. package/locales/tr.json +230 -17
  83. package/locales/uk.json +229 -16
  84. package/locales/ur.json +230 -17
  85. package/locales/uz.json +229 -16
  86. package/locales/vi.json +230 -17
  87. package/locales/zh-HK.json +229 -16
  88. package/locales/zh-TW.json +230 -17
  89. package/locales/zh.json +228 -15
  90. package/locales/zu.json +230 -17
  91. package/models/trace/Processor.js +40 -11
  92. package/models/trace/Processor.js.map +1 -1
  93. package/models/trace/extras/ScriptDuplication.d.ts +27 -8
  94. package/models/trace/extras/ScriptDuplication.js +27 -26
  95. package/models/trace/extras/ScriptDuplication.js.map +1 -1
  96. package/models/trace/extras/StackTraceForEvent.js +7 -0
  97. package/models/trace/extras/StackTraceForEvent.js.map +1 -1
  98. package/models/trace/handlers/ExtensionTraceDataHandler.js +14 -9
  99. package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
  100. package/models/trace/handlers/LargestImagePaintHandler.d.ts +1 -1
  101. package/models/trace/handlers/LargestImagePaintHandler.js +3 -3
  102. package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
  103. package/models/trace/handlers/MetaHandler.d.ts +13 -0
  104. package/models/trace/handlers/MetaHandler.js +34 -1
  105. package/models/trace/handlers/MetaHandler.js.map +1 -1
  106. package/models/trace/helpers/Network.d.ts +18 -0
  107. package/models/trace/helpers/Network.js +57 -0
  108. package/models/trace/helpers/Network.js.map +1 -1
  109. package/models/trace/helpers/SamplesIntegrator.js +1 -1
  110. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  111. package/models/trace/helpers/Trace.js +4 -0
  112. package/models/trace/helpers/Trace.js.map +1 -1
  113. package/models/trace/insights/CLSCulprits.js +0 -1
  114. package/models/trace/insights/CLSCulprits.js.map +1 -1
  115. package/models/trace/insights/DOMSize.js +0 -1
  116. package/models/trace/insights/DOMSize.js.map +1 -1
  117. package/models/trace/insights/DocumentLatency.d.ts +2 -1
  118. package/models/trace/insights/DocumentLatency.js +5 -3
  119. package/models/trace/insights/DocumentLatency.js.map +1 -1
  120. package/models/trace/insights/{DuplicateJavaScript.d.ts → DuplicatedJavaScript.d.ts} +6 -1
  121. package/models/trace/insights/{DuplicateJavaScript.js → DuplicatedJavaScript.js} +15 -6
  122. package/models/trace/insights/DuplicatedJavaScript.js.map +1 -0
  123. package/models/trace/insights/FontDisplay.d.ts +1 -2
  124. package/models/trace/insights/FontDisplay.js +0 -1
  125. package/models/trace/insights/FontDisplay.js.map +1 -1
  126. package/models/trace/insights/ForcedReflow.d.ts +22 -2
  127. package/models/trace/insights/ForcedReflow.js +62 -107
  128. package/models/trace/insights/ForcedReflow.js.map +1 -1
  129. package/models/trace/insights/ImageDelivery.js +0 -1
  130. package/models/trace/insights/ImageDelivery.js.map +1 -1
  131. package/models/trace/insights/InteractionToNextPaint.js +1 -4
  132. package/models/trace/insights/InteractionToNextPaint.js.map +1 -1
  133. package/models/trace/insights/LCPDiscovery.js +5 -8
  134. package/models/trace/insights/LCPDiscovery.js.map +1 -1
  135. package/models/trace/insights/LCPPhases.js +4 -8
  136. package/models/trace/insights/LCPPhases.js.map +1 -1
  137. package/models/trace/insights/Models.d.ts +2 -1
  138. package/models/trace/insights/Models.js +2 -1
  139. package/models/trace/insights/Models.js.map +1 -1
  140. package/models/trace/insights/NetworkDependencyTree.d.ts +2 -1
  141. package/models/trace/insights/NetworkDependencyTree.js +9 -6
  142. package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
  143. package/models/trace/insights/RenderBlocking.js +1 -4
  144. package/models/trace/insights/RenderBlocking.js.map +1 -1
  145. package/models/trace/insights/SlowCSSSelector.js +0 -1
  146. package/models/trace/insights/SlowCSSSelector.js.map +1 -1
  147. package/models/trace/insights/Statistics.d.ts +4 -0
  148. package/models/trace/insights/Statistics.js +7 -0
  149. package/models/trace/insights/Statistics.js.map +1 -1
  150. package/models/trace/insights/ThirdParties.js +0 -1
  151. package/models/trace/insights/ThirdParties.js.map +1 -1
  152. package/models/trace/insights/UseCache.d.ts +69 -0
  153. package/models/trace/insights/UseCache.js +189 -0
  154. package/models/trace/insights/UseCache.js.map +1 -0
  155. package/models/trace/insights/Viewport.js +0 -3
  156. package/models/trace/insights/Viewport.js.map +1 -1
  157. package/models/trace/insights/insights-tsconfig.json +2 -1
  158. package/models/trace/insights/types.d.ts +3 -15
  159. package/models/trace/insights/types.js.map +1 -1
  160. package/models/trace/lantern/types/types-tsconfig.json +1 -1
  161. package/models/trace/types/Configuration.d.ts +6 -0
  162. package/models/trace/types/Configuration.js.map +1 -1
  163. package/models/trace/types/TraceEvents.d.ts +16 -4
  164. package/models/trace/types/TraceEvents.js +4 -1
  165. package/models/trace/types/TraceEvents.js.map +1 -1
  166. package/models/trace/types/types-tsconfig.json +3 -0
  167. package/package.json +1 -1
  168. package/test/test-trace-engine.mjs +2 -1
  169. package/models/trace/insights/DuplicateJavaScript.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Processor.js","sourceRoot":"","sources":["../../../../../../front_end/models/trace/Processor.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 Handlers from './handlers/handlers.js';\nimport * as Helpers from './helpers/helpers.js';\nimport * as Insights from './insights/insights.js';\nimport * as Lantern from './lantern/lantern.js';\nimport * as LanternComputationData from './LanternComputationData.js';\nimport type * as Model from './ModelImpl.js';\nimport * as Types from './types/types.js';\n\nconst enum Status {\n IDLE = 'IDLE',\n PARSING = 'PARSING',\n FINISHED_PARSING = 'FINISHED_PARSING',\n ERRORED_WHILE_PARSING = 'ERRORED_WHILE_PARSING',\n}\n\nexport class TraceParseProgressEvent extends Event {\n static readonly eventName = 'traceparseprogress';\n constructor(public data: Model.TraceParseEventProgressData, init: EventInit = {bubbles: true}) {\n super(TraceParseProgressEvent.eventName, init);\n }\n}\n\n/**\n * Parsing a trace can take time. On large traces we see a breakdown of time like so:\n * - handleEvent() loop: ~20%\n * - finalize() loop: ~60%\n * - shallowClone calls: ~20%\n * The numbers below are set so we can report a progress percentage of [0...1]\n */\nconst enum ProgressPhase {\n HANDLE_EVENT = 0.2,\n FINALIZE = 0.8,\n CLONE = 1.0,\n}\nfunction calculateProgress(value: number, phase: ProgressPhase): number {\n // Finalize values should be [0.2...0.8]\n if (phase === ProgressPhase.FINALIZE) {\n return (value * (ProgressPhase.FINALIZE - ProgressPhase.HANDLE_EVENT)) + ProgressPhase.HANDLE_EVENT;\n }\n return value * phase;\n}\n\ndeclare global {\n interface HTMLElementEventMap {\n [TraceParseProgressEvent.eventName]: TraceParseProgressEvent;\n }\n}\n\nexport class TraceProcessor extends EventTarget {\n // We force the Meta handler to be enabled, so the TraceHandlers type here is\n // the model handlers the user passes in and the Meta handler.\n readonly #traceHandlers: Partial<Handlers.Types.Handlers>;\n #status = Status.IDLE;\n #modelConfiguration = Types.Configuration.defaults();\n #data: Handlers.Types.ParsedTrace|null = null;\n #insights: Insights.Types.TraceInsightSets|null = null;\n\n static createWithAllHandlers(): TraceProcessor {\n return new TraceProcessor(Handlers.ModelHandlers, Types.Configuration.defaults());\n }\n\n /**\n * This function is kept for testing with `stub`.\n */\n static getInsightRunners(): Insights.Types.InsightModelsType {\n return {...Insights.Models};\n }\n\n constructor(traceHandlers: Partial<Handlers.Types.Handlers>, modelConfiguration?: Types.Configuration.Configuration) {\n super();\n\n this.#verifyHandlers(traceHandlers);\n this.#traceHandlers = {\n Meta: Handlers.ModelHandlers.Meta,\n ...traceHandlers,\n };\n if (modelConfiguration) {\n this.#modelConfiguration = modelConfiguration;\n }\n this.#passConfigToHandlers();\n }\n\n #passConfigToHandlers(): void {\n for (const handler of Object.values(this.#traceHandlers)) {\n // Bit of an odd double check, but without this TypeScript refuses to let\n // you call the function as it thinks it might be undefined.\n if ('handleUserConfig' in handler && handler.handleUserConfig) {\n handler.handleUserConfig(this.#modelConfiguration);\n }\n }\n }\n\n /**\n * When the user passes in a set of handlers, we want to ensure that we have all\n * the required handlers. Handlers can depend on other handlers, so if the user\n * passes in FooHandler which depends on BarHandler, they must also pass in\n * BarHandler too. This method verifies that all dependencies are met, and\n * throws if not.\n **/\n #verifyHandlers(providedHandlers: Partial<Handlers.Types.Handlers>): void {\n // Tiny optimisation: if the amount of provided handlers matches the amount\n // of handlers in the Handlers.ModelHandlers object, that means that the\n // user has passed in every handler we have. So therefore they cannot have\n // missed any, and there is no need to iterate through the handlers and\n // check the dependencies.\n if (Object.keys(providedHandlers).length === Object.keys(Handlers.ModelHandlers).length) {\n return;\n }\n const requiredHandlerKeys = new Set<Handlers.Types.HandlerName>();\n for (const [handlerName, handler] of Object.entries(providedHandlers)) {\n requiredHandlerKeys.add(handlerName as Handlers.Types.HandlerName);\n const deps = 'deps' in handler ? handler.deps() : [];\n for (const depName of deps) {\n requiredHandlerKeys.add(depName);\n }\n }\n\n const providedHandlerKeys = new Set(Object.keys(providedHandlers));\n // We always force the Meta handler to be enabled when creating the\n // Processor, so if it is missing from the set the user gave us that is OK,\n // as we will have enabled it anyway.\n requiredHandlerKeys.delete('Meta');\n\n for (const requiredKey of requiredHandlerKeys) {\n if (!providedHandlerKeys.has(requiredKey)) {\n throw new Error(`Required handler ${requiredKey} not provided.`);\n }\n }\n }\n\n reset(): void {\n if (this.#status === Status.PARSING) {\n throw new Error('Trace processor can\\'t reset while parsing.');\n }\n\n const handlers = Object.values(this.#traceHandlers);\n for (const handler of handlers) {\n handler.reset();\n }\n\n this.#data = null;\n this.#insights = null;\n this.#status = Status.IDLE;\n }\n\n async parse(traceEvents: readonly Types.Events.Event[], options: Types.Configuration.ParseOptions): Promise<void> {\n if (this.#status !== Status.IDLE) {\n throw new Error(`Trace processor can't start parsing when not idle. Current state: ${this.#status}`);\n }\n try {\n this.#status = Status.PARSING;\n await this.#computeParsedTrace(traceEvents, options);\n if (this.#data && !options.isCPUProfile) { // We do not calculate insights for CPU Profiles.\n this.#computeInsights(this.#data, traceEvents, options);\n }\n this.#status = Status.FINISHED_PARSING;\n } catch (e) {\n this.#status = Status.ERRORED_WHILE_PARSING;\n throw e;\n }\n }\n\n /**\n * Run all the handlers and set the result to `#data`.\n */\n async #computeParsedTrace(traceEvents: readonly Types.Events.Event[], options: Types.Configuration.ParseOptions):\n Promise<void> {\n /**\n * We want to yield regularly to maintain responsiveness. If we yield too often, we're wasting idle time.\n * We could do this by checking `performance.now()` regularly, but it's an expensive call in such a hot loop.\n * `eventsPerChunk` is an approximated proxy metric.\n * But how big a chunk? We're aiming for long tasks that are no smaller than 100ms and not bigger than 200ms.\n * It's CPU dependent, so it should be calibrated on oldish hardware.\n * Illustration of a previous change to `eventsPerChunk`: https://imgur.com/wzp8BnR\n */\n const eventsPerChunk = 50_000;\n // Convert to array so that we are able to iterate all handlers multiple times.\n const sortedHandlers = [...sortHandlers(this.#traceHandlers).values()];\n\n // Reset.\n for (const handler of sortedHandlers) {\n handler.reset();\n }\n\n // Handle each event.\n for (let i = 0; i < traceEvents.length; ++i) {\n // Every so often we take a break just to render.\n if (i % eventsPerChunk === 0 && i) {\n // Take the opportunity to provide status update events.\n const percent = calculateProgress(i / traceEvents.length, ProgressPhase.HANDLE_EVENT);\n this.dispatchEvent(new TraceParseProgressEvent({percent}));\n // TODO(paulirish): consider using `scheduler.yield()` or `scheduler.postTask(() => {}, {priority: 'user-blocking'})`\n await new Promise(resolve => setTimeout(resolve, 0));\n }\n const event = traceEvents[i];\n for (let j = 0; j < sortedHandlers.length; ++j) {\n sortedHandlers[j].handleEvent(event);\n }\n }\n\n // Finalize.\n for (const [i, handler] of sortedHandlers.entries()) {\n if (handler.finalize) {\n // Yield to the UI because finalize() calls can be expensive\n // TODO(jacktfranklin): consider using `scheduler.yield()` or `scheduler.postTask(() => {}, {priority: 'user-blocking'})`\n await new Promise(resolve => setTimeout(resolve, 0));\n await handler.finalize(options);\n }\n const percent = calculateProgress(i / sortedHandlers.length, ProgressPhase.FINALIZE);\n this.dispatchEvent(new TraceParseProgressEvent({percent}));\n }\n\n // Handlers that depend on other handlers do so via .data(), which used to always\n // return a shallow clone of its internal data structures. However, that pattern\n // easily results in egregious amounts of allocation. Now .data() does not do any\n // cloning, and it happens here instead so that users of the trace processor may\n // still assume that the parsed data is theirs.\n // See: crbug/41484172\n const shallowClone = (value: unknown, recurse = true): unknown => {\n if (value instanceof Map) {\n return new Map(value);\n }\n if (value instanceof Set) {\n return new Set(value);\n }\n if (Array.isArray(value)) {\n return [...value];\n }\n if (typeof value === 'object' && value && recurse) {\n const obj: Record<string, unknown> = {};\n for (const [key, v] of Object.entries(value)) {\n obj[key] = shallowClone(v, false);\n }\n return obj;\n }\n return value;\n };\n\n const parsedTrace = {};\n for (const [name, handler] of Object.entries(this.#traceHandlers)) {\n const data = shallowClone(handler.data());\n Object.assign(parsedTrace, {[name]: data});\n }\n this.dispatchEvent(new TraceParseProgressEvent({percent: ProgressPhase.CLONE}));\n\n this.#data = parsedTrace as Handlers.Types.ParsedTrace;\n }\n\n get parsedTrace(): Handlers.Types.ParsedTrace|null {\n if (this.#status !== Status.FINISHED_PARSING) {\n return null;\n }\n\n return this.#data;\n }\n\n get insights(): Insights.Types.TraceInsightSets|null {\n if (this.#status !== Status.FINISHED_PARSING) {\n return null;\n }\n\n return this.#insights;\n }\n\n #createLanternContext(\n parsedTrace: Handlers.Types.ParsedTrace, traceEvents: readonly Types.Events.Event[], frameId: string,\n navigationId: string): Insights.Types.LanternContext|undefined {\n // Check for required handlers.\n if (!parsedTrace.NetworkRequests || !parsedTrace.Workers || !parsedTrace.PageLoadMetrics) {\n return;\n }\n if (!parsedTrace.NetworkRequests.byTime.length) {\n throw new Lantern.Core.LanternError('No network requests found in trace');\n }\n\n const navStarts = parsedTrace.Meta.navigationsByFrameId.get(frameId);\n const navStartIndex = navStarts?.findIndex(n => n.args.data?.navigationId === navigationId);\n if (!navStarts || navStartIndex === undefined || navStartIndex === -1) {\n throw new Lantern.Core.LanternError('Could not find navigation start');\n }\n\n const startTime = navStarts[navStartIndex].ts;\n const endTime = navStartIndex + 1 < navStarts.length ? navStarts[navStartIndex + 1].ts : Number.POSITIVE_INFINITY;\n const boundedTraceEvents = traceEvents.filter(e => e.ts >= startTime && e.ts < endTime);\n\n // Lantern.Types.TraceEvent and Types.Events.Event represent the same\n // object - a trace event - but one is more flexible than the other. It should be safe to cast between them.\n const trace: Lantern.Types.Trace = {\n traceEvents: boundedTraceEvents as unknown as Lantern.Types.TraceEvent[],\n };\n\n const requests = LanternComputationData.createNetworkRequests(trace, parsedTrace, startTime, endTime);\n const graph = LanternComputationData.createGraph(requests, trace, parsedTrace);\n const processedNavigation = LanternComputationData.createProcessedNavigation(parsedTrace, frameId, navigationId);\n\n const networkAnalysis = Lantern.Core.NetworkAnalyzer.analyze(requests);\n if (!networkAnalysis) {\n return;\n }\n\n const simulator: Lantern.Simulation.Simulator<Types.Events.SyntheticNetworkRequest> =\n Lantern.Simulation.Simulator.createSimulator({\n // TODO(crbug.com/372674229): if devtools throttling was on, does this network analysis capture\n // that? Do we need to set 'devtools' throttlingMethod?\n networkAnalysis,\n throttlingMethod: 'provided',\n });\n\n const computeData = {graph, simulator, processedNavigation};\n const fcpResult = Lantern.Metrics.FirstContentfulPaint.compute(computeData);\n const lcpResult = Lantern.Metrics.LargestContentfulPaint.compute(computeData, {fcpResult});\n const interactiveResult = Lantern.Metrics.Interactive.compute(computeData, {lcpResult});\n const tbtResult = Lantern.Metrics.TotalBlockingTime.compute(computeData, {fcpResult, interactiveResult});\n const metrics = {\n firstContentfulPaint: fcpResult,\n interactive: interactiveResult,\n largestContentfulPaint: lcpResult,\n totalBlockingTime: tbtResult,\n };\n\n return {graph, simulator, metrics};\n }\n\n /**\n * Sort the insight models based on the impact of each insight's estimated savings, additionally weighted by the\n * worst metrics according to field data (if present).\n */\n sortInsightSet(\n insights: Insights.Types.TraceInsightSets, insightSet: Insights.Types.InsightSet,\n metadata: Types.File.MetaData|null): void {\n // The initial order of the insights is alphabetical, based on `front_end/models/trace/insights/Models.ts`.\n // The order here provides a baseline that groups insights in a more logical way.\n const baselineOrder: Record<keyof Insights.Types.InsightModels, null> = {\n InteractionToNextPaint: null,\n LCPPhases: null,\n LCPDiscovery: null,\n CLSCulprits: null,\n RenderBlocking: null,\n NetworkDependencyTree: null,\n ImageDelivery: null,\n DocumentLatency: null,\n FontDisplay: null,\n Viewport: null,\n DOMSize: null,\n ThirdParties: null,\n DuplicateJavaScript: null,\n SlowCSSSelector: null,\n ForcedReflow: null,\n };\n\n // Determine the weights for each metric based on field data, utilizing the same scoring curve that Lighthouse uses.\n const weights = Insights.Common.calculateMetricWeightsForSorting(insightSet, metadata);\n\n // Normalize the estimated savings to a single number, weighted by its relative impact\n // to the page experience based on the same scoring curve that Lighthouse uses.\n const observedLcp = Insights.Common.getLCP(insights, insightSet.id)?.value;\n const observedCls = Insights.Common.getCLS(insights, insightSet.id).value;\n\n // INP is special - if users did not interact with the page, we'll have no INP, but we should still\n // be able to prioritize insights based on this metric. When we observe no interaction, instead use\n // a default value for the baseline INP.\n const observedInp = Insights.Common.getINP(insights, insightSet.id)?.value ?? 200;\n\n const observedLcpScore =\n observedLcp !== undefined ? Insights.Common.evaluateLCPMetricScore(observedLcp) : undefined;\n const observedInpScore = Insights.Common.evaluateINPMetricScore(observedInp);\n const observedClsScore = Insights.Common.evaluateCLSMetricScore(observedCls);\n\n const insightToSortingRank = new Map<string, number>();\n for (const [name, model] of Object.entries(insightSet.model)) {\n const lcp = model.metricSavings?.LCP ?? 0;\n const inp = model.metricSavings?.INP ?? 0;\n const cls = model.metricSavings?.CLS ?? 0;\n\n const lcpPostSavings = observedLcp !== undefined ? Math.max(0, observedLcp - lcp) : undefined;\n const inpPostSavings = Math.max(0, observedInp - inp);\n const clsPostSavings = Math.max(0, observedCls - cls);\n\n let score = 0;\n if (weights.lcp && lcp && observedLcpScore !== undefined && lcpPostSavings !== undefined) {\n score += weights.lcp * (Insights.Common.evaluateLCPMetricScore(lcpPostSavings) - observedLcpScore);\n }\n if (weights.inp && inp && observedInpScore !== undefined) {\n score += weights.inp * (Insights.Common.evaluateINPMetricScore(inpPostSavings) - observedInpScore);\n }\n if (weights.cls && cls && observedClsScore !== undefined) {\n score += weights.cls * (Insights.Common.evaluateCLSMetricScore(clsPostSavings) - observedClsScore);\n }\n\n insightToSortingRank.set(name, score);\n }\n\n // Now perform the actual sorting.\n const baselineOrderKeys = Object.keys(baselineOrder);\n const orderedKeys = Object.keys(insightSet.model);\n orderedKeys.sort((a, b) => {\n const a1 = baselineOrderKeys.indexOf(a);\n const b1 = baselineOrderKeys.indexOf(b);\n if (a1 >= 0 && b1 >= 0) {\n return a1 - b1;\n }\n if (a1 >= 0) {\n return -1;\n }\n if (b1 >= 0) {\n return 1;\n }\n return 0;\n });\n orderedKeys.sort((a, b) => (insightToSortingRank.get(b) ?? 0) - (insightToSortingRank.get(a) ?? 0));\n\n const newModel = {} as Insights.Types.InsightModels;\n for (const key of orderedKeys as Array<keyof Insights.Types.InsightModels>) {\n const model = insightSet.model[key];\n // @ts-expect-error Maybe someday typescript will be powerful enough to handle this.\n newModel[key] = model;\n }\n insightSet.model = newModel;\n }\n\n #computeInsightSet(\n insights: Insights.Types.TraceInsightSets, parsedTrace: Handlers.Types.ParsedTrace,\n context: Insights.Types.InsightSetContext, options: Types.Configuration.ParseOptions): void {\n let id, urlString, navigation;\n if (context.navigation) {\n id = context.navigationId;\n urlString = context.navigation.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;\n navigation = context.navigation;\n } else {\n id = Types.Events.NO_NAVIGATION;\n urlString = parsedTrace.Meta.mainFrameURL;\n }\n\n const model = {} as Insights.Types.InsightSet['model'];\n\n for (const [name, insight] of Object.entries(TraceProcessor.getInsightRunners())) {\n let insightResult;\n try {\n insightResult = insight.generateInsight(parsedTrace, context);\n const navId = context.navigation?.args.data?.navigationId;\n if (navId) {\n insightResult.navigationId = navId;\n }\n } catch (err) {\n insightResult = err;\n }\n Object.assign(model, {[name]: insightResult});\n }\n\n let url;\n try {\n url = new URL(urlString);\n } catch {\n // We're pretty sure this only happens for our test fixture: missing-url.json.gz. Shouldn't\n // happen for real traces.\n return;\n }\n\n const insightSet: Insights.Types.InsightSet = {\n id,\n url,\n navigation,\n frameId: context.frameId,\n bounds: context.bounds,\n model,\n };\n insights.set(insightSet.id, insightSet);\n this.sortInsightSet(insights, insightSet, options.metadata ?? null);\n }\n\n /**\n * Run all the insights and set the result to `#insights`.\n */\n #computeInsights(\n parsedTrace: Handlers.Types.ParsedTrace, traceEvents: readonly Types.Events.Event[],\n options: Types.Configuration.ParseOptions): void {\n this.#insights = new Map();\n\n const navigations = parsedTrace.Meta.mainFrameNavigations.filter(\n navigation => navigation.args.frame && navigation.args.data?.navigationId);\n\n // Check if there is a meaningful chunk of work happening prior to the first navigation.\n // If so, we run the insights on that initial bounds.\n // Otherwise, there are no navigations and we do a no-navigation insights pass on the entire trace.\n if (navigations.length) {\n const bounds = Helpers.Timing.traceWindowFromMicroSeconds(parsedTrace.Meta.traceBounds.min, navigations[0].ts);\n // When using \"Record and reload\" option, it typically takes ~5ms. So use 50ms to be safe.\n const threshold = Helpers.Timing.milliToMicro(50 as Types.Timing.Milli);\n if (bounds.range > threshold) {\n const context: Insights.Types.InsightSetContext = {\n bounds,\n frameId: parsedTrace.Meta.mainFrameId,\n };\n this.#computeInsightSet(this.#insights, parsedTrace, context, options);\n }\n // If threshold is not met, then the very beginning of the trace is ignored by the insights engine.\n } else {\n const context: Insights.Types.InsightSetContext = {\n bounds: parsedTrace.Meta.traceBounds,\n frameId: parsedTrace.Meta.mainFrameId,\n };\n this.#computeInsightSet(this.#insights, parsedTrace, context, options);\n }\n\n // Now run the insights for each navigation in isolation.\n for (const [i, navigation] of navigations.entries()) {\n // The above filter guarantees these are present.\n const frameId = navigation.args.frame;\n const navigationId = navigation.args.data?.navigationId as string;\n\n // The lantern sub-context is optional on InsightSetContext, so not setting it is OK.\n // This is also a hedge against an error inside Lantern resulting in breaking the entire performance panel.\n // Additionally, many trace fixtures are too old to be processed by Lantern.\n let lantern;\n try {\n lantern = this.#createLanternContext(parsedTrace, traceEvents, frameId, navigationId);\n } catch (e) {\n // Don't allow an error in constructing the Lantern graphs to break the rest of the trace processor.\n // Log unexpected errors, but suppress anything that occurs from a trace being too old.\n // Otherwise tests using old fixtures become way too noisy.\n const expectedErrors = [\n 'mainDocumentRequest not found',\n 'missing metric scores for main frame',\n 'missing metric: FCP',\n 'missing metric: LCP',\n 'No network requests found in trace',\n 'Trace is too old',\n ];\n if (!(e instanceof Lantern.Core.LanternError)) {\n // If this wasn't a managed LanternError, the stack trace is likely needed for debugging.\n console.error(e);\n } else if (!expectedErrors.some(err => e.message === err)) {\n // To reduce noise from tests, only print errors that are not expected to occur because a trace is\n // too old (for which there is no single check).\n console.error(e);\n }\n }\n\n const min = navigation.ts;\n const max = i + 1 < navigations.length ? navigations[i + 1].ts : parsedTrace.Meta.traceBounds.max;\n const bounds = Helpers.Timing.traceWindowFromMicroSeconds(min, max);\n const context: Insights.Types.InsightSetContext = {\n bounds,\n frameId,\n navigation,\n navigationId,\n lantern,\n };\n\n this.#computeInsightSet(this.#insights, parsedTrace, context, options);\n }\n }\n}\n\n/**\n * Some Handlers need data provided by others. Dependencies of a handler handler are\n * declared in the `deps` field.\n * @returns A map from trace event handler name to trace event handler whose entries\n * iterate in such a way that each handler is visited after its dependencies.\n */\nexport function sortHandlers(traceHandlers: Partial<{[key in Handlers.Types.HandlerName]: Handlers.Types.Handler}>):\n Map<Handlers.Types.HandlerName, Handlers.Types.Handler> {\n const sortedMap = new Map<Handlers.Types.HandlerName, Handlers.Types.Handler>();\n const visited = new Set<Handlers.Types.HandlerName>();\n const visitHandler = (handlerName: Handlers.Types.HandlerName): void => {\n if (sortedMap.has(handlerName)) {\n return;\n }\n if (visited.has(handlerName)) {\n let stackPath = '';\n for (const handler of visited) {\n if (stackPath || handler === handlerName) {\n stackPath += `${handler}->`;\n }\n }\n stackPath += handlerName;\n throw new Error(`Found dependency cycle in trace event handlers: ${stackPath}`);\n }\n visited.add(handlerName);\n const handler = traceHandlers[handlerName];\n if (!handler) {\n return;\n }\n const deps = handler.deps?.();\n if (deps) {\n deps.forEach(visitHandler);\n }\n sortedMap.set(handlerName, handler);\n };\n\n for (const handlerName of Object.keys(traceHandlers)) {\n visitHandler(handlerName as Handlers.Types.HandlerName);\n }\n return sortedMap;\n}\n"]}
1
+ {"version":3,"file":"Processor.js","sourceRoot":"","sources":["../../../../../../front_end/models/trace/Processor.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,OAAO,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,OAAO,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,sBAAsB,MAAM,6BAA6B,CAAC;AAEtE,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAS1C,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAE7B;IADnB,MAAM,CAAU,SAAS,GAAG,oBAAoB,CAAC;IACjD,YAAmB,IAAuC,EAAE,OAAkB,EAAC,OAAO,EAAE,IAAI,EAAC;QAC3F,KAAK,CAAC,uBAAuB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAD9B,SAAI,GAAJ,IAAI,CAAmC;IAE1D,CAAC;;AAeH,SAAS,iBAAiB,CAAC,KAAa,EAAE,KAAoB;IAC5D,wCAAwC;IACxC,IAAI,KAAK,qCAA2B,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,GAAG,CAAC,uEAAmD,CAAC,CAAC,uCAA6B,CAAC;IACtG,CAAC;IACD,OAAO,KAAK,GAAG,KAAK,CAAC;AACvB,CAAC;AAQD,MAAM,OAAO,cAAe,SAAQ,WAAW;IAC7C,6EAA6E;IAC7E,8DAA8D;IACrD,cAAc,CAAmC;IAC1D,OAAO,4BAAe;IACtB,mBAAmB,GAAG,KAAK,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC;IACrD,KAAK,GAAoC,IAAI,CAAC;IAC9C,SAAS,GAAyC,IAAI,CAAC;IAEvD,MAAM,CAAC,qBAAqB;QAC1B,OAAO,IAAI,cAAc,CAAC,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpF,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,iBAAiB;QACtB,OAAO,EAAC,GAAG,QAAQ,CAAC,MAAM,EAAC,CAAC;IAC9B,CAAC;IAED,YAAY,aAA+C,EAAE,kBAAsD;QACjH,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;QACpC,IAAI,CAAC,cAAc,GAAG;YACpB,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,IAAI;YACjC,GAAG,aAAa;SACjB,CAAC;QACF,IAAI,kBAAkB,EAAE,CAAC;YACvB,IAAI,CAAC,mBAAmB,GAAG,kBAAkB,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC/B,CAAC;IAED,qBAAqB;QACnB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;YACzD,yEAAyE;YACzE,4DAA4D;YAC5D,IAAI,kBAAkB,IAAI,OAAO,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;gBAC9D,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;QAMI;IACJ,eAAe,CAAC,gBAAkD;QAChE,2EAA2E;QAC3E,wEAAwE;QACxE,0EAA0E;QAC1E,uEAAuE;QACvE,0BAA0B;QAC1B,IAAI,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,CAAC;YACxF,OAAO;QACT,CAAC;QACD,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAA8B,CAAC;QAClE,KAAK,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACtE,mBAAmB,CAAC,GAAG,CAAC,WAAyC,CAAC,CAAC;YACnE,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE,CAAC;gBAC3B,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;QAED,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACnE,mEAAmE;QACnE,2EAA2E;QAC3E,qCAAqC;QACrC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAEnC,KAAK,MAAM,WAAW,IAAI,mBAAmB,EAAE,CAAC;YAC9C,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC1C,MAAM,IAAI,KAAK,CAAC,oBAAoB,WAAW,gBAAgB,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,OAAO,mCAAmB,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACpD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,OAAO,2BAAc,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,WAA0C,EAAE,OAAyC;QAC/F,IAAI,IAAI,CAAC,OAAO,6BAAgB,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,qEAAqE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACvG,CAAC;QAED,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,iCAAiB,CAAC;YAC9B,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAC/B,MAAM,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACrD,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YAC7B,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAE,iDAAiD;gBAC3F,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;gBAClC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;gBACxD,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;YAClC,CAAC;YACD,IAAI,CAAC,OAAO,mDAA0B,CAAC;QACzC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,OAAO,6DAA+B,CAAC;YAC5C,MAAM,CAAC,CAAC;QACV,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,WAA0C,EAAE,OAAyC;QAE7G;;;;;;;WAOG;QACH,MAAM,cAAc,GAAG,MAAM,CAAC;QAC9B,+EAA+E;QAC/E,MAAM,cAAc,GAAG,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAExE,SAAS;QACT,KAAK,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,cAAc,EAAE,CAAC;YACzC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAE3C,qBAAqB;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;YAC5C,iDAAiD;YACjD,IAAI,CAAC,GAAG,cAAc,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClC,wDAAwD;gBACxD,MAAM,OAAO,GAAG,iBAAiB,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,uCAA6B,CAAC;gBACtF,IAAI,CAAC,aAAa,CAAC,IAAI,uBAAuB,CAAC,EAAC,OAAO,EAAC,CAAC,CAAC,CAAC;gBAC3D,qHAAqH;gBACrH,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;gBAC/C,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;gBACtC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,mBAAmB,CAAC,CAAC;QAEzC,YAAY;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YAC1C,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,IAAI,WAAW,CAAC,CAAC;gBAChD,4DAA4D;gBAC5D,yHAAyH;gBACzH,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;gBACrD,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAChC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,SAAS,IAAI,WAAW,CAAC,CAAC;YAChD,CAAC;YACD,MAAM,OAAO,GAAG,iBAAiB,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,mCAAyB,CAAC;YACrF,IAAI,CAAC,aAAa,CAAC,IAAI,uBAAuB,CAAC,EAAC,OAAO,EAAC,CAAC,CAAC,CAAC;QAC7D,CAAC;QAED,iFAAiF;QACjF,gFAAgF;QAChF,iFAAiF;QACjF,gFAAgF;QAChF,+CAA+C;QAC/C,sBAAsB;QACtB,MAAM,YAAY,GAAG,CAAC,KAAc,EAAE,OAAO,GAAG,IAAI,EAAW,EAAE;YAC/D,IAAI,KAAK,YAAY,GAAG,EAAE,CAAC;gBACzB,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;YACD,IAAI,KAAK,YAAY,GAAG,EAAE,CAAC;gBACzB,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;YACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;YACpB,CAAC;YACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,OAAO,EAAE,CAAC;gBAClD,MAAM,GAAG,GAA4B,EAAE,CAAC;gBACxC,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC7C,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;gBACpC,CAAC;gBACD,OAAO,GAAG,CAAC;YACb,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;QAEF,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QACrC,MAAM,WAAW,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YAC1C,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,EAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAC,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;QAEnC,IAAI,CAAC,aAAa,CAAC,IAAI,uBAAuB,CAAC,EAAC,OAAO,6BAAqB,EAAC,CAAC,CAAC,CAAC;QAEhF,IAAI,CAAC,KAAK,GAAG,WAAyC,CAAC;IACzD,CAAC;IAED,IAAI,WAAW;QACb,IAAI,IAAI,CAAC,OAAO,qDAA4B,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,IAAI,QAAQ;QACV,IAAI,IAAI,CAAC,OAAO,qDAA4B,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,qBAAqB,CACjB,WAAuC,EAAE,WAA0C,EAAE,OAAe,EACpG,YAAoB,EAAE,OAAyC;QACjE,+BAA+B;QAC/B,IAAI,CAAC,WAAW,CAAC,eAAe,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,CAAC;YACzF,OAAO;QACT,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YAC/C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,oCAAoC,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrE,MAAM,aAAa,GAAG,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,KAAK,YAAY,CAAC,CAAC;QAC5F,IAAI,CAAC,SAAS,IAAI,aAAa,KAAK,SAAS,IAAI,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,iCAAiC,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,SAAS,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;QAC9C,MAAM,OAAO,GAAG,aAAa,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAClH,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,SAAS,IAAI,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC;QAExF,qEAAqE;QACrE,4GAA4G;QAC5G,MAAM,KAAK,GAAwB;YACjC,WAAW,EAAE,kBAA2D;SACzE,CAAC;QAEF,MAAM,QAAQ,GAAG,sBAAsB,CAAC,qBAAqB,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QACtG,MAAM,KAAK,GAAG,sBAAsB,CAAC,WAAW,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;QAC/E,MAAM,mBAAmB,GAAG,sBAAsB,CAAC,yBAAyB,CAAC,WAAW,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;QAEjH,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvE,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,eAAe,GAAsC;YACzD,+FAA+F;YAC/F,uDAAuD;YACvD,eAAe;YACf,gBAAgB,EAAE,UAAU;YAC5B,GAAG,OAAO,CAAC,eAAe;SAC3B,CAAC;QACF,MAAM,SAAS,GACX,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;QAElE,MAAM,WAAW,GAAG,EAAC,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC5E,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,OAAO,CAAC,WAAW,EAAE,EAAC,SAAS,EAAC,CAAC,CAAC;QAC3F,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,EAAC,SAAS,EAAC,CAAC,CAAC;QACxF,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,WAAW,EAAE,EAAC,SAAS,EAAE,iBAAiB,EAAC,CAAC,CAAC;QACzG,MAAM,OAAO,GAAG;YACd,oBAAoB,EAAE,SAAS;YAC/B,WAAW,EAAE,iBAAiB;YAC9B,sBAAsB,EAAE,SAAS;YACjC,iBAAiB,EAAE,SAAS;SAC7B,CAAC;QAEF,OAAO,EAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAC,CAAC;IACrC,CAAC;IAED;;;OAGG;IACH,cAAc,CACV,QAAyC,EAAE,UAAqC,EAChF,QAAkC;QACpC,2GAA2G;QAC3G,iFAAiF;QACjF,MAAM,aAAa,GAAqD;YACtE,sBAAsB,EAAE,IAAI;YAC5B,SAAS,EAAE,IAAI;YACf,YAAY,EAAE,IAAI;YAClB,WAAW,EAAE,IAAI;YACjB,cAAc,EAAE,IAAI;YACpB,qBAAqB,EAAE,IAAI;YAC3B,aAAa,EAAE,IAAI;YACnB,eAAe,EAAE,IAAI;YACrB,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,IAAI;YACb,YAAY,EAAE,IAAI;YAClB,oBAAoB,EAAE,IAAI;YAC1B,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,IAAI;SACf,CAAC;QAEF,oHAAoH;QACpH,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,gCAAgC,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAEvF,sFAAsF;QACtF,+EAA+E;QAC/E,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;QAC3E,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC;QAE1E,mGAAmG;QACnG,mGAAmG;QACnG,wCAAwC;QACxC,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,GAAG,CAAC;QAElF,MAAM,gBAAgB,GAClB,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAChG,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC;QAC7E,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC;QAE7E,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAkB,CAAC;QACvD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7D,MAAM,GAAG,GAAG,KAAK,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,KAAK,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,KAAK,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAAC;YAE1C,MAAM,cAAc,GAAG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC9F,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,GAAG,CAAC,CAAC;YACtD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,GAAG,CAAC,CAAC;YAEtD,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,IAAI,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI,gBAAgB,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBACzF,KAAK,IAAI,OAAO,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,cAAc,CAAC,GAAG,gBAAgB,CAAC,CAAC;YACrG,CAAC;YACD,IAAI,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;gBACzD,KAAK,IAAI,OAAO,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,cAAc,CAAC,GAAG,gBAAgB,CAAC,CAAC;YACrG,CAAC;YACD,IAAI,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;gBACzD,KAAK,IAAI,OAAO,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,cAAc,CAAC,GAAG,gBAAgB,CAAC,CAAC;YACrG,CAAC;YAED,oBAAoB,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC;QAED,kCAAkC;QAClC,MAAM,iBAAiB,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAClD,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACxB,MAAM,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACxC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACvB,OAAO,EAAE,GAAG,EAAE,CAAC;YACjB,CAAC;YACD,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACZ,OAAO,CAAC,CAAC,CAAC;YACZ,CAAC;YACD,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACZ,OAAO,CAAC,CAAC;YACX,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;QACH,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpG,MAAM,QAAQ,GAAG,EAAkC,CAAC;QACpD,KAAK,MAAM,GAAG,IAAI,WAAwD,EAAE,CAAC;YAC3E,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACpC,oFAAoF;YACpF,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACxB,CAAC;QACD,UAAU,CAAC,KAAK,GAAG,QAAQ,CAAC;IAC9B,CAAC;IAED,kBAAkB,CACd,QAAyC,EAAE,WAAuC,EAClF,OAAyC,EAAE,OAAyC;QACtF,IAAI,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC;QAC9B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;YAC1B,SAAS;gBACL,WAAW,CAAC,IAAI,CAAC,6BAA6B,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC;YAC9G,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC;YAChC,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,6BAA6B,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC;QACtG,CAAC;QAED,MAAM,KAAK,GAAG,EAAwC,CAAC;QAEvD,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,iBAAiB,EAAE,CAAC,EAAE,CAAC;YACjF,IAAI,aAAa,CAAC;YAClB,IAAI,CAAC;gBACH,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;gBAC1C,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBAC9D,aAAa,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;gBACxC,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;gBAC1D,IAAI,KAAK,EAAE,CAAC;oBACV,aAAa,CAAC,YAAY,GAAG,KAAK,CAAC;gBACrC,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,aAAa,GAAG,GAAG,CAAC;YACtB,CAAC;oBAAS,CAAC;gBACT,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;YAC1C,CAAC;YACD,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,EAAC,CAAC,IAAI,CAAC,EAAE,aAAa,EAAC,CAAC,CAAC;QAChD,CAAC;QAED,IAAI,GAAG,CAAC;QACR,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,2FAA2F;YAC3F,0BAA0B;YAC1B,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAA8B;YAC5C,EAAE;YACF,GAAG;YACH,UAAU;YACV,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK;SACN,CAAC;QACF,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QACxC,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;IACtE,CAAC;IAED;;OAEG;IACH,gBAAgB,CACZ,WAAuC,EAAE,WAA0C,EACnF,OAAyC;QAC3C,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;QAE3B,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAC5D,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAE/E,wFAAwF;QACxF,qDAAqD;QACrD,mGAAmG;QACnG,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,2BAA2B,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC/G,0FAA0F;YAC1F,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,EAAwB,CAAC,CAAC;YACxE,IAAI,MAAM,CAAC,KAAK,GAAG,SAAS,EAAE,CAAC;gBAC7B,MAAM,OAAO,GAAqC;oBAChD,MAAM;oBACN,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,WAAW;iBACtC,CAAC;gBACF,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YACzE,CAAC;YACD,mGAAmG;QACrG,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAqC;gBAChD,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,WAAW;gBACpC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,WAAW;aACtC,CAAC;YACF,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC;QAED,yDAAyD;QACzD,KAAK,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;YACpD,iDAAiD;YACjD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;YACtC,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,YAAsB,CAAC;YAElE,qFAAqF;YACrF,2GAA2G;YAC3G,4EAA4E;YAC5E,IAAI,OAAO,CAAC;YACZ,IAAI,CAAC;gBACH,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBACvD,OAAO,GAAG,IAAI,CAAC,qBAAqB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;YACjG,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,oGAAoG;gBACpG,uFAAuF;gBACvF,2DAA2D;gBAC3D,MAAM,cAAc,GAAG;oBACrB,+BAA+B;oBAC/B,sCAAsC;oBACtC,qBAAqB;oBACrB,qBAAqB;oBACrB,oCAAoC;oBACpC,kBAAkB;iBACnB,CAAC;gBACF,IAAI,CAAC,CAAC,CAAC,YAAY,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC9C,yFAAyF;oBACzF,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACnB,CAAC;qBAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,GAAG,CAAC,EAAE,CAAC;oBAC1D,kGAAkG;oBAClG,gDAAgD;oBAChD,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,+BAA+B,CAAC,CAAC;YACvD,CAAC;YAED,MAAM,GAAG,GAAG,UAAU,CAAC,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;YAClG,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,2BAA2B,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACpE,MAAM,OAAO,GAAqC;gBAChD,MAAM;gBACN,OAAO;gBACP,UAAU;gBACV,YAAY;gBACZ,OAAO;aACR,CAAC;YAEF,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,aAAqF;IAEhH,MAAM,SAAS,GAAG,IAAI,GAAG,EAAsD,CAAC;IAChF,MAAM,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;IACtD,MAAM,YAAY,GAAG,CAAC,WAAuC,EAAQ,EAAE;QACrE,IAAI,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7B,IAAI,SAAS,GAAG,EAAE,CAAC;YACnB,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;gBAC9B,IAAI,SAAS,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;oBACzC,SAAS,IAAI,GAAG,OAAO,IAAI,CAAC;gBAC9B,CAAC;YACH,CAAC;YACD,SAAS,IAAI,WAAW,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,mDAAmD,SAAS,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAC9B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC7B,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QACrD,YAAY,CAAC,WAAyC,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","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 Handlers from './handlers/handlers.js';\nimport * as Helpers from './helpers/helpers.js';\nimport * as Insights from './insights/insights.js';\nimport * as Lantern from './lantern/lantern.js';\nimport * as LanternComputationData from './LanternComputationData.js';\nimport type * as Model from './ModelImpl.js';\nimport * as Types from './types/types.js';\n\nconst enum Status {\n IDLE = 'IDLE',\n PARSING = 'PARSING',\n FINISHED_PARSING = 'FINISHED_PARSING',\n ERRORED_WHILE_PARSING = 'ERRORED_WHILE_PARSING',\n}\n\nexport class TraceParseProgressEvent extends Event {\n static readonly eventName = 'traceparseprogress';\n constructor(public data: Model.TraceParseEventProgressData, init: EventInit = {bubbles: true}) {\n super(TraceParseProgressEvent.eventName, init);\n }\n}\n\n/**\n * Parsing a trace can take time. On large traces we see a breakdown of time like so:\n * - handleEvent() loop: ~20%\n * - finalize() loop: ~60%\n * - shallowClone calls: ~20%\n * The numbers below are set so we can report a progress percentage of [0...1]\n */\nconst enum ProgressPhase {\n HANDLE_EVENT = 0.2,\n FINALIZE = 0.8,\n CLONE = 1.0,\n}\nfunction calculateProgress(value: number, phase: ProgressPhase): number {\n // Finalize values should be [0.2...0.8]\n if (phase === ProgressPhase.FINALIZE) {\n return (value * (ProgressPhase.FINALIZE - ProgressPhase.HANDLE_EVENT)) + ProgressPhase.HANDLE_EVENT;\n }\n return value * phase;\n}\n\ndeclare global {\n interface HTMLElementEventMap {\n [TraceParseProgressEvent.eventName]: TraceParseProgressEvent;\n }\n}\n\nexport class TraceProcessor extends EventTarget {\n // We force the Meta handler to be enabled, so the TraceHandlers type here is\n // the model handlers the user passes in and the Meta handler.\n readonly #traceHandlers: Partial<Handlers.Types.Handlers>;\n #status = Status.IDLE;\n #modelConfiguration = Types.Configuration.defaults();\n #data: Handlers.Types.ParsedTrace|null = null;\n #insights: Insights.Types.TraceInsightSets|null = null;\n\n static createWithAllHandlers(): TraceProcessor {\n return new TraceProcessor(Handlers.ModelHandlers, Types.Configuration.defaults());\n }\n\n /**\n * This function is kept for testing with `stub`.\n */\n static getInsightRunners(): Insights.Types.InsightModelsType {\n return {...Insights.Models};\n }\n\n constructor(traceHandlers: Partial<Handlers.Types.Handlers>, modelConfiguration?: Types.Configuration.Configuration) {\n super();\n\n this.#verifyHandlers(traceHandlers);\n this.#traceHandlers = {\n Meta: Handlers.ModelHandlers.Meta,\n ...traceHandlers,\n };\n if (modelConfiguration) {\n this.#modelConfiguration = modelConfiguration;\n }\n this.#passConfigToHandlers();\n }\n\n #passConfigToHandlers(): void {\n for (const handler of Object.values(this.#traceHandlers)) {\n // Bit of an odd double check, but without this TypeScript refuses to let\n // you call the function as it thinks it might be undefined.\n if ('handleUserConfig' in handler && handler.handleUserConfig) {\n handler.handleUserConfig(this.#modelConfiguration);\n }\n }\n }\n\n /**\n * When the user passes in a set of handlers, we want to ensure that we have all\n * the required handlers. Handlers can depend on other handlers, so if the user\n * passes in FooHandler which depends on BarHandler, they must also pass in\n * BarHandler too. This method verifies that all dependencies are met, and\n * throws if not.\n **/\n #verifyHandlers(providedHandlers: Partial<Handlers.Types.Handlers>): void {\n // Tiny optimisation: if the amount of provided handlers matches the amount\n // of handlers in the Handlers.ModelHandlers object, that means that the\n // user has passed in every handler we have. So therefore they cannot have\n // missed any, and there is no need to iterate through the handlers and\n // check the dependencies.\n if (Object.keys(providedHandlers).length === Object.keys(Handlers.ModelHandlers).length) {\n return;\n }\n const requiredHandlerKeys = new Set<Handlers.Types.HandlerName>();\n for (const [handlerName, handler] of Object.entries(providedHandlers)) {\n requiredHandlerKeys.add(handlerName as Handlers.Types.HandlerName);\n const deps = 'deps' in handler ? handler.deps() : [];\n for (const depName of deps) {\n requiredHandlerKeys.add(depName);\n }\n }\n\n const providedHandlerKeys = new Set(Object.keys(providedHandlers));\n // We always force the Meta handler to be enabled when creating the\n // Processor, so if it is missing from the set the user gave us that is OK,\n // as we will have enabled it anyway.\n requiredHandlerKeys.delete('Meta');\n\n for (const requiredKey of requiredHandlerKeys) {\n if (!providedHandlerKeys.has(requiredKey)) {\n throw new Error(`Required handler ${requiredKey} not provided.`);\n }\n }\n }\n\n reset(): void {\n if (this.#status === Status.PARSING) {\n throw new Error('Trace processor can\\'t reset while parsing.');\n }\n\n const handlers = Object.values(this.#traceHandlers);\n for (const handler of handlers) {\n handler.reset();\n }\n\n this.#data = null;\n this.#insights = null;\n this.#status = Status.IDLE;\n }\n\n async parse(traceEvents: readonly Types.Events.Event[], options: Types.Configuration.ParseOptions): Promise<void> {\n if (this.#status !== Status.IDLE) {\n throw new Error(`Trace processor can't start parsing when not idle. Current state: ${this.#status}`);\n }\n\n options.logger?.start('total');\n try {\n this.#status = Status.PARSING;\n options.logger?.start('parse');\n await this.#computeParsedTrace(traceEvents, options);\n options.logger?.end('parse');\n if (this.#data && !options.isCPUProfile) { // We do not calculate insights for CPU Profiles.\n options.logger?.start('insights');\n this.#computeInsights(this.#data, traceEvents, options);\n options.logger?.end('insights');\n }\n this.#status = Status.FINISHED_PARSING;\n } catch (e) {\n this.#status = Status.ERRORED_WHILE_PARSING;\n throw e;\n } finally {\n options.logger?.end('total');\n }\n }\n\n /**\n * Run all the handlers and set the result to `#data`.\n */\n async #computeParsedTrace(traceEvents: readonly Types.Events.Event[], options: Types.Configuration.ParseOptions):\n Promise<void> {\n /**\n * We want to yield regularly to maintain responsiveness. If we yield too often, we're wasting idle time.\n * We could do this by checking `performance.now()` regularly, but it's an expensive call in such a hot loop.\n * `eventsPerChunk` is an approximated proxy metric.\n * But how big a chunk? We're aiming for long tasks that are no smaller than 100ms and not bigger than 200ms.\n * It's CPU dependent, so it should be calibrated on oldish hardware.\n * Illustration of a previous change to `eventsPerChunk`: https://imgur.com/wzp8BnR\n */\n const eventsPerChunk = 50_000;\n // Convert to array so that we are able to iterate all handlers multiple times.\n const sortedHandlers = [...sortHandlers(this.#traceHandlers).entries()];\n\n // Reset.\n for (const [, handler] of sortedHandlers) {\n handler.reset();\n }\n\n options.logger?.start('parse:handleEvent');\n\n // Handle each event.\n for (let i = 0; i < traceEvents.length; ++i) {\n // Every so often we take a break just to render.\n if (i % eventsPerChunk === 0 && i) {\n // Take the opportunity to provide status update events.\n const percent = calculateProgress(i / traceEvents.length, ProgressPhase.HANDLE_EVENT);\n this.dispatchEvent(new TraceParseProgressEvent({percent}));\n // TODO(paulirish): consider using `scheduler.yield()` or `scheduler.postTask(() => {}, {priority: 'user-blocking'})`\n await new Promise(resolve => setTimeout(resolve, 0));\n }\n const event = traceEvents[i];\n for (let j = 0; j < sortedHandlers.length; ++j) {\n const [, handler] = sortedHandlers[j];\n handler.handleEvent(event);\n }\n }\n\n options.logger?.end('parse:handleEvent');\n\n // Finalize.\n for (let i = 0; i < sortedHandlers.length; i++) {\n const [name, handler] = sortedHandlers[i];\n if (handler.finalize) {\n options.logger?.start(`parse:${name}:finalize`);\n // Yield to the UI because finalize() calls can be expensive\n // TODO(jacktfranklin): consider using `scheduler.yield()` or `scheduler.postTask(() => {}, {priority: 'user-blocking'})`\n await new Promise(resolve => setTimeout(resolve, 0));\n await handler.finalize(options);\n options.logger?.end(`parse:${name}:finalize`);\n }\n const percent = calculateProgress(i / sortedHandlers.length, ProgressPhase.FINALIZE);\n this.dispatchEvent(new TraceParseProgressEvent({percent}));\n }\n\n // Handlers that depend on other handlers do so via .data(), which used to always\n // return a shallow clone of its internal data structures. However, that pattern\n // easily results in egregious amounts of allocation. Now .data() does not do any\n // cloning, and it happens here instead so that users of the trace processor may\n // still assume that the parsed data is theirs.\n // See: crbug/41484172\n const shallowClone = (value: unknown, recurse = true): unknown => {\n if (value instanceof Map) {\n return new Map(value);\n }\n if (value instanceof Set) {\n return new Set(value);\n }\n if (Array.isArray(value)) {\n return [...value];\n }\n if (typeof value === 'object' && value && recurse) {\n const obj: Record<string, unknown> = {};\n for (const [key, v] of Object.entries(value)) {\n obj[key] = shallowClone(v, false);\n }\n return obj;\n }\n return value;\n };\n\n options.logger?.start('parse:clone');\n const parsedTrace = {};\n for (const [name, handler] of Object.entries(this.#traceHandlers)) {\n const data = shallowClone(handler.data());\n Object.assign(parsedTrace, {[name]: data});\n }\n options.logger?.end('parse:clone');\n\n this.dispatchEvent(new TraceParseProgressEvent({percent: ProgressPhase.CLONE}));\n\n this.#data = parsedTrace as Handlers.Types.ParsedTrace;\n }\n\n get parsedTrace(): Handlers.Types.ParsedTrace|null {\n if (this.#status !== Status.FINISHED_PARSING) {\n return null;\n }\n\n return this.#data;\n }\n\n get insights(): Insights.Types.TraceInsightSets|null {\n if (this.#status !== Status.FINISHED_PARSING) {\n return null;\n }\n\n return this.#insights;\n }\n\n #createLanternContext(\n parsedTrace: Handlers.Types.ParsedTrace, traceEvents: readonly Types.Events.Event[], frameId: string,\n navigationId: string, options: Types.Configuration.ParseOptions): Insights.Types.LanternContext|undefined {\n // Check for required handlers.\n if (!parsedTrace.NetworkRequests || !parsedTrace.Workers || !parsedTrace.PageLoadMetrics) {\n return;\n }\n if (!parsedTrace.NetworkRequests.byTime.length) {\n throw new Lantern.Core.LanternError('No network requests found in trace');\n }\n\n const navStarts = parsedTrace.Meta.navigationsByFrameId.get(frameId);\n const navStartIndex = navStarts?.findIndex(n => n.args.data?.navigationId === navigationId);\n if (!navStarts || navStartIndex === undefined || navStartIndex === -1) {\n throw new Lantern.Core.LanternError('Could not find navigation start');\n }\n\n const startTime = navStarts[navStartIndex].ts;\n const endTime = navStartIndex + 1 < navStarts.length ? navStarts[navStartIndex + 1].ts : Number.POSITIVE_INFINITY;\n const boundedTraceEvents = traceEvents.filter(e => e.ts >= startTime && e.ts < endTime);\n\n // Lantern.Types.TraceEvent and Types.Events.Event represent the same\n // object - a trace event - but one is more flexible than the other. It should be safe to cast between them.\n const trace: Lantern.Types.Trace = {\n traceEvents: boundedTraceEvents as unknown as Lantern.Types.TraceEvent[],\n };\n\n const requests = LanternComputationData.createNetworkRequests(trace, parsedTrace, startTime, endTime);\n const graph = LanternComputationData.createGraph(requests, trace, parsedTrace);\n const processedNavigation = LanternComputationData.createProcessedNavigation(parsedTrace, frameId, navigationId);\n\n const networkAnalysis = Lantern.Core.NetworkAnalyzer.analyze(requests);\n if (!networkAnalysis) {\n return;\n }\n\n const lanternSettings: Lantern.Types.Simulation.Settings = {\n // TODO(crbug.com/372674229): if devtools throttling was on, does this network analysis capture\n // that? Do we need to set 'devtools' throttlingMethod?\n networkAnalysis,\n throttlingMethod: 'provided',\n ...options.lanternSettings,\n };\n const simulator: Lantern.Simulation.Simulator<Types.Events.SyntheticNetworkRequest> =\n Lantern.Simulation.Simulator.createSimulator(lanternSettings);\n\n const computeData = {graph, simulator, processedNavigation};\n const fcpResult = Lantern.Metrics.FirstContentfulPaint.compute(computeData);\n const lcpResult = Lantern.Metrics.LargestContentfulPaint.compute(computeData, {fcpResult});\n const interactiveResult = Lantern.Metrics.Interactive.compute(computeData, {lcpResult});\n const tbtResult = Lantern.Metrics.TotalBlockingTime.compute(computeData, {fcpResult, interactiveResult});\n const metrics = {\n firstContentfulPaint: fcpResult,\n interactive: interactiveResult,\n largestContentfulPaint: lcpResult,\n totalBlockingTime: tbtResult,\n };\n\n return {graph, simulator, metrics};\n }\n\n /**\n * Sort the insight models based on the impact of each insight's estimated savings, additionally weighted by the\n * worst metrics according to field data (if present).\n */\n sortInsightSet(\n insights: Insights.Types.TraceInsightSets, insightSet: Insights.Types.InsightSet,\n metadata: Types.File.MetaData|null): void {\n // The initial order of the insights is alphabetical, based on `front_end/models/trace/insights/Models.ts`.\n // The order here provides a baseline that groups insights in a more logical way.\n const baselineOrder: Record<keyof Insights.Types.InsightModels, null> = {\n InteractionToNextPaint: null,\n LCPPhases: null,\n LCPDiscovery: null,\n CLSCulprits: null,\n RenderBlocking: null,\n NetworkDependencyTree: null,\n ImageDelivery: null,\n DocumentLatency: null,\n FontDisplay: null,\n Viewport: null,\n DOMSize: null,\n ThirdParties: null,\n DuplicatedJavaScript: null,\n SlowCSSSelector: null,\n ForcedReflow: null,\n UseCache: null,\n };\n\n // Determine the weights for each metric based on field data, utilizing the same scoring curve that Lighthouse uses.\n const weights = Insights.Common.calculateMetricWeightsForSorting(insightSet, metadata);\n\n // Normalize the estimated savings to a single number, weighted by its relative impact\n // to the page experience based on the same scoring curve that Lighthouse uses.\n const observedLcp = Insights.Common.getLCP(insights, insightSet.id)?.value;\n const observedCls = Insights.Common.getCLS(insights, insightSet.id).value;\n\n // INP is special - if users did not interact with the page, we'll have no INP, but we should still\n // be able to prioritize insights based on this metric. When we observe no interaction, instead use\n // a default value for the baseline INP.\n const observedInp = Insights.Common.getINP(insights, insightSet.id)?.value ?? 200;\n\n const observedLcpScore =\n observedLcp !== undefined ? Insights.Common.evaluateLCPMetricScore(observedLcp) : undefined;\n const observedInpScore = Insights.Common.evaluateINPMetricScore(observedInp);\n const observedClsScore = Insights.Common.evaluateCLSMetricScore(observedCls);\n\n const insightToSortingRank = new Map<string, number>();\n for (const [name, model] of Object.entries(insightSet.model)) {\n const lcp = model.metricSavings?.LCP ?? 0;\n const inp = model.metricSavings?.INP ?? 0;\n const cls = model.metricSavings?.CLS ?? 0;\n\n const lcpPostSavings = observedLcp !== undefined ? Math.max(0, observedLcp - lcp) : undefined;\n const inpPostSavings = Math.max(0, observedInp - inp);\n const clsPostSavings = Math.max(0, observedCls - cls);\n\n let score = 0;\n if (weights.lcp && lcp && observedLcpScore !== undefined && lcpPostSavings !== undefined) {\n score += weights.lcp * (Insights.Common.evaluateLCPMetricScore(lcpPostSavings) - observedLcpScore);\n }\n if (weights.inp && inp && observedInpScore !== undefined) {\n score += weights.inp * (Insights.Common.evaluateINPMetricScore(inpPostSavings) - observedInpScore);\n }\n if (weights.cls && cls && observedClsScore !== undefined) {\n score += weights.cls * (Insights.Common.evaluateCLSMetricScore(clsPostSavings) - observedClsScore);\n }\n\n insightToSortingRank.set(name, score);\n }\n\n // Now perform the actual sorting.\n const baselineOrderKeys = Object.keys(baselineOrder);\n const orderedKeys = Object.keys(insightSet.model);\n orderedKeys.sort((a, b) => {\n const a1 = baselineOrderKeys.indexOf(a);\n const b1 = baselineOrderKeys.indexOf(b);\n if (a1 >= 0 && b1 >= 0) {\n return a1 - b1;\n }\n if (a1 >= 0) {\n return -1;\n }\n if (b1 >= 0) {\n return 1;\n }\n return 0;\n });\n orderedKeys.sort((a, b) => (insightToSortingRank.get(b) ?? 0) - (insightToSortingRank.get(a) ?? 0));\n\n const newModel = {} as Insights.Types.InsightModels;\n for (const key of orderedKeys as Array<keyof Insights.Types.InsightModels>) {\n const model = insightSet.model[key];\n // @ts-expect-error Maybe someday typescript will be powerful enough to handle this.\n newModel[key] = model;\n }\n insightSet.model = newModel;\n }\n\n #computeInsightSet(\n insights: Insights.Types.TraceInsightSets, parsedTrace: Handlers.Types.ParsedTrace,\n context: Insights.Types.InsightSetContext, options: Types.Configuration.ParseOptions): void {\n let id, urlString, navigation;\n if (context.navigation) {\n id = context.navigationId;\n urlString =\n parsedTrace.Meta.finalDisplayUrlByNavigationId.get(context.navigationId) ?? parsedTrace.Meta.mainFrameURL;\n navigation = context.navigation;\n } else {\n id = Types.Events.NO_NAVIGATION;\n urlString = parsedTrace.Meta.finalDisplayUrlByNavigationId.get('') ?? parsedTrace.Meta.mainFrameURL;\n }\n\n const model = {} as Insights.Types.InsightSet['model'];\n\n for (const [name, insight] of Object.entries(TraceProcessor.getInsightRunners())) {\n let insightResult;\n try {\n options.logger?.start(`insights:${name}`);\n insightResult = insight.generateInsight(parsedTrace, context);\n insightResult.frameId = context.frameId;\n const navId = context.navigation?.args.data?.navigationId;\n if (navId) {\n insightResult.navigationId = navId;\n }\n } catch (err) {\n insightResult = err;\n } finally {\n options.logger?.end(`insights:${name}`);\n }\n Object.assign(model, {[name]: insightResult});\n }\n\n let url;\n try {\n url = new URL(urlString);\n } catch {\n // We're pretty sure this only happens for our test fixture: missing-url.json.gz. Shouldn't\n // happen for real traces.\n return;\n }\n\n const insightSet: Insights.Types.InsightSet = {\n id,\n url,\n navigation,\n frameId: context.frameId,\n bounds: context.bounds,\n model,\n };\n insights.set(insightSet.id, insightSet);\n this.sortInsightSet(insights, insightSet, options.metadata ?? null);\n }\n\n /**\n * Run all the insights and set the result to `#insights`.\n */\n #computeInsights(\n parsedTrace: Handlers.Types.ParsedTrace, traceEvents: readonly Types.Events.Event[],\n options: Types.Configuration.ParseOptions): void {\n this.#insights = new Map();\n\n const navigations = parsedTrace.Meta.mainFrameNavigations.filter(\n navigation => navigation.args.frame && navigation.args.data?.navigationId);\n\n // Check if there is a meaningful chunk of work happening prior to the first navigation.\n // If so, we run the insights on that initial bounds.\n // Otherwise, there are no navigations and we do a no-navigation insights pass on the entire trace.\n if (navigations.length) {\n const bounds = Helpers.Timing.traceWindowFromMicroSeconds(parsedTrace.Meta.traceBounds.min, navigations[0].ts);\n // When using \"Record and reload\" option, it typically takes ~5ms. So use 50ms to be safe.\n const threshold = Helpers.Timing.milliToMicro(50 as Types.Timing.Milli);\n if (bounds.range > threshold) {\n const context: Insights.Types.InsightSetContext = {\n bounds,\n frameId: parsedTrace.Meta.mainFrameId,\n };\n this.#computeInsightSet(this.#insights, parsedTrace, context, options);\n }\n // If threshold is not met, then the very beginning of the trace is ignored by the insights engine.\n } else {\n const context: Insights.Types.InsightSetContext = {\n bounds: parsedTrace.Meta.traceBounds,\n frameId: parsedTrace.Meta.mainFrameId,\n };\n this.#computeInsightSet(this.#insights, parsedTrace, context, options);\n }\n\n // Now run the insights for each navigation in isolation.\n for (const [i, navigation] of navigations.entries()) {\n // The above filter guarantees these are present.\n const frameId = navigation.args.frame;\n const navigationId = navigation.args.data?.navigationId as string;\n\n // The lantern sub-context is optional on InsightSetContext, so not setting it is OK.\n // This is also a hedge against an error inside Lantern resulting in breaking the entire performance panel.\n // Additionally, many trace fixtures are too old to be processed by Lantern.\n let lantern;\n try {\n options.logger?.start('insights:createLanternContext');\n lantern = this.#createLanternContext(parsedTrace, traceEvents, frameId, navigationId, options);\n } catch (e) {\n // Don't allow an error in constructing the Lantern graphs to break the rest of the trace processor.\n // Log unexpected errors, but suppress anything that occurs from a trace being too old.\n // Otherwise tests using old fixtures become way too noisy.\n const expectedErrors = [\n 'mainDocumentRequest not found',\n 'missing metric scores for main frame',\n 'missing metric: FCP',\n 'missing metric: LCP',\n 'No network requests found in trace',\n 'Trace is too old',\n ];\n if (!(e instanceof Lantern.Core.LanternError)) {\n // If this wasn't a managed LanternError, the stack trace is likely needed for debugging.\n console.error(e);\n } else if (!expectedErrors.some(err => e.message === err)) {\n // To reduce noise from tests, only print errors that are not expected to occur because a trace is\n // too old (for which there is no single check).\n console.error(e);\n }\n } finally {\n options.logger?.end('insights:createLanternContext');\n }\n\n const min = navigation.ts;\n const max = i + 1 < navigations.length ? navigations[i + 1].ts : parsedTrace.Meta.traceBounds.max;\n const bounds = Helpers.Timing.traceWindowFromMicroSeconds(min, max);\n const context: Insights.Types.InsightSetContext = {\n bounds,\n frameId,\n navigation,\n navigationId,\n lantern,\n };\n\n this.#computeInsightSet(this.#insights, parsedTrace, context, options);\n }\n }\n}\n\n/**\n * Some Handlers need data provided by others. Dependencies of a handler handler are\n * declared in the `deps` field.\n * @returns A map from trace event handler name to trace event handler whose entries\n * iterate in such a way that each handler is visited after its dependencies.\n */\nexport function sortHandlers(traceHandlers: Partial<{[key in Handlers.Types.HandlerName]: Handlers.Types.Handler}>):\n Map<Handlers.Types.HandlerName, Handlers.Types.Handler> {\n const sortedMap = new Map<Handlers.Types.HandlerName, Handlers.Types.Handler>();\n const visited = new Set<Handlers.Types.HandlerName>();\n const visitHandler = (handlerName: Handlers.Types.HandlerName): void => {\n if (sortedMap.has(handlerName)) {\n return;\n }\n if (visited.has(handlerName)) {\n let stackPath = '';\n for (const handler of visited) {\n if (stackPath || handler === handlerName) {\n stackPath += `${handler}->`;\n }\n }\n stackPath += handlerName;\n throw new Error(`Found dependency cycle in trace event handlers: ${stackPath}`);\n }\n visited.add(handlerName);\n const handler = traceHandlers[handlerName];\n if (!handler) {\n return;\n }\n const deps = handler.deps?.();\n if (deps) {\n deps.forEach(visitHandler);\n }\n sortedMap.set(handlerName, handler);\n };\n\n for (const handlerName of Object.keys(traceHandlers)) {\n visitHandler(handlerName as Handlers.Types.HandlerName);\n }\n return sortedMap;\n}\n"]}
@@ -12,19 +12,38 @@ type GeneratedFileSizes = {
12
12
  export declare function computeGeneratedFileSizes(script: Handlers.ModelHandlers.Scripts.Script): GeneratedFileSizes;
13
13
  export declare function normalizeSource(source: string): string;
14
14
  /**
15
- * The key is a source map `sources` entry, but normalized via `normalizeSource`.
15
+ * The key is a source map `sources` entry (these are URLs/file paths), but normalized
16
+ * via `normalizeSource`.
16
17
  *
17
- * The value is an array with an entry for every script that has a source map which
18
+ * The value is an object with an entry for every script that has a source map which
18
19
  * denotes that this source was used, along with the estimated resource size it takes
19
20
  * up in the script.
20
21
  */
21
- export type ScriptDuplication = Map<string, Array<{
22
- script: Handlers.ModelHandlers.Scripts.Script;
23
- resourceSize: number;
24
- }>>;
22
+ export type ScriptDuplication = Map<string, {
23
+ /**
24
+ * This is the sum of all (but one) `attributedSize` in `scripts`.
25
+ *
26
+ * One copy of this module is treated as the canonical version - the rest will
27
+ * have non-zero `wastedBytes`. The canonical copy is the first entry of
28
+ * `scripts`.
29
+ *
30
+ * In the case of all copies being the same version, all sizes are
31
+ * equal and the selection doesn't matter (ignoring compression ratios). When
32
+ * the copies are different versions, it does matter. Ideally the newest
33
+ * version would be the canonical copy, but version information is not present.
34
+ * Instead, size is used as a heuristic for latest version. This makes the
35
+ * value here conserative in its estimation.
36
+ */
37
+ estimatedDuplicateBytes: number;
38
+ duplicates: Array<{
39
+ script: Handlers.ModelHandlers.Scripts.Script;
40
+ /** The number of bytes in the script bundle that map back to this module. */
41
+ attributedSize: number;
42
+ }>;
43
+ }>;
25
44
  /**
26
- * Sorts each array within @see ScriptDuplication by resource size, and drops information
27
- * on sources that are too small.
45
+ * Sorts each array within @see ScriptDuplication by attributedSize, drops information
46
+ * on sources that are too small, and calculates esimatedDuplicateBytes.
28
47
  */
29
48
  export declare function normalizeDuplication(duplication: ScriptDuplication): void;
30
49
  /**
@@ -1,8 +1,10 @@
1
1
  // Copyright 2025 The Chromium Authors. All rights reserved.
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
- const RELATIVE_SIZE_THRESHOLD = 0.1;
4
+ // Ignore modules smaller than an absolute threshold.
5
5
  const ABSOLUTE_SIZE_THRESHOLD_BYTES = 1024 * 0.5;
6
+ // Ignore modules smaller than a % size of largest copy of the module.
7
+ const RELATIVE_SIZE_THRESHOLD = 0.1;
6
8
  /**
7
9
  * Using a script's contents and source map, attribute every generated byte to an authored source file.
8
10
  */
@@ -84,31 +86,29 @@ function shouldIgnoreSource(source) {
84
86
  return false;
85
87
  }
86
88
  /**
87
- * Sorts each array within @see ScriptDuplication by resource size, and drops information
88
- * on sources that are too small.
89
+ * Sorts each array within @see ScriptDuplication by attributedSize, drops information
90
+ * on sources that are too small, and calculates esimatedDuplicateBytes.
89
91
  */
90
92
  export function normalizeDuplication(duplication) {
91
- for (const [key, originalSourceData] of duplication.entries()) {
92
- let sourceData = originalSourceData;
93
+ for (const [key, data] of duplication) {
93
94
  // Sort by resource size.
94
- sourceData.sort((a, b) => b.resourceSize - a.resourceSize);
95
- // Remove modules smaller than a % size of largest.
96
- if (sourceData.length > 1) {
97
- const largestResourceSize = sourceData[0].resourceSize;
98
- sourceData = sourceData.filter(data => {
99
- const percentSize = data.resourceSize / largestResourceSize;
95
+ data.duplicates.sort((a, b) => b.attributedSize - a.attributedSize);
96
+ // Ignore modules smaller than a % size of largest.
97
+ if (data.duplicates.length > 1) {
98
+ const largestResourceSize = data.duplicates[0].attributedSize;
99
+ data.duplicates = data.duplicates.filter(duplicate => {
100
+ const percentSize = duplicate.attributedSize / largestResourceSize;
100
101
  return percentSize >= RELATIVE_SIZE_THRESHOLD;
101
102
  });
102
103
  }
103
- // Remove modules smaller than an absolute threshold.
104
- sourceData = sourceData.filter(data => data.resourceSize >= ABSOLUTE_SIZE_THRESHOLD_BYTES);
105
- // Delete any that now don't have multiple source data entries.
106
- if (sourceData.length > 1) {
107
- duplication.set(key, sourceData);
108
- }
109
- else {
104
+ // Ignore modules smaller than an absolute threshold.
105
+ data.duplicates = data.duplicates.filter(duplicate => duplicate.attributedSize >= ABSOLUTE_SIZE_THRESHOLD_BYTES);
106
+ // Delete any that now don't have multiple entries.
107
+ if (data.duplicates.length <= 1) {
110
108
  duplication.delete(key);
109
+ continue;
111
110
  }
111
+ data.estimatedDuplicateBytes = data.duplicates.slice(1).reduce((acc, cur) => acc + cur.attributedSize, 0);
112
112
  }
113
113
  }
114
114
  function computeLastGeneratedColumnMap(map) {
@@ -158,21 +158,22 @@ export function computeScriptDuplication(scriptsData) {
158
158
  });
159
159
  }
160
160
  }
161
- const moduleNameToSourceData = new Map();
161
+ const duplication = new Map();
162
162
  for (const [script, sourceDataArray] of sourceDatasMap) {
163
163
  for (const sourceData of sourceDataArray) {
164
- let data = moduleNameToSourceData.get(sourceData.source);
164
+ let data = duplication.get(sourceData.source);
165
165
  if (!data) {
166
- data = [];
167
- moduleNameToSourceData.set(sourceData.source, data);
166
+ data = { estimatedDuplicateBytes: 0, duplicates: [] };
167
+ duplication.set(sourceData.source, data);
168
168
  }
169
- data.push({
169
+ data.duplicates.push({
170
170
  script,
171
- resourceSize: sourceData.resourceSize,
171
+ attributedSize: sourceData.resourceSize,
172
172
  });
173
173
  }
174
174
  }
175
- normalizeDuplication(moduleNameToSourceData);
176
- return moduleNameToSourceData;
175
+ normalizeDuplication(duplication);
176
+ // Sort by estimated savings.
177
+ return new Map([...duplication].sort((a, b) => b[1].estimatedDuplicateBytes - a[1].estimatedDuplicateBytes));
177
178
  }
178
179
  //# sourceMappingURL=ScriptDuplication.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ScriptDuplication.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/extras/ScriptDuplication.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as SDK from '../../../core/sdk/sdk.js';\nimport type * as Handlers from '../handlers/handlers.js';\n\nconst RELATIVE_SIZE_THRESHOLD = 0.1;\nconst ABSOLUTE_SIZE_THRESHOLD_BYTES = 1024 * 0.5;\n\ntype GeneratedFileSizes = {\n errorMessage: string,\n}|{files: Record<string, number>, unmappedBytes: number, totalBytes: number};\n\n/**\n * Using a script's contents and source map, attribute every generated byte to an authored source file.\n */\nexport function computeGeneratedFileSizes(script: Handlers.ModelHandlers.Scripts.Script): GeneratedFileSizes {\n if (!script.sourceMap) {\n throw new Error('expected source map');\n }\n\n const map = script.sourceMap;\n const content = script.content ?? '';\n const contentLength = content.length;\n const lines = content.split('\\n');\n const files: Record<string, number> = {};\n const totalBytes = contentLength;\n let unmappedBytes = totalBytes;\n\n const lastGeneratedColumnMap = computeLastGeneratedColumnMap(script.sourceMap);\n\n for (const mapping of map.mappings()) {\n const source = mapping.sourceURL;\n const lineNum = mapping.lineNumber;\n const colNum = mapping.columnNumber;\n const lastColNum = lastGeneratedColumnMap.get(mapping);\n\n // Webpack sometimes emits null mappings.\n // https://github.com/mozilla/source-map/pull/303\n if (!source) {\n continue;\n }\n\n // Lines and columns are zero-based indices. Visually, lines are shown as a 1-based index.\n\n const line = lines[lineNum];\n if (line === null || line === undefined) {\n const errorMessage = `${map.url()} mapping for line out of bounds: ${lineNum + 1}`;\n return {errorMessage};\n }\n\n if (colNum > line.length) {\n const errorMessage = `${map.url()} mapping for column out of bounds: ${lineNum + 1}:${colNum}`;\n return {errorMessage};\n }\n\n let mappingLength = 0;\n if (lastColNum !== undefined) {\n if (lastColNum > line.length) {\n const errorMessage = `${map.url()} mapping for last column out of bounds: ${lineNum + 1}:${lastColNum}`;\n return {errorMessage};\n }\n mappingLength = lastColNum - colNum;\n } else {\n // Add +1 to account for the newline.\n mappingLength = line.length - colNum + 1;\n }\n files[source] = (files[source] || 0) + mappingLength;\n unmappedBytes -= mappingLength;\n }\n\n return {\n files,\n unmappedBytes,\n totalBytes,\n };\n}\n\ninterface SourceData {\n source: string;\n resourceSize: number;\n}\n\nexport function normalizeSource(source: string): string {\n // Trim trailing question mark - b/c webpack.\n source = source.replace(/\\?$/, '');\n\n // Normalize paths for dependencies by only keeping everything after the last `node_modules`.\n const lastNodeModulesIndex = source.lastIndexOf('node_modules');\n if (lastNodeModulesIndex !== -1) {\n source = source.substring(lastNodeModulesIndex);\n }\n\n return source;\n}\n\nfunction shouldIgnoreSource(source: string): boolean {\n // Ignore bundle overhead.\n if (source.includes('webpack/bootstrap')) {\n return true;\n }\n if (source.includes('(webpack)/buildin')) {\n return true;\n }\n\n // Ignore webpack module shims, i.e. aliases of the form `module.exports = window.jQuery`\n if (source.includes('external ')) {\n return true;\n }\n\n return false;\n}\n\n/**\n * The key is a source map `sources` entry, but normalized via `normalizeSource`.\n *\n * The value is an array with an entry for every script that has a source map which\n * denotes that this source was used, along with the estimated resource size it takes\n * up in the script.\n */\nexport type ScriptDuplication =\n Map<string, Array<{script: Handlers.ModelHandlers.Scripts.Script, resourceSize: number}>>;\n\n/**\n * Sorts each array within @see ScriptDuplication by resource size, and drops information\n * on sources that are too small.\n */\nexport function normalizeDuplication(duplication: ScriptDuplication): void {\n for (const [key, originalSourceData] of duplication.entries()) {\n let sourceData = originalSourceData;\n\n // Sort by resource size.\n sourceData.sort((a, b) => b.resourceSize - a.resourceSize);\n\n // Remove modules smaller than a % size of largest.\n if (sourceData.length > 1) {\n const largestResourceSize = sourceData[0].resourceSize;\n sourceData = sourceData.filter(data => {\n const percentSize = data.resourceSize / largestResourceSize;\n return percentSize >= RELATIVE_SIZE_THRESHOLD;\n });\n }\n\n // Remove modules smaller than an absolute threshold.\n sourceData = sourceData.filter(data => data.resourceSize >= ABSOLUTE_SIZE_THRESHOLD_BYTES);\n\n // Delete any that now don't have multiple source data entries.\n if (sourceData.length > 1) {\n duplication.set(key, sourceData);\n } else {\n duplication.delete(key);\n }\n }\n}\n\nfunction computeLastGeneratedColumnMap(map: SDK.SourceMap.SourceMap): Map<SDK.SourceMap.SourceMapEntry, number> {\n const result = new Map<SDK.SourceMap.SourceMapEntry, number>();\n\n const mappings = map.mappings();\n for (let i = 0; i < mappings.length - 1; i++) {\n const mapping = mappings[i];\n const nextMapping = mappings[i + 1];\n if (mapping.lineNumber === nextMapping.lineNumber) {\n result.set(mapping, nextMapping.columnNumber);\n }\n }\n\n // Now, all but the last mapping on each line will have 'lastColumnNumber' set to a number.\n return result;\n}\n\n/**\n * Returns a @see ScriptDuplication for the given collection of script contents + source maps.\n */\nexport function computeScriptDuplication(scriptsData: Handlers.ModelHandlers.Scripts.ScriptsData): ScriptDuplication {\n const sizesMap = new Map<Handlers.ModelHandlers.Scripts.Script, GeneratedFileSizes>();\n for (const script of scriptsData.scripts) {\n if (script.content && script.sourceMap) {\n sizesMap.set(script, computeGeneratedFileSizes(script));\n }\n }\n\n const sourceDatasMap = new Map<Handlers.ModelHandlers.Scripts.Script, SourceData[]>();\n\n // Determine size of each `sources` entry.\n for (const [script, sizes] of sizesMap) {\n if (!script.sourceMap) {\n continue;\n }\n\n if ('errorMessage' in sizes) {\n console.error(sizes.errorMessage);\n continue;\n }\n\n const sourceDataArray: SourceData[] = [];\n sourceDatasMap.set(script, sourceDataArray);\n\n const sources = script.sourceMap.sourceURLs();\n for (let i = 0; i < sources.length; i++) {\n if (shouldIgnoreSource(sources[i])) {\n continue;\n }\n\n const sourceSize = sizes.files[sources[i]];\n sourceDataArray.push({\n source: normalizeSource(sources[i]),\n resourceSize: sourceSize,\n });\n }\n }\n\n const moduleNameToSourceData: ScriptDuplication = new Map();\n for (const [script, sourceDataArray] of sourceDatasMap) {\n for (const sourceData of sourceDataArray) {\n let data = moduleNameToSourceData.get(sourceData.source);\n if (!data) {\n data = [];\n moduleNameToSourceData.set(sourceData.source, data);\n }\n data.push({\n script,\n resourceSize: sourceData.resourceSize,\n });\n }\n }\n\n normalizeDuplication(moduleNameToSourceData);\n return moduleNameToSourceData;\n}\n"]}
1
+ {"version":3,"file":"ScriptDuplication.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/extras/ScriptDuplication.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as SDK from '../../../core/sdk/sdk.js';\nimport type * as Handlers from '../handlers/handlers.js';\n\n// Ignore modules smaller than an absolute threshold.\nconst ABSOLUTE_SIZE_THRESHOLD_BYTES = 1024 * 0.5;\n// Ignore modules smaller than a % size of largest copy of the module.\nconst RELATIVE_SIZE_THRESHOLD = 0.1;\n\ntype GeneratedFileSizes = {\n errorMessage: string,\n}|{files: Record<string, number>, unmappedBytes: number, totalBytes: number};\n\n/**\n * Using a script's contents and source map, attribute every generated byte to an authored source file.\n */\nexport function computeGeneratedFileSizes(script: Handlers.ModelHandlers.Scripts.Script): GeneratedFileSizes {\n if (!script.sourceMap) {\n throw new Error('expected source map');\n }\n\n const map = script.sourceMap;\n const content = script.content ?? '';\n const contentLength = content.length;\n const lines = content.split('\\n');\n const files: Record<string, number> = {};\n const totalBytes = contentLength;\n let unmappedBytes = totalBytes;\n\n const lastGeneratedColumnMap = computeLastGeneratedColumnMap(script.sourceMap);\n\n for (const mapping of map.mappings()) {\n const source = mapping.sourceURL;\n const lineNum = mapping.lineNumber;\n const colNum = mapping.columnNumber;\n const lastColNum = lastGeneratedColumnMap.get(mapping);\n\n // Webpack sometimes emits null mappings.\n // https://github.com/mozilla/source-map/pull/303\n if (!source) {\n continue;\n }\n\n // Lines and columns are zero-based indices. Visually, lines are shown as a 1-based index.\n\n const line = lines[lineNum];\n if (line === null || line === undefined) {\n const errorMessage = `${map.url()} mapping for line out of bounds: ${lineNum + 1}`;\n return {errorMessage};\n }\n\n if (colNum > line.length) {\n const errorMessage = `${map.url()} mapping for column out of bounds: ${lineNum + 1}:${colNum}`;\n return {errorMessage};\n }\n\n let mappingLength = 0;\n if (lastColNum !== undefined) {\n if (lastColNum > line.length) {\n const errorMessage = `${map.url()} mapping for last column out of bounds: ${lineNum + 1}:${lastColNum}`;\n return {errorMessage};\n }\n mappingLength = lastColNum - colNum;\n } else {\n // Add +1 to account for the newline.\n mappingLength = line.length - colNum + 1;\n }\n files[source] = (files[source] || 0) + mappingLength;\n unmappedBytes -= mappingLength;\n }\n\n return {\n files,\n unmappedBytes,\n totalBytes,\n };\n}\n\ninterface SourceData {\n source: string;\n resourceSize: number;\n}\n\nexport function normalizeSource(source: string): string {\n // Trim trailing question mark - b/c webpack.\n source = source.replace(/\\?$/, '');\n\n // Normalize paths for dependencies by only keeping everything after the last `node_modules`.\n const lastNodeModulesIndex = source.lastIndexOf('node_modules');\n if (lastNodeModulesIndex !== -1) {\n source = source.substring(lastNodeModulesIndex);\n }\n\n return source;\n}\n\nfunction shouldIgnoreSource(source: string): boolean {\n // Ignore bundle overhead.\n if (source.includes('webpack/bootstrap')) {\n return true;\n }\n if (source.includes('(webpack)/buildin')) {\n return true;\n }\n\n // Ignore webpack module shims, i.e. aliases of the form `module.exports = window.jQuery`\n if (source.includes('external ')) {\n return true;\n }\n\n return false;\n}\n\n/**\n * The key is a source map `sources` entry (these are URLs/file paths), but normalized\n * via `normalizeSource`.\n *\n * The value is an object with an entry for every script that has a source map which\n * denotes that this source was used, along with the estimated resource size it takes\n * up in the script.\n */\nexport type ScriptDuplication = Map<string, {\n /**\n * This is the sum of all (but one) `attributedSize` in `scripts`.\n *\n * One copy of this module is treated as the canonical version - the rest will\n * have non-zero `wastedBytes`. The canonical copy is the first entry of\n * `scripts`.\n *\n * In the case of all copies being the same version, all sizes are\n * equal and the selection doesn't matter (ignoring compression ratios). When\n * the copies are different versions, it does matter. Ideally the newest\n * version would be the canonical copy, but version information is not present.\n * Instead, size is used as a heuristic for latest version. This makes the\n * value here conserative in its estimation.\n */\n estimatedDuplicateBytes: number,\n duplicates: Array<{\n script: Handlers.ModelHandlers.Scripts.Script,\n /** The number of bytes in the script bundle that map back to this module. */\n attributedSize: number,\n }>,\n}>;\n\n/**\n * Sorts each array within @see ScriptDuplication by attributedSize, drops information\n * on sources that are too small, and calculates esimatedDuplicateBytes.\n */\nexport function normalizeDuplication(duplication: ScriptDuplication): void {\n for (const [key, data] of duplication) {\n // Sort by resource size.\n data.duplicates.sort((a, b) => b.attributedSize - a.attributedSize);\n\n // Ignore modules smaller than a % size of largest.\n if (data.duplicates.length > 1) {\n const largestResourceSize = data.duplicates[0].attributedSize;\n data.duplicates = data.duplicates.filter(duplicate => {\n const percentSize = duplicate.attributedSize / largestResourceSize;\n return percentSize >= RELATIVE_SIZE_THRESHOLD;\n });\n }\n\n // Ignore modules smaller than an absolute threshold.\n data.duplicates = data.duplicates.filter(duplicate => duplicate.attributedSize >= ABSOLUTE_SIZE_THRESHOLD_BYTES);\n\n // Delete any that now don't have multiple entries.\n if (data.duplicates.length <= 1) {\n duplication.delete(key);\n continue;\n }\n\n data.estimatedDuplicateBytes = data.duplicates.slice(1).reduce((acc, cur) => acc + cur.attributedSize, 0);\n }\n}\n\nfunction computeLastGeneratedColumnMap(map: SDK.SourceMap.SourceMap): Map<SDK.SourceMap.SourceMapEntry, number> {\n const result = new Map<SDK.SourceMap.SourceMapEntry, number>();\n\n const mappings = map.mappings();\n for (let i = 0; i < mappings.length - 1; i++) {\n const mapping = mappings[i];\n const nextMapping = mappings[i + 1];\n if (mapping.lineNumber === nextMapping.lineNumber) {\n result.set(mapping, nextMapping.columnNumber);\n }\n }\n\n // Now, all but the last mapping on each line will have 'lastColumnNumber' set to a number.\n return result;\n}\n\n/**\n * Returns a @see ScriptDuplication for the given collection of script contents + source maps.\n */\nexport function computeScriptDuplication(scriptsData: Handlers.ModelHandlers.Scripts.ScriptsData): ScriptDuplication {\n const sizesMap = new Map<Handlers.ModelHandlers.Scripts.Script, GeneratedFileSizes>();\n for (const script of scriptsData.scripts) {\n if (script.content && script.sourceMap) {\n sizesMap.set(script, computeGeneratedFileSizes(script));\n }\n }\n\n const sourceDatasMap = new Map<Handlers.ModelHandlers.Scripts.Script, SourceData[]>();\n\n // Determine size of each `sources` entry.\n for (const [script, sizes] of sizesMap) {\n if (!script.sourceMap) {\n continue;\n }\n\n if ('errorMessage' in sizes) {\n console.error(sizes.errorMessage);\n continue;\n }\n\n const sourceDataArray: SourceData[] = [];\n sourceDatasMap.set(script, sourceDataArray);\n\n const sources = script.sourceMap.sourceURLs();\n for (let i = 0; i < sources.length; i++) {\n if (shouldIgnoreSource(sources[i])) {\n continue;\n }\n\n const sourceSize = sizes.files[sources[i]];\n sourceDataArray.push({\n source: normalizeSource(sources[i]),\n resourceSize: sourceSize,\n });\n }\n }\n\n const duplication: ScriptDuplication = new Map();\n for (const [script, sourceDataArray] of sourceDatasMap) {\n for (const sourceData of sourceDataArray) {\n let data = duplication.get(sourceData.source);\n if (!data) {\n data = {estimatedDuplicateBytes: 0, duplicates: []};\n duplication.set(sourceData.source, data);\n }\n data.duplicates.push({\n script,\n attributedSize: sourceData.resourceSize,\n });\n }\n }\n\n normalizeDuplication(duplication);\n\n // Sort by estimated savings.\n return new Map([...duplication].sort((a, b) => b[1].estimatedDuplicateBytes - a[1].estimatedDuplicateBytes));\n}\n"]}
@@ -32,6 +32,13 @@ export function get(event, parsedTrace) {
32
32
  else if (Types.Events.isUserTiming(event)) {
33
33
  result = getForUserTiming(event, parsedTrace);
34
34
  }
35
+ else if (Types.Events.isLayout(event) || Types.Events.isUpdateLayoutTree(event)) {
36
+ const node = parsedTrace.Renderer.entryToNode.get(event);
37
+ const parent = node?.parent?.entry;
38
+ if (parent) {
39
+ result = get(parent, parsedTrace);
40
+ }
41
+ }
35
42
  if (result) {
36
43
  cacheForTrace.set(event, result);
37
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StackTraceForEvent.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/extras/StackTraceForEvent.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nexport const stackTraceForEventInTrace =\n new Map<Handlers.Types.ParsedTrace, Map<Types.Events.Event, Protocol.Runtime.StackTrace>>();\n\nexport function clearCacheForTrace(parsedTrace: Handlers.Types.ParsedTrace): void {\n stackTraceForEventInTrace.delete(parsedTrace);\n}\n/**\n * This util builds a stack trace that includes async calls for a given\n * event. It leverages data we collect from sampling to deduce sync\n * stacks and trace event instrumentation on the V8 debugger to stitch\n * them together.\n */\nexport function get(event: Types.Events.Event, parsedTrace: Handlers.Types.ParsedTrace): Protocol.Runtime.StackTrace|\n null {\n let cacheForTrace = stackTraceForEventInTrace.get(parsedTrace);\n if (!cacheForTrace) {\n cacheForTrace = new Map();\n stackTraceForEventInTrace.set(parsedTrace, cacheForTrace);\n }\n const resultFromCache = cacheForTrace.get(event);\n if (resultFromCache) {\n return resultFromCache;\n }\n let result: Protocol.Runtime.StackTrace|null = null;\n if (Types.Events.isProfileCall(event)) {\n result = getForProfileCall(event, parsedTrace);\n } else if (Types.Extensions.isSyntheticExtensionEntry(event)) {\n result = getForExtensionEntry(event, parsedTrace);\n } else if (Types.Events.isUserTiming(event)) {\n result = getForUserTiming(event, parsedTrace);\n }\n if (result) {\n cacheForTrace.set(event, result);\n }\n return result;\n}\n\nfunction getForProfileCall(\n event: Types.Events.SyntheticProfileCall, parsedTrace: Handlers.Types.ParsedTrace): Protocol.Runtime.StackTrace {\n // When working with a CPU profile the renderer handler won't have\n // entries in its tree.\n const entryToNode =\n parsedTrace.Renderer.entryToNode.size > 0 ? parsedTrace.Renderer.entryToNode : parsedTrace.Samples.entryToNode;\n const topStackTrace: Protocol.Runtime.StackTrace = {callFrames: []};\n let stackTrace: Protocol.Runtime.StackTrace = topStackTrace;\n let currentEntry = event;\n let node: Helpers.TreeHelpers.TraceEntryNode|null|undefined = entryToNode.get(event);\n const traceCache =\n stackTraceForEventInTrace.get(parsedTrace) || new Map<Types.Events.Event, Protocol.Runtime.StackTrace>();\n stackTraceForEventInTrace.set(parsedTrace, traceCache);\n // Move up this node's ancestor tree appending frames to its\n // stack trace.\n while (node) {\n if (!Types.Events.isProfileCall(node.entry)) {\n node = node.parent;\n continue;\n }\n\n currentEntry = node.entry;\n // First check if this entry was processed before.\n const stackTraceFromCache = traceCache.get(node.entry);\n if (stackTraceFromCache) {\n stackTrace.callFrames.push(...stackTraceFromCache.callFrames.filter(callFrame => !isNativeJSFunction(callFrame)));\n stackTrace.parent = stackTraceFromCache.parent;\n // Only set the description to the cache value if we didn't\n // compute it in the previous iteration, since the async stack\n // trace descriptions / taskNames is only extracted when jumping\n // to the async parent, and that might not have happened when\n // the cached value was computed (e.g. the cached value\n // computation started at some point inside the parent stack\n // trace).\n stackTrace.description = stackTrace.description || stackTraceFromCache.description;\n break;\n }\n\n if (!isNativeJSFunction(currentEntry.callFrame)) {\n stackTrace.callFrames.push(currentEntry.callFrame);\n }\n const maybeAsyncParentEvent = parsedTrace.AsyncJSCalls.asyncCallToScheduler.get(currentEntry);\n const maybeAsyncParentNode = maybeAsyncParentEvent && entryToNode.get(maybeAsyncParentEvent.scheduler);\n if (maybeAsyncParentNode) {\n // The Protocol.Runtime.StackTrace type is recursive, so we\n // move one level deeper in it as we walk up the ancestor tree.\n stackTrace.parent = {callFrames: []};\n stackTrace = stackTrace.parent;\n // Note: this description effectively corresponds to the name\n // of the task that scheduled the stack trace we are jumping\n // FROM, so it would make sense that it was set to that stack\n // trace instead of the one we are jumping TO. However, the\n // JS presentation utils we use to present async stack traces\n // assume the description is added to the stack trace that\n // scheduled the async task, so we build the data that way.\n stackTrace.description = maybeAsyncParentEvent.taskName;\n node = maybeAsyncParentNode;\n continue;\n }\n node = node.parent;\n }\n return topStackTrace;\n}\n\n/**\n * Finds the JS call in which an extension entry was injected (the\n * code location that called the extension API), and returns its stack\n * trace.\n */\nfunction getForExtensionEntry(event: Types.Extensions.SyntheticExtensionEntry, parsedTrace: Handlers.Types.ParsedTrace):\n Protocol.Runtime.StackTrace|null {\n return getForUserTiming(event.rawSourceEvent, parsedTrace);\n}\n\n/**\n * Finds the JS call in which the user timing API was called and returns\n * its stack trace.\n */\nfunction getForUserTiming(\n event: Types.Events.UserTiming|Types.Events.ConsoleTimeStamp,\n parsedTrace: Handlers.Types.ParsedTrace): Protocol.Runtime.StackTrace|null {\n let rawEvent: Types.Events.Event|undefined = event;\n if (Types.Events.isPerformanceMeasureBegin(event)) {\n if (event.args.traceId === undefined) {\n return null;\n }\n rawEvent = parsedTrace.UserTimings.measureTraceByTraceId.get(event.args.traceId);\n }\n if (!rawEvent) {\n return null;\n }\n // Look for the nearest profile call ancestor of the event tracing\n // the call to the API.\n let node: Helpers.TreeHelpers.TraceEntryNode|undefined|null = parsedTrace.Renderer.entryToNode.get(rawEvent);\n while (node && !Types.Events.isProfileCall(node.entry)) {\n node = node.parent;\n }\n if (node && Types.Events.isProfileCall(node.entry)) {\n return get(node.entry, parsedTrace);\n }\n return null;\n}\n/**\n * Determines if a function is a native JS API (like setTimeout,\n * requestAnimationFrame, consoleTask.run. etc.). This is useful to\n * discard stack frames corresponding to the JS scheduler function\n * itself, since it's already being used as title of async stack traces\n * taken from the async `taskName`. This is also consistent with the\n * behaviour of the stack trace in the sources\n * panel.\n */\nfunction isNativeJSFunction({columnNumber, lineNumber, url, scriptId}: Protocol.Runtime.CallFrame): boolean {\n return lineNumber === -1 && columnNumber === -1 && url === '' && scriptId === '0';\n}\n"]}
1
+ {"version":3,"file":"StackTraceForEvent.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/extras/StackTraceForEvent.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nexport const stackTraceForEventInTrace =\n new Map<Handlers.Types.ParsedTrace, Map<Types.Events.Event, Protocol.Runtime.StackTrace>>();\n\nexport function clearCacheForTrace(parsedTrace: Handlers.Types.ParsedTrace): void {\n stackTraceForEventInTrace.delete(parsedTrace);\n}\n/**\n * This util builds a stack trace that includes async calls for a given\n * event. It leverages data we collect from sampling to deduce sync\n * stacks and trace event instrumentation on the V8 debugger to stitch\n * them together.\n */\nexport function get(event: Types.Events.Event, parsedTrace: Handlers.Types.ParsedTrace): Protocol.Runtime.StackTrace|\n null {\n let cacheForTrace = stackTraceForEventInTrace.get(parsedTrace);\n if (!cacheForTrace) {\n cacheForTrace = new Map();\n stackTraceForEventInTrace.set(parsedTrace, cacheForTrace);\n }\n const resultFromCache = cacheForTrace.get(event);\n if (resultFromCache) {\n return resultFromCache;\n }\n let result: Protocol.Runtime.StackTrace|null = null;\n if (Types.Events.isProfileCall(event)) {\n result = getForProfileCall(event, parsedTrace);\n } else if (Types.Extensions.isSyntheticExtensionEntry(event)) {\n result = getForExtensionEntry(event, parsedTrace);\n } else if (Types.Events.isUserTiming(event)) {\n result = getForUserTiming(event, parsedTrace);\n } else if (Types.Events.isLayout(event) || Types.Events.isUpdateLayoutTree(event)) {\n const node = parsedTrace.Renderer.entryToNode.get(event);\n const parent = node?.parent?.entry;\n if (parent) {\n result = get(parent, parsedTrace);\n }\n }\n if (result) {\n cacheForTrace.set(event, result);\n }\n return result;\n}\n\nfunction getForProfileCall(\n event: Types.Events.SyntheticProfileCall, parsedTrace: Handlers.Types.ParsedTrace): Protocol.Runtime.StackTrace {\n // When working with a CPU profile the renderer handler won't have\n // entries in its tree.\n const entryToNode =\n parsedTrace.Renderer.entryToNode.size > 0 ? parsedTrace.Renderer.entryToNode : parsedTrace.Samples.entryToNode;\n const topStackTrace: Protocol.Runtime.StackTrace = {callFrames: []};\n let stackTrace: Protocol.Runtime.StackTrace = topStackTrace;\n let currentEntry = event;\n let node: Helpers.TreeHelpers.TraceEntryNode|null|undefined = entryToNode.get(event);\n const traceCache =\n stackTraceForEventInTrace.get(parsedTrace) || new Map<Types.Events.Event, Protocol.Runtime.StackTrace>();\n stackTraceForEventInTrace.set(parsedTrace, traceCache);\n // Move up this node's ancestor tree appending frames to its\n // stack trace.\n while (node) {\n if (!Types.Events.isProfileCall(node.entry)) {\n node = node.parent;\n continue;\n }\n\n currentEntry = node.entry;\n // First check if this entry was processed before.\n const stackTraceFromCache = traceCache.get(node.entry);\n if (stackTraceFromCache) {\n stackTrace.callFrames.push(...stackTraceFromCache.callFrames.filter(callFrame => !isNativeJSFunction(callFrame)));\n stackTrace.parent = stackTraceFromCache.parent;\n // Only set the description to the cache value if we didn't\n // compute it in the previous iteration, since the async stack\n // trace descriptions / taskNames is only extracted when jumping\n // to the async parent, and that might not have happened when\n // the cached value was computed (e.g. the cached value\n // computation started at some point inside the parent stack\n // trace).\n stackTrace.description = stackTrace.description || stackTraceFromCache.description;\n break;\n }\n\n if (!isNativeJSFunction(currentEntry.callFrame)) {\n stackTrace.callFrames.push(currentEntry.callFrame);\n }\n const maybeAsyncParentEvent = parsedTrace.AsyncJSCalls.asyncCallToScheduler.get(currentEntry);\n const maybeAsyncParentNode = maybeAsyncParentEvent && entryToNode.get(maybeAsyncParentEvent.scheduler);\n if (maybeAsyncParentNode) {\n // The Protocol.Runtime.StackTrace type is recursive, so we\n // move one level deeper in it as we walk up the ancestor tree.\n stackTrace.parent = {callFrames: []};\n stackTrace = stackTrace.parent;\n // Note: this description effectively corresponds to the name\n // of the task that scheduled the stack trace we are jumping\n // FROM, so it would make sense that it was set to that stack\n // trace instead of the one we are jumping TO. However, the\n // JS presentation utils we use to present async stack traces\n // assume the description is added to the stack trace that\n // scheduled the async task, so we build the data that way.\n stackTrace.description = maybeAsyncParentEvent.taskName;\n node = maybeAsyncParentNode;\n continue;\n }\n node = node.parent;\n }\n return topStackTrace;\n}\n\n/**\n * Finds the JS call in which an extension entry was injected (the\n * code location that called the extension API), and returns its stack\n * trace.\n */\nfunction getForExtensionEntry(event: Types.Extensions.SyntheticExtensionEntry, parsedTrace: Handlers.Types.ParsedTrace):\n Protocol.Runtime.StackTrace|null {\n return getForUserTiming(event.rawSourceEvent, parsedTrace);\n}\n\n/**\n * Finds the JS call in which the user timing API was called and returns\n * its stack trace.\n */\nfunction getForUserTiming(\n event: Types.Events.UserTiming|Types.Events.ConsoleTimeStamp,\n parsedTrace: Handlers.Types.ParsedTrace): Protocol.Runtime.StackTrace|null {\n let rawEvent: Types.Events.Event|undefined = event;\n if (Types.Events.isPerformanceMeasureBegin(event)) {\n if (event.args.traceId === undefined) {\n return null;\n }\n rawEvent = parsedTrace.UserTimings.measureTraceByTraceId.get(event.args.traceId);\n }\n if (!rawEvent) {\n return null;\n }\n // Look for the nearest profile call ancestor of the event tracing\n // the call to the API.\n let node: Helpers.TreeHelpers.TraceEntryNode|undefined|null = parsedTrace.Renderer.entryToNode.get(rawEvent);\n while (node && !Types.Events.isProfileCall(node.entry)) {\n node = node.parent;\n }\n if (node && Types.Events.isProfileCall(node.entry)) {\n return get(node.entry, parsedTrace);\n }\n return null;\n}\n/**\n * Determines if a function is a native JS API (like setTimeout,\n * requestAnimationFrame, consoleTask.run. etc.). This is useful to\n * discard stack frames corresponding to the JS scheduler function\n * itself, since it's already being used as title of async stack traces\n * taken from the async `taskName`. This is also consistent with the\n * behaviour of the stack trace in the sources\n * panel.\n */\nfunction isNativeJSFunction({columnNumber, lineNumber, url, scriptId}: Protocol.Runtime.CallFrame): boolean {\n return lineNumber === -1 && columnNumber === -1 && url === '' && scriptId === '0';\n}\n"]}
@@ -66,22 +66,26 @@ export function extractConsoleAPIExtensionEntries() {
66
66
  if (!currentTimeStamp.args.data) {
67
67
  continue;
68
68
  }
69
- const timeStampName = String(currentTimeStamp.args.data.name);
69
+ const timeStampName = String(currentTimeStamp.args.data.name ?? currentTimeStamp.args.data.message);
70
70
  timeStampByName.set(timeStampName, currentTimeStamp);
71
71
  const extensionData = extensionDataInConsoleTimeStamp(currentTimeStamp);
72
- const startName = currentTimeStamp.args.data.start;
73
- const endName = currentTimeStamp.args.data.end;
74
- if (!extensionData && !startName && !endName) {
72
+ const start = currentTimeStamp.args.data.start;
73
+ const end = currentTimeStamp.args.data.end;
74
+ if (!extensionData && !start && !end) {
75
75
  continue;
76
76
  }
77
- const startTimeStamp = startName ? timeStampByName.get(String(startName)) : undefined;
78
- const endTimeStamp = endName ? timeStampByName.get(String(endName)) : undefined;
79
- if (endTimeStamp && !startTimeStamp) {
77
+ // If the start or end is a number, it's assumed to be a timestamp
78
+ // from the tracing clock, so we use that directly, otherwise we
79
+ // assume it's the label of a previous console timestamp, in which
80
+ // case we use its corresponding timestamp.
81
+ const startTimeStamp = typeof start === 'number' ? Types.Timing.Micro(start) : timeStampByName.get(String(start))?.ts;
82
+ const endTimeStamp = typeof end === 'number' ? Types.Timing.Micro(end) : timeStampByName.get(String(end))?.ts;
83
+ if (endTimeStamp !== undefined && startTimeStamp === undefined) {
80
84
  // Invalid data
81
85
  continue;
82
86
  }
83
- const entryStartTime = startTimeStamp?.ts ?? currentTimeStamp.ts;
84
- const entryEndTime = endTimeStamp?.ts ?? currentTimeStamp.ts;
87
+ const entryStartTime = startTimeStamp ?? currentTimeStamp.ts;
88
+ const entryEndTime = endTimeStamp ?? currentTimeStamp.ts;
85
89
  if (extensionData) {
86
90
  const unregisteredExtensionEntry = {
87
91
  ...currentTimeStamp,
@@ -91,6 +95,7 @@ export function extractConsoleAPIExtensionEntries() {
91
95
  rawSourceEvent: currentTimeStamp,
92
96
  dur: Types.Timing.Micro(entryEndTime - entryStartTime),
93
97
  ts: entryStartTime,
98
+ ph: "X" /* Types.Events.Phase.COMPLETE */,
94
99
  };
95
100
  const extensionEntry = Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager()
96
101
  .registerSyntheticEvent(unregisteredExtensionEntry);