@paulirish/trace_engine 0.0.51 → 0.0.53

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 (197) hide show
  1. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  2. package/core/platform/DOMUtilities.d.ts +8 -0
  3. package/core/platform/DOMUtilities.js +14 -0
  4. package/core/platform/DOMUtilities.js.map +1 -1
  5. package/core/platform/StringUtilities.d.ts +1 -5
  6. package/core/platform/StringUtilities.js +4 -1
  7. package/core/platform/StringUtilities.js.map +1 -1
  8. package/core/platform/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  9. package/core/platform/platform-tsconfig.json +1 -1
  10. package/generated/protocol.d.ts +345 -44
  11. package/locales/af.json +11 -5
  12. package/locales/am.json +7 -1
  13. package/locales/ar.json +7 -1
  14. package/locales/as.json +7 -1
  15. package/locales/az.json +7 -1
  16. package/locales/be.json +7 -1
  17. package/locales/bg.json +7 -1
  18. package/locales/bn.json +7 -1
  19. package/locales/bs.json +7 -1
  20. package/locales/ca.json +7 -1
  21. package/locales/cs.json +7 -1
  22. package/locales/cy.json +7 -1
  23. package/locales/da.json +7 -1
  24. package/locales/de.json +7 -1
  25. package/locales/el.json +7 -1
  26. package/locales/en-GB.json +7 -1
  27. package/locales/en-US.json +52 -7
  28. package/locales/en-XL.json +52 -7
  29. package/locales/es-419.json +7 -1
  30. package/locales/es.json +7 -1
  31. package/locales/et.json +7 -1
  32. package/locales/eu.json +7 -1
  33. package/locales/fa.json +7 -1
  34. package/locales/fi.json +7 -1
  35. package/locales/fil.json +7 -1
  36. package/locales/fr-CA.json +7 -1
  37. package/locales/fr.json +7 -1
  38. package/locales/gl.json +7 -1
  39. package/locales/gu.json +7 -1
  40. package/locales/he.json +7 -1
  41. package/locales/hi.json +7 -1
  42. package/locales/hr.json +7 -1
  43. package/locales/hu.json +7 -1
  44. package/locales/hy.json +7 -1
  45. package/locales/id.json +7 -1
  46. package/locales/is.json +7 -1
  47. package/locales/it.json +7 -1
  48. package/locales/ja.json +7 -1
  49. package/locales/ka.json +7 -1
  50. package/locales/kk.json +7 -1
  51. package/locales/km.json +7 -1
  52. package/locales/kn.json +7 -1
  53. package/locales/ko.json +7 -1
  54. package/locales/ky.json +7 -1
  55. package/locales/lo.json +7 -1
  56. package/locales/lt.json +7 -1
  57. package/locales/lv.json +7 -1
  58. package/locales/mk.json +7 -1
  59. package/locales/ml.json +7 -1
  60. package/locales/mn.json +7 -1
  61. package/locales/mr.json +7 -1
  62. package/locales/ms.json +7 -1
  63. package/locales/my.json +7 -1
  64. package/locales/ne.json +7 -1
  65. package/locales/nl.json +7 -1
  66. package/locales/no.json +7 -1
  67. package/locales/or.json +7 -1
  68. package/locales/pa.json +7 -1
  69. package/locales/pl.json +7 -1
  70. package/locales/pt-PT.json +7 -1
  71. package/locales/pt.json +7 -1
  72. package/locales/ro.json +7 -1
  73. package/locales/ru.json +7 -1
  74. package/locales/si.json +7 -1
  75. package/locales/sk.json +7 -1
  76. package/locales/sl.json +7 -1
  77. package/locales/sq.json +7 -1
  78. package/locales/sr-Latn.json +7 -1
  79. package/locales/sr.json +7 -1
  80. package/locales/sv.json +7 -1
  81. package/locales/sw.json +7 -1
  82. package/locales/ta.json +7 -1
  83. package/locales/te.json +7 -1
  84. package/locales/th.json +7 -1
  85. package/locales/tr.json +7 -1
  86. package/locales/uk.json +7 -1
  87. package/locales/ur.json +7 -1
  88. package/locales/uz.json +7 -1
  89. package/locales/vi.json +7 -1
  90. package/locales/zh-HK.json +7 -1
  91. package/locales/zh-TW.json +7 -1
  92. package/locales/zh.json +7 -1
  93. package/locales/zu.json +7 -1
  94. package/models/cpu_profile/cpu_profile-tsconfig.json +1 -1
  95. package/models/cpu_profile/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  96. package/models/trace/LanternComputationData.js +3 -3
  97. package/models/trace/LanternComputationData.js.map +1 -1
  98. package/models/trace/Processor.d.ts +1 -3
  99. package/models/trace/Processor.js +1 -1
  100. package/models/trace/Processor.js.map +1 -1
  101. package/models/trace/TracingManager.js.map +1 -1
  102. package/models/trace/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  103. package/models/trace/extras/ScriptDuplication.d.ts +5 -2
  104. package/models/trace/extras/ScriptDuplication.js +4 -2
  105. package/models/trace/extras/ScriptDuplication.js.map +1 -1
  106. package/models/trace/extras/StackTraceForEvent.js +88 -47
  107. package/models/trace/extras/StackTraceForEvent.js.map +1 -1
  108. package/models/trace/extras/ThirdParties.d.ts +13 -12
  109. package/models/trace/extras/ThirdParties.js +50 -19
  110. package/models/trace/extras/ThirdParties.js.map +1 -1
  111. package/models/trace/extras/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  112. package/models/trace/extras/extras-tsconfig.json +1 -1
  113. package/models/trace/extras/extras.d.ts +98 -6
  114. package/models/trace/extras/extras.js +98 -6
  115. package/models/trace/handlers/AsyncJSCallsHandler.d.ts +5 -0
  116. package/models/trace/handlers/AsyncJSCallsHandler.js +12 -9
  117. package/models/trace/handlers/AsyncJSCallsHandler.js.map +1 -1
  118. package/models/trace/handlers/FramesHandler.js.map +1 -1
  119. package/models/trace/handlers/NetworkRequestsHandler.d.ts +1 -0
  120. package/models/trace/handlers/NetworkRequestsHandler.js +37 -23
  121. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  122. package/models/trace/handlers/ScriptsHandler.d.ts +5 -1
  123. package/models/trace/handlers/ScriptsHandler.js +59 -22
  124. package/models/trace/handlers/ScriptsHandler.js.map +1 -1
  125. package/models/trace/handlers/WarningsHandler.js +14 -2
  126. package/models/trace/handlers/WarningsHandler.js.map +1 -1
  127. package/models/trace/handlers/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  128. package/models/trace/handlers/handlers-tsconfig.json +1 -1
  129. package/models/trace/handlers/helpers.js +12 -0
  130. package/models/trace/handlers/helpers.js.map +1 -1
  131. package/models/trace/handlers/types.d.ts +2 -6
  132. package/models/trace/handlers/types.js.map +1 -1
  133. package/models/trace/helpers/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  134. package/models/trace/helpers/helpers-tsconfig.json +1 -1
  135. package/models/trace/insights/CLSCulprits.d.ts +6 -1
  136. package/models/trace/insights/CLSCulprits.js +11 -2
  137. package/models/trace/insights/CLSCulprits.js.map +1 -1
  138. package/models/trace/insights/Cache.d.ts +0 -1
  139. package/models/trace/insights/Cache.js +8 -7
  140. package/models/trace/insights/Cache.js.map +1 -1
  141. package/models/trace/insights/Common.js +6 -0
  142. package/models/trace/insights/Common.js.map +1 -1
  143. package/models/trace/insights/DocumentLatency.d.ts +7 -3
  144. package/models/trace/insights/DocumentLatency.js +25 -8
  145. package/models/trace/insights/DocumentLatency.js.map +1 -1
  146. package/models/trace/insights/DuplicatedJavaScript.js +9 -3
  147. package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
  148. package/models/trace/insights/ImageDelivery.d.ts +0 -1
  149. package/models/trace/insights/ImageDelivery.js +1 -1
  150. package/models/trace/insights/ImageDelivery.js.map +1 -1
  151. package/models/trace/insights/LCPPhases.d.ts +1 -1
  152. package/models/trace/insights/LCPPhases.js +1 -1
  153. package/models/trace/insights/LCPPhases.js.map +1 -1
  154. package/models/trace/insights/LegacyJavaScript.d.ts +1 -1
  155. package/models/trace/insights/LegacyJavaScript.js +6 -3
  156. package/models/trace/insights/LegacyJavaScript.js.map +1 -1
  157. package/models/trace/insights/NetworkDependencyTree.d.ts +151 -3
  158. package/models/trace/insights/NetworkDependencyTree.js +648 -10
  159. package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
  160. package/models/trace/insights/RenderBlocking.js +1 -1
  161. package/models/trace/insights/RenderBlocking.js.map +1 -1
  162. package/models/trace/insights/ThirdParties.d.ts +1 -1
  163. package/models/trace/insights/ThirdParties.js +7 -7
  164. package/models/trace/insights/ThirdParties.js.map +1 -1
  165. package/models/trace/insights/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  166. package/models/trace/insights/insights-tsconfig.json +1 -1
  167. package/models/trace/insights/types.d.ts +11 -0
  168. package/models/trace/insights/types.js.map +1 -1
  169. package/models/trace/lantern/core/core-tsconfig.json +1 -1
  170. package/models/trace/lantern/core/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  171. package/models/trace/lantern/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  172. package/models/trace/lantern/graph/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  173. package/models/trace/lantern/graph/graph-tsconfig.json +1 -1
  174. package/models/trace/lantern/lantern-tsconfig.json +1 -1
  175. package/models/trace/lantern/metrics/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  176. package/models/trace/lantern/metrics/metrics-tsconfig.json +1 -1
  177. package/models/trace/lantern/simulation/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  178. package/models/trace/lantern/simulation/simulation-tsconfig.json +1 -1
  179. package/models/trace/lantern/types/Lantern.d.ts +4 -7
  180. package/models/trace/lantern/types/Lantern.js +1 -0
  181. package/models/trace/lantern/types/Lantern.js.map +1 -1
  182. package/models/trace/lantern/types/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  183. package/models/trace/lantern/types/types-tsconfig.json +1 -1
  184. package/models/trace/trace-tsconfig.json +1 -1
  185. package/models/trace/types/Configuration.d.ts +2 -0
  186. package/models/trace/types/Configuration.js.map +1 -1
  187. package/models/trace/types/Extensions.d.ts +1 -3
  188. package/models/trace/types/Extensions.js.map +1 -1
  189. package/models/trace/types/File.d.ts +2 -1
  190. package/models/trace/types/File.js.map +1 -1
  191. package/models/trace/types/TraceEvents.d.ts +51 -26
  192. package/models/trace/types/TraceEvents.js +6 -0
  193. package/models/trace/types/TraceEvents.js.map +1 -1
  194. package/models/trace/types/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
  195. package/models/trace/types/types-tsconfig.json +1 -1
  196. package/package.json +1 -1
  197. package/test/test-trace-engine.mjs +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"TracingManager.js","sourceRoot":"","sources":["../../../../../../front_end/models/trace/TracingManager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2014 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as SDK from '../../core/sdk/sdk.js';\nimport type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';\nimport * as Protocol from '../../generated/protocol.js';\n\nimport type * as Types from './types/types.js';\n\nexport class TracingManager extends SDK.SDKModel.SDKModel<void> {\n readonly #tracingAgent: ProtocolProxyApi.TracingApi;\n #activeClient: TracingManagerClient|null;\n #eventsRetrieved: number;\n #finishing?: boolean;\n constructor(target: SDK.Target.Target) {\n super(target);\n this.#tracingAgent = target.tracingAgent();\n target.registerTracingDispatcher(new TracingDispatcher(this));\n\n this.#activeClient = null;\n this.#eventsRetrieved = 0;\n }\n\n bufferUsage(usage?: number, percentFull?: number): void {\n if (this.#activeClient) {\n this.#activeClient.tracingBufferUsage(usage || percentFull || 0);\n }\n }\n\n eventsCollected(events: Types.Events.Event[]): void {\n if (!this.#activeClient) {\n return;\n }\n this.#activeClient.traceEventsCollected(events);\n this.#eventsRetrieved += events.length;\n\n // CDP no longer provides an approximate_event_count AKA eventCount. It's always 0.\n // To give some idea of progress we'll compare to a large (900k event) trace.\n // And we'll clamp both sides so the user sees some progress, and never maxed at 99%\n const progress = Math.min((this.#eventsRetrieved / 900_000) + 0.15, 0.90);\n this.#activeClient.eventsRetrievalProgress(progress);\n }\n\n tracingComplete(): void {\n this.#eventsRetrieved = 0;\n if (this.#activeClient) {\n this.#activeClient.tracingComplete();\n this.#activeClient = null;\n }\n this.#finishing = false;\n }\n\n async reset(): Promise<void> {\n // If we have an active client, we should try to stop\n // it before resetting it, else we will leave the\n // backend in a broken state where it thinks we are in\n // the middle of tracing, but we think we are not.\n // Then, any subsequent attempts to record will fail\n // because the backend will not let us start a second\n // tracing session.\n if (this.#activeClient) {\n await this.#tracingAgent.invoke_end();\n }\n this.#eventsRetrieved = 0;\n this.#activeClient = null;\n this.#finishing = false;\n }\n\n async start(client: TracingManagerClient, categoryFilter: string): Promise<Protocol.ProtocolResponseWithError> {\n if (this.#activeClient) {\n throw new Error('Tracing is already started');\n }\n const bufferUsageReportingIntervalMs = 500;\n this.#activeClient = client;\n const args = {\n bufferUsageReportingInterval: bufferUsageReportingIntervalMs,\n transferMode: Protocol.Tracing.StartRequestTransferMode.ReportEvents,\n traceConfig: {\n recordMode: Protocol.Tracing.TraceConfigRecordMode.RecordUntilFull,\n traceBufferSizeInKb: 400 * 1000,\n includedCategories: categoryFilter.split(','),\n },\n };\n const response = await this.#tracingAgent.invoke_start(args);\n if (response.getError()) {\n this.#activeClient = null;\n }\n return response;\n }\n\n stop(): void {\n if (!this.#activeClient) {\n throw new Error('Tracing is not started');\n }\n if (this.#finishing) {\n throw new Error('Tracing is already being stopped');\n }\n this.#finishing = true;\n void this.#tracingAgent.invoke_end();\n }\n}\n\nexport interface TracingManagerClient {\n traceEventsCollected(events: Types.Events.Event[]): void;\n\n tracingComplete(): void;\n tracingBufferUsage(usage: number): void;\n eventsRetrievalProgress(progress: number): void;\n}\n\nclass TracingDispatcher implements ProtocolProxyApi.TracingDispatcher {\n readonly #tracingManager: TracingManager;\n constructor(tracingManager: TracingManager) {\n this.#tracingManager = tracingManager;\n }\n\n // `eventCount` will always be 0 as perfetto no longer calculates `approximate_event_count`\n bufferUsage({value, percentFull}: Protocol.Tracing.BufferUsageEvent): void {\n this.#tracingManager.bufferUsage(value, percentFull);\n }\n\n dataCollected({value}: Protocol.Tracing.DataCollectedEvent): void {\n this.#tracingManager.eventsCollected(value);\n }\n\n tracingComplete(): void {\n this.#tracingManager.tracingComplete();\n }\n}\n\nSDK.SDKModel.SDKModel.register(TracingManager, {capabilities: SDK.Target.Capability.TRACING, autostart: false});\n"]}
1
+ {"version":3,"file":"TracingManager.js","sourceRoot":"","sources":["../../../../../../front_end/models/trace/TracingManager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2014 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as SDK from '../../core/sdk/sdk.js';\nimport type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';\nimport * as Protocol from '../../generated/protocol.js';\n\nimport type * as Types from './types/types.js';\n\nexport class TracingManager extends SDK.SDKModel.SDKModel<void> {\n readonly #tracingAgent: ProtocolProxyApi.TracingApi;\n #activeClient: TracingManagerClient|null;\n #eventsRetrieved: number;\n #finishing?: boolean;\n constructor(target: SDK.Target.Target) {\n super(target);\n this.#tracingAgent = target.tracingAgent();\n target.registerTracingDispatcher(new TracingDispatcher(this));\n\n this.#activeClient = null;\n this.#eventsRetrieved = 0;\n }\n\n bufferUsage(usage?: number, percentFull?: number): void {\n if (this.#activeClient) {\n this.#activeClient.tracingBufferUsage(usage || percentFull || 0);\n }\n }\n\n eventsCollected(events: Types.Events.Event[]): void {\n if (!this.#activeClient) {\n return;\n }\n this.#activeClient.traceEventsCollected(events);\n this.#eventsRetrieved += events.length;\n\n // CDP no longer provides an approximate_event_count AKA eventCount. It's always 0.\n // To give some idea of progress we'll compare to a large (900k event) trace.\n // And we'll clamp both sides so the user sees some progress, and never maxed at 99%\n const progress = Math.min((this.#eventsRetrieved / 900_000) + 0.15, 0.90);\n this.#activeClient.eventsRetrievalProgress(progress);\n }\n\n tracingComplete(): void {\n this.#eventsRetrieved = 0;\n if (this.#activeClient) {\n this.#activeClient.tracingComplete();\n this.#activeClient = null;\n }\n this.#finishing = false;\n }\n\n async reset(): Promise<void> {\n // If we have an active client, we should try to stop\n // it before resetting it, else we will leave the\n // backend in a broken state where it thinks we are in\n // the middle of tracing, but we think we are not.\n // Then, any subsequent attempts to record will fail\n // because the backend will not let us start a second\n // tracing session.\n if (this.#activeClient) {\n await this.#tracingAgent.invoke_end();\n }\n this.#eventsRetrieved = 0;\n this.#activeClient = null;\n this.#finishing = false;\n }\n\n async start(client: TracingManagerClient, categoryFilter: string): Promise<Protocol.ProtocolResponseWithError> {\n if (this.#activeClient) {\n throw new Error('Tracing is already started');\n }\n const bufferUsageReportingIntervalMs = 500;\n this.#activeClient = client;\n const args = {\n bufferUsageReportingInterval: bufferUsageReportingIntervalMs,\n transferMode: Protocol.Tracing.StartRequestTransferMode.ReportEvents,\n traceConfig: {\n recordMode: Protocol.Tracing.TraceConfigRecordMode.RecordUntilFull,\n traceBufferSizeInKb: 1200 * 1000,\n includedCategories: categoryFilter.split(','),\n },\n };\n const response = await this.#tracingAgent.invoke_start(args);\n if (response.getError()) {\n this.#activeClient = null;\n }\n return response;\n }\n\n stop(): void {\n if (!this.#activeClient) {\n throw new Error('Tracing is not started');\n }\n if (this.#finishing) {\n throw new Error('Tracing is already being stopped');\n }\n this.#finishing = true;\n void this.#tracingAgent.invoke_end();\n }\n}\n\nexport interface TracingManagerClient {\n traceEventsCollected(events: Types.Events.Event[]): void;\n\n tracingComplete(): void;\n tracingBufferUsage(usage: number): void;\n eventsRetrievalProgress(progress: number): void;\n}\n\nclass TracingDispatcher implements ProtocolProxyApi.TracingDispatcher {\n readonly #tracingManager: TracingManager;\n constructor(tracingManager: TracingManager) {\n this.#tracingManager = tracingManager;\n }\n\n // `eventCount` will always be 0 as perfetto no longer calculates `approximate_event_count`\n bufferUsage({value, percentFull}: Protocol.Tracing.BufferUsageEvent): void {\n this.#tracingManager.bufferUsage(value, percentFull);\n }\n\n dataCollected({value}: Protocol.Tracing.DataCollectedEvent): void {\n this.#tracingManager.eventsCollected(value);\n }\n\n tracingComplete(): void {\n this.#tracingManager.tracingComplete();\n }\n}\n\nSDK.SDKModel.SDKModel.register(TracingManager, {capabilities: SDK.Target.Capability.TRACING, autostart: false});\n"]}
@@ -18,7 +18,7 @@
18
18
  "noImplicitOverride": true,
19
19
  "noImplicitReturns": true,
20
20
  "noUnusedLocals": false,
21
- "noUnusedParameters": true,
21
+ "noUnusedParameters": false,
22
22
  "outDir": ".",
23
23
  "rootDir": "../../../../../../front_end/models/trace",
24
24
  "skipLibCheck": true,
@@ -26,7 +26,10 @@ export type ScriptDuplication = Map<string, {
26
26
  estimatedDuplicateBytes: number;
27
27
  duplicates: Array<{
28
28
  script: Handlers.ModelHandlers.Scripts.Script;
29
- /** The number of bytes in the script bundle that map back to this module. */
29
+ /**
30
+ * The number of bytes in the script bundle that map back to this module,
31
+ * in terms of estimated impact on transfer size.
32
+ */
30
33
  attributedSize: number;
31
34
  }>;
32
35
  }>;
@@ -43,7 +46,7 @@ export declare function getNodeModuleName(source: string): string;
43
46
  * 2. `duplication` keys correspond to authored files, except all files within the same
44
47
  * node_module package are aggregated under the same entry.
45
48
  */
46
- export declare function computeScriptDuplication(scriptsData: Handlers.ModelHandlers.Scripts.ScriptsData): {
49
+ export declare function computeScriptDuplication(scriptsData: Handlers.ModelHandlers.Scripts.ScriptsData, compressionRatios: Map<string, number>): {
47
50
  duplication: ScriptDuplication;
48
51
  duplicationGroupedByNodeModules: ScriptDuplication;
49
52
  };
@@ -107,7 +107,7 @@ function sorted(duplication) {
107
107
  * 2. `duplication` keys correspond to authored files, except all files within the same
108
108
  * node_module package are aggregated under the same entry.
109
109
  */
110
- export function computeScriptDuplication(scriptsData) {
110
+ export function computeScriptDuplication(scriptsData, compressionRatios) {
111
111
  const sourceDatasMap = new Map();
112
112
  // Determine size of each `sources` entry.
113
113
  for (const script of scriptsData.scripts) {
@@ -144,9 +144,11 @@ export function computeScriptDuplication(scriptsData) {
144
144
  data = { estimatedDuplicateBytes: 0, duplicates: [] };
145
145
  duplication.set(sourceData.source, data);
146
146
  }
147
+ const compressionRatio = script.request ? compressionRatios.get(script.request?.args.data.requestId) ?? 1 : 1;
148
+ const transferSize = Math.round(sourceData.resourceSize * compressionRatio);
147
149
  data.duplicates.push({
148
150
  script,
149
- attributedSize: sourceData.resourceSize,
151
+ attributedSize: transferSize,
150
152
  });
151
153
  }
152
154
  }
@@ -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 * 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\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 indexOfOrLength(haystack: string, needle: string, startPosition = 0): number {\n const index = haystack.indexOf(needle, startPosition);\n return index === -1 ? haystack.length : index;\n}\n\nexport function getNodeModuleName(source: string): string {\n const sourceSplit = source.split('node_modules/');\n source = sourceSplit[sourceSplit.length - 1];\n\n const indexFirstSlash = indexOfOrLength(source, '/');\n if (source[0] === '@') {\n return source.slice(0, indexOfOrLength(source, '/', indexFirstSlash + 1));\n }\n\n return source.slice(0, indexFirstSlash);\n}\n\nfunction groupByNodeModules(duplication: ScriptDuplication): ScriptDuplication {\n const groupedDuplication: ScriptDuplication = new Map();\n for (const [source, data] of duplication) {\n if (!source.includes('node_modules')) {\n groupedDuplication.set(source, data);\n continue;\n }\n\n const nodeModuleKey = 'node_modules/' + getNodeModuleName(source);\n const aggregatedData = groupedDuplication.get(nodeModuleKey) ?? {\n duplicates: [],\n // This is calculated in normalizeDuplication.\n estimatedDuplicateBytes: 0,\n };\n groupedDuplication.set(nodeModuleKey, aggregatedData);\n\n for (const {script, attributedSize} of data.duplicates) {\n let duplicate = aggregatedData.duplicates.find(d => d.script === script);\n if (!duplicate) {\n duplicate = {script, attributedSize: 0};\n aggregatedData.duplicates.push(duplicate);\n }\n duplicate.attributedSize += attributedSize;\n }\n }\n\n return groupedDuplication;\n}\n\n/**\n * Sort by estimated savings.\n */\nfunction sorted(duplication: ScriptDuplication): ScriptDuplication {\n return new Map([...duplication].sort((a, b) => b[1].estimatedDuplicateBytes - a[1].estimatedDuplicateBytes));\n}\n\n/**\n * Returns 2 @see ScriptDuplication for the given collection of script contents + source maps:\n *\n * 1. `duplication` keys correspond to authored files\n * 2. `duplication` keys correspond to authored files, except all files within the same\n * node_module package are aggregated under the same entry.\n */\nexport function computeScriptDuplication(scriptsData: Handlers.ModelHandlers.Scripts.ScriptsData):\n {duplication: ScriptDuplication, duplicationGroupedByNodeModules: ScriptDuplication} {\n const sourceDatasMap = new Map<Handlers.ModelHandlers.Scripts.Script, SourceData[]>();\n\n // Determine size of each `sources` entry.\n for (const script of scriptsData.scripts) {\n if (!script.content || !script.sourceMap) {\n continue;\n }\n\n const sizes = Handlers.ModelHandlers.Scripts.getScriptGeneratedSizes(script);\n if (!sizes) {\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 const duplicationGroupedByNodeModules = groupByNodeModules(duplication);\n\n normalizeDuplication(duplication);\n normalizeDuplication(duplicationGroupedByNodeModules);\n\n return {\n duplication: sorted(duplication),\n duplicationGroupedByNodeModules: sorted(duplicationGroupedByNodeModules),\n };\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 * 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\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 /**\n * The number of bytes in the script bundle that map back to this module,\n * in terms of estimated impact on transfer size.\n */\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 indexOfOrLength(haystack: string, needle: string, startPosition = 0): number {\n const index = haystack.indexOf(needle, startPosition);\n return index === -1 ? haystack.length : index;\n}\n\nexport function getNodeModuleName(source: string): string {\n const sourceSplit = source.split('node_modules/');\n source = sourceSplit[sourceSplit.length - 1];\n\n const indexFirstSlash = indexOfOrLength(source, '/');\n if (source[0] === '@') {\n return source.slice(0, indexOfOrLength(source, '/', indexFirstSlash + 1));\n }\n\n return source.slice(0, indexFirstSlash);\n}\n\nfunction groupByNodeModules(duplication: ScriptDuplication): ScriptDuplication {\n const groupedDuplication: ScriptDuplication = new Map();\n for (const [source, data] of duplication) {\n if (!source.includes('node_modules')) {\n groupedDuplication.set(source, data);\n continue;\n }\n\n const nodeModuleKey = 'node_modules/' + getNodeModuleName(source);\n const aggregatedData = groupedDuplication.get(nodeModuleKey) ?? {\n duplicates: [],\n // This is calculated in normalizeDuplication.\n estimatedDuplicateBytes: 0,\n };\n groupedDuplication.set(nodeModuleKey, aggregatedData);\n\n for (const {script, attributedSize} of data.duplicates) {\n let duplicate = aggregatedData.duplicates.find(d => d.script === script);\n if (!duplicate) {\n duplicate = {script, attributedSize: 0};\n aggregatedData.duplicates.push(duplicate);\n }\n duplicate.attributedSize += attributedSize;\n }\n }\n\n return groupedDuplication;\n}\n\n/**\n * Sort by estimated savings.\n */\nfunction sorted(duplication: ScriptDuplication): ScriptDuplication {\n return new Map([...duplication].sort((a, b) => b[1].estimatedDuplicateBytes - a[1].estimatedDuplicateBytes));\n}\n\n/**\n * Returns 2 @see ScriptDuplication for the given collection of script contents + source maps:\n *\n * 1. `duplication` keys correspond to authored files\n * 2. `duplication` keys correspond to authored files, except all files within the same\n * node_module package are aggregated under the same entry.\n */\nexport function computeScriptDuplication(\n scriptsData: Handlers.ModelHandlers.Scripts.ScriptsData, compressionRatios: Map<string, number>):\n {duplication: ScriptDuplication, duplicationGroupedByNodeModules: ScriptDuplication} {\n const sourceDatasMap = new Map<Handlers.ModelHandlers.Scripts.Script, SourceData[]>();\n\n // Determine size of each `sources` entry.\n for (const script of scriptsData.scripts) {\n if (!script.content || !script.sourceMap) {\n continue;\n }\n\n const sizes = Handlers.ModelHandlers.Scripts.getScriptGeneratedSizes(script);\n if (!sizes) {\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 const compressionRatio = script.request ? compressionRatios.get(script.request?.args.data.requestId) ?? 1 : 1;\n const transferSize = Math.round(sourceData.resourceSize * compressionRatio);\n data.duplicates.push({\n script,\n attributedSize: transferSize,\n });\n }\n }\n\n const duplicationGroupedByNodeModules = groupByNodeModules(duplication);\n\n normalizeDuplication(duplication);\n normalizeDuplication(duplicationGroupedByNodeModules);\n\n return {\n duplication: sorted(duplication),\n duplicationGroupedByNodeModules: sorted(duplicationGroupedByNodeModules),\n };\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  // Copyright 2024 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
+ import * as Helpers from '../helpers/helpers.js';
4
5
  import * as Types from '../types/types.js';
5
6
  export const stackTraceForEventInTrace = new Map();
6
7
  export function clearCacheForTrace(parsedTrace) {
@@ -23,20 +24,29 @@ export function get(event, parsedTrace) {
23
24
  return resultFromCache;
24
25
  }
25
26
  let result = null;
26
- if (Types.Events.isProfileCall(event)) {
27
- result = getForProfileCall(event, parsedTrace);
28
- }
29
- else if (Types.Extensions.isSyntheticExtensionEntry(event)) {
27
+ if (Types.Extensions.isSyntheticExtensionEntry(event)) {
30
28
  result = getForExtensionEntry(event, parsedTrace);
31
29
  }
32
- else if (Types.Events.isUserTiming(event)) {
33
- result = getForUserTiming(event, parsedTrace);
30
+ else if (Types.Events.isPerformanceMeasureBegin(event)) {
31
+ result = getForPerformanceMeasure(event, parsedTrace);
34
32
  }
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);
33
+ else {
34
+ result = getForEvent(event, parsedTrace);
35
+ const payloadCallFrames = getTraceEventPayloadStackAsProtocolCallFrame(event).filter(callFrame => !isNativeJSFunction(callFrame));
36
+ // If the event has a payload stack trace, replace the synchronous
37
+ // portion of the calculated stack with the payload's call frames.
38
+ // We do this because trace payload call frames contain call
39
+ // locations, unlike profile call frames obtained with getForEvent
40
+ // (which contain function declaration locations).
41
+ // This way the user knows which exact JS location triggered an
42
+ // event.
43
+ if (!result.callFrames.length) {
44
+ result.callFrames = payloadCallFrames;
45
+ }
46
+ else {
47
+ for (let i = 0; i < payloadCallFrames.length && i < result.callFrames.length; i++) {
48
+ result.callFrames[i] = payloadCallFrames[i];
49
+ }
40
50
  }
41
51
  }
42
52
  if (result) {
@@ -44,21 +54,36 @@ export function get(event, parsedTrace) {
44
54
  }
45
55
  return result;
46
56
  }
47
- function getForProfileCall(event, parsedTrace) {
57
+ /**
58
+ * Fallback method to obtain a stack trace using the parsed event tree
59
+ * hierarchy. This shouldn't be called outside of this file, use `get`
60
+ * instead to ensure the correct event in the tree hierarchy is used.
61
+ */
62
+ function getForEvent(event, parsedTrace) {
48
63
  // When working with a CPU profile the renderer handler won't have
49
64
  // entries in its tree.
50
65
  const entryToNode = parsedTrace.Renderer.entryToNode.size > 0 ? parsedTrace.Renderer.entryToNode : parsedTrace.Samples.entryToNode;
51
66
  const topStackTrace = { callFrames: [] };
52
67
  let stackTrace = topStackTrace;
53
- let currentEntry = event;
68
+ let currentEntry;
54
69
  let node = entryToNode.get(event);
55
70
  const traceCache = stackTraceForEventInTrace.get(parsedTrace) || new Map();
56
71
  stackTraceForEventInTrace.set(parsedTrace, traceCache);
57
- // Move up this node's ancestor tree appending frames to its
58
- // stack trace.
72
+ // Move up this node's ancestor tree appending JS frames to its
73
+ // stack trace. If an async caller is detected, move up in the async
74
+ // stack instead.
59
75
  while (node) {
60
76
  if (!Types.Events.isProfileCall(node.entry)) {
61
- node = node.parent;
77
+ const maybeAsyncParent = parsedTrace.AsyncJSCalls.runEntryPointToScheduler.get(node.entry);
78
+ if (!maybeAsyncParent) {
79
+ node = node.parent;
80
+ continue;
81
+ }
82
+ const maybeAsyncParentNode = maybeAsyncParent && entryToNode.get(maybeAsyncParent.scheduler);
83
+ if (maybeAsyncParentNode) {
84
+ stackTrace = addAsyncParentToStack(stackTrace, maybeAsyncParent.taskName);
85
+ node = maybeAsyncParentNode;
86
+ }
62
87
  continue;
63
88
  }
64
89
  currentEntry = node.entry;
@@ -83,18 +108,7 @@ function getForProfileCall(event, parsedTrace) {
83
108
  const maybeAsyncParentEvent = parsedTrace.AsyncJSCalls.asyncCallToScheduler.get(currentEntry);
84
109
  const maybeAsyncParentNode = maybeAsyncParentEvent && entryToNode.get(maybeAsyncParentEvent.scheduler);
85
110
  if (maybeAsyncParentNode) {
86
- // The Protocol.Runtime.StackTrace type is recursive, so we
87
- // move one level deeper in it as we walk up the ancestor tree.
88
- stackTrace.parent = { callFrames: [] };
89
- stackTrace = stackTrace.parent;
90
- // Note: this description effectively corresponds to the name
91
- // of the task that scheduled the stack trace we are jumping
92
- // FROM, so it would make sense that it was set to that stack
93
- // trace instead of the one we are jumping TO. However, the
94
- // JS presentation utils we use to present async stack traces
95
- // assume the description is added to the stack trace that
96
- // scheduled the async task, so we build the data that way.
97
- stackTrace.description = maybeAsyncParentEvent.taskName;
111
+ stackTrace = addAsyncParentToStack(stackTrace, maybeAsyncParentEvent.taskName);
98
112
  node = maybeAsyncParentNode;
99
113
  continue;
100
114
  }
@@ -102,39 +116,54 @@ function getForProfileCall(event, parsedTrace) {
102
116
  }
103
117
  return topStackTrace;
104
118
  }
119
+ function addAsyncParentToStack(stackTrace, taskName) {
120
+ const parent = { callFrames: [] };
121
+ // The Protocol.Runtime.StackTrace type is recursive, so we
122
+ // move one level deeper in it as we walk up the ancestor tree.
123
+ stackTrace.parent = parent;
124
+ // Note: this description effectively corresponds to the name
125
+ // of the task that scheduled the stack trace we are jumping
126
+ // FROM, so it would make sense that it was set to that stack
127
+ // trace instead of the one we are jumping TO. However, the
128
+ // JS presentation utils we use to present async stack traces
129
+ // assume the description is added to the stack trace that
130
+ // scheduled the async task, so we build the data that way.
131
+ parent.description = taskName;
132
+ return parent;
133
+ }
105
134
  /**
106
135
  * Finds the JS call in which an extension entry was injected (the
107
136
  * code location that called the extension API), and returns its stack
108
137
  * trace.
109
138
  */
110
139
  function getForExtensionEntry(event, parsedTrace) {
111
- return getForUserTiming(event.rawSourceEvent, parsedTrace);
140
+ const rawEvent = event.rawSourceEvent;
141
+ if (Types.Events.isPerformanceMeasureBegin(rawEvent)) {
142
+ return getForPerformanceMeasure(rawEvent, parsedTrace);
143
+ }
144
+ if (!rawEvent) {
145
+ return null;
146
+ }
147
+ return get(rawEvent, parsedTrace);
112
148
  }
113
149
  /**
114
- * Finds the JS call in which the user timing API was called and returns
115
- * its stack trace.
150
+ * Gets the raw event for a user timing and obtains its stack trace.
116
151
  */
117
- function getForUserTiming(event, parsedTrace) {
152
+ function getForPerformanceMeasure(event, parsedTrace) {
118
153
  let rawEvent = event;
119
- if (Types.Events.isPerformanceMeasureBegin(event)) {
120
- if (event.args.traceId === undefined) {
121
- return null;
122
- }
123
- rawEvent = parsedTrace.UserTimings.measureTraceByTraceId.get(event.args.traceId);
154
+ if (event.args.traceId === undefined) {
155
+ return null;
124
156
  }
157
+ // performance.measure calls dispatch 2 events: one for the call
158
+ // itself and another to represent the measured entry in the trace
159
+ // timeline. They are connected via a common traceId. At this
160
+ // point `rawEvent` corresponds to the second case, we must
161
+ // encounter the event for the call itself to obtain its callstack.
162
+ rawEvent = parsedTrace.UserTimings.measureTraceByTraceId.get(event.args.traceId);
125
163
  if (!rawEvent) {
126
164
  return null;
127
165
  }
128
- // Look for the nearest profile call ancestor of the event tracing
129
- // the call to the API.
130
- let node = parsedTrace.Renderer.entryToNode.get(rawEvent);
131
- while (node && !Types.Events.isProfileCall(node.entry)) {
132
- node = node.parent;
133
- }
134
- if (node && Types.Events.isProfileCall(node.entry)) {
135
- return get(node.entry, parsedTrace);
136
- }
137
- return null;
166
+ return get(rawEvent, parsedTrace);
138
167
  }
139
168
  /**
140
169
  * Determines if a function is a native JS API (like setTimeout,
@@ -148,4 +177,16 @@ function getForUserTiming(event, parsedTrace) {
148
177
  function isNativeJSFunction({ columnNumber, lineNumber, url, scriptId }) {
149
178
  return lineNumber === -1 && columnNumber === -1 && url === '' && scriptId === '0';
150
179
  }
180
+ /**
181
+ * Converts a stack trace from a trace event's payload into an array of
182
+ * Protocol.Runtime.CallFrame.
183
+ */
184
+ function getTraceEventPayloadStackAsProtocolCallFrame(event) {
185
+ const payloadCallStack = Helpers.Trace.getZeroIndexedStackTraceInEventPayload(event) || [];
186
+ const callFrames = [];
187
+ for (const frame of payloadCallStack) {
188
+ callFrames.push({ ...frame, scriptId: String(frame.scriptId) });
189
+ }
190
+ return callFrames;
191
+ }
151
192
  //# sourceMappingURL=StackTraceForEvent.js.map
@@ -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 } 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"]}
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 * 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.Extensions.isSyntheticExtensionEntry(event)) {\n result = getForExtensionEntry(event, parsedTrace);\n } else if (Types.Events.isPerformanceMeasureBegin(event)) {\n result = getForPerformanceMeasure(event, parsedTrace);\n } else {\n result = getForEvent(event, parsedTrace);\n const payloadCallFrames =\n getTraceEventPayloadStackAsProtocolCallFrame(event).filter(callFrame => !isNativeJSFunction(callFrame));\n // If the event has a payload stack trace, replace the synchronous\n // portion of the calculated stack with the payload's call frames.\n // We do this because trace payload call frames contain call\n // locations, unlike profile call frames obtained with getForEvent\n // (which contain function declaration locations).\n // This way the user knows which exact JS location triggered an\n // event.\n if (!result.callFrames.length) {\n result.callFrames = payloadCallFrames;\n } else {\n for (let i = 0; i < payloadCallFrames.length && i < result.callFrames.length; i++) {\n result.callFrames[i] = payloadCallFrames[i];\n }\n }\n }\n if (result) {\n cacheForTrace.set(event, result);\n }\n return result;\n}\n\n/**\n * Fallback method to obtain a stack trace using the parsed event tree\n * hierarchy. This shouldn't be called outside of this file, use `get`\n * instead to ensure the correct event in the tree hierarchy is used.\n */\nfunction getForEvent(event: Types.Events.Event, 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: Types.Events.SyntheticProfileCall;\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 JS frames to its\n // stack trace. If an async caller is detected, move up in the async\n // stack instead.\n while (node) {\n if (!Types.Events.isProfileCall(node.entry)) {\n const maybeAsyncParent = parsedTrace.AsyncJSCalls.runEntryPointToScheduler.get(node.entry);\n if (!maybeAsyncParent) {\n node = node.parent;\n continue;\n }\n const maybeAsyncParentNode = maybeAsyncParent && entryToNode.get(maybeAsyncParent.scheduler);\n if (maybeAsyncParentNode) {\n stackTrace = addAsyncParentToStack(stackTrace, maybeAsyncParent.taskName);\n node = maybeAsyncParentNode;\n }\n continue;\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 stackTrace = addAsyncParentToStack(stackTrace, maybeAsyncParentEvent.taskName);\n node = maybeAsyncParentNode;\n continue;\n }\n node = node.parent;\n }\n return topStackTrace;\n}\n\nfunction addAsyncParentToStack(stackTrace: Protocol.Runtime.StackTrace, taskName: string): Protocol.Runtime.StackTrace {\n const parent: Protocol.Runtime.StackTrace = {callFrames: []};\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 = 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 parent.description = taskName;\n return parent;\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 const rawEvent: Types.Events.Event = event.rawSourceEvent;\n if (Types.Events.isPerformanceMeasureBegin(rawEvent)) {\n return getForPerformanceMeasure(rawEvent, parsedTrace);\n }\n if (!rawEvent) {\n return null;\n }\n return get(rawEvent, parsedTrace);\n}\n\n/**\n * Gets the raw event for a user timing and obtains its stack trace.\n */\nfunction getForPerformanceMeasure(event: Types.Events.PerformanceMeasureBegin, parsedTrace: Handlers.Types.ParsedTrace):\n Protocol.Runtime.StackTrace|null {\n let rawEvent: Types.Events.Event|undefined = event;\n if (event.args.traceId === undefined) {\n return null;\n }\n // performance.measure calls dispatch 2 events: one for the call\n // itself and another to represent the measured entry in the trace\n // timeline. They are connected via a common traceId. At this\n // point `rawEvent` corresponds to the second case, we must\n // encounter the event for the call itself to obtain its callstack.\n rawEvent = parsedTrace.UserTimings.measureTraceByTraceId.get(event.args.traceId);\n if (!rawEvent) {\n return null;\n }\n return get(rawEvent, parsedTrace);\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\n/**\n * Converts a stack trace from a trace event's payload into an array of\n * Protocol.Runtime.CallFrame.\n */\nfunction getTraceEventPayloadStackAsProtocolCallFrame(event: Types.Events.Event): Protocol.Runtime.CallFrame[] {\n const payloadCallStack = Helpers.Trace.getZeroIndexedStackTraceInEventPayload(event) || [];\n const callFrames: Protocol.Runtime.CallFrame[] = [];\n for (const frame of payloadCallStack) {\n callFrames.push({...frame, scriptId: String(frame.scriptId) as Protocol.Runtime.ScriptId});\n }\n return callFrames;\n}\n"]}
@@ -1,21 +1,22 @@
1
1
  import type * as ThirdPartyWeb from '../../../third_party/third-party-web/third-party-web.js';
2
- import type * as Handlers from '../handlers/handlers.js';
2
+ import * as Handlers from '../handlers/handlers.js';
3
3
  import * as Types from '../types/types.js';
4
4
  export type Entity = typeof ThirdPartyWeb.ThirdPartyWeb.entities[number];
5
- export interface Summary {
5
+ interface BaseSummary {
6
+ entity: Entity;
6
7
  transferSize: number;
7
8
  mainThreadTime: Types.Timing.Milli;
8
- relatedEvents?: Types.Events.Event[];
9
- entity: Entity;
10
9
  }
11
- export interface ThirdPartySummary {
12
- byEntity: Map<Entity, Summary>;
13
- byUrl: Map<string, Summary>;
14
- urlsByEntity: Map<Entity, Set<string>>;
15
- eventsByEntity: Map<Entity, Types.Events.Event[]>;
16
- madeUpEntityCache: Map<string, Entity>;
10
+ export interface EntitySummary extends BaseSummary {
11
+ relatedEvents: Types.Events.Event[];
12
+ }
13
+ export interface URLSummary extends BaseSummary {
14
+ url: string;
15
+ request?: Types.Events.SyntheticNetworkRequest;
17
16
  }
17
+ export declare function summarizeByThirdParty(parsedTrace: Handlers.Types.ParsedTrace, traceBounds: Types.Timing.TraceWindowMicro): EntitySummary[];
18
18
  /**
19
- * @param networkRequests Won't be filtered by trace bounds, so callers should ensure it is filtered.
19
+ * Used only by Lighthouse.
20
20
  */
21
- export declare function summarizeThirdParties(parsedTrace: Handlers.Types.ParsedTrace, traceBounds: Types.Timing.TraceWindowMicro): Summary[];
21
+ export declare function summarizeByURL(parsedTrace: Handlers.Types.ParsedTrace, traceBounds: Types.Timing.TraceWindowMicro): URLSummary[];
22
+ export {};
@@ -1,6 +1,7 @@
1
1
  // Copyright 2024 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
+ import * as Handlers from '../handlers/handlers.js';
4
5
  import * as Helpers from '../helpers/helpers.js';
5
6
  import * as Types from '../types/types.js';
6
7
  import * as TraceFilter from './TraceFilter.js';
@@ -25,22 +26,32 @@ function collectMainThreadActivity(parsedTrace) {
25
26
  }
26
27
  return mainFrameMainThread.entries;
27
28
  }
29
+ export function summarizeByThirdParty(parsedTrace, traceBounds) {
30
+ const mainThreadEvents = collectMainThreadActivity(parsedTrace).sort(Helpers.Trace.eventTimeComparator);
31
+ const groupingFunction = (event) => {
32
+ const entity = parsedTrace.Renderer.entityMappings.entityByEvent.get(event);
33
+ return entity?.name ?? '';
34
+ };
35
+ const node = getBottomUpTree(mainThreadEvents, traceBounds, groupingFunction);
36
+ const summaries = summarizeBottomUpByEntity(node, parsedTrace);
37
+ return summaries;
38
+ }
28
39
  /**
29
- * @param networkRequests Won't be filtered by trace bounds, so callers should ensure it is filtered.
40
+ * Used only by Lighthouse.
30
41
  */
31
- export function summarizeThirdParties(parsedTrace, traceBounds) {
42
+ export function summarizeByURL(parsedTrace, traceBounds) {
32
43
  const mainThreadEvents = collectMainThreadActivity(parsedTrace).sort(Helpers.Trace.eventTimeComparator);
33
- const node = getBottomUpTree(mainThreadEvents, parsedTrace, traceBounds);
34
- const summaries = summarizeBottomUp(node, parsedTrace);
44
+ const groupingFunction = (event) => {
45
+ return Handlers.Helpers.getNonResolvedURL(event, parsedTrace) ?? '';
46
+ };
47
+ const node = getBottomUpTree(mainThreadEvents, traceBounds, groupingFunction);
48
+ const summaries = summarizeBottomUpByURL(node, parsedTrace);
35
49
  return summaries;
36
50
  }
37
- function summarizeBottomUp(thirdPartyBottomUp, parsedTrace) {
38
- const summaryForEntity = new Map();
51
+ function summarizeBottomUpByEntity(root, parsedTrace) {
39
52
  const summaries = [];
40
- // Our top nodes are the 3P entities.
41
- // Tree nodes are built lazily, .children() is essential, it triggers the
42
- // construction of the root node's child nodes.
43
- const topNodes = [...thirdPartyBottomUp.children().values()].flat();
53
+ // Top nodes are the 3P entities.
54
+ const topNodes = [...root.children().values()].flat();
44
55
  for (const node of topNodes) {
45
56
  if (node.id === '') {
46
57
  continue;
@@ -49,25 +60,45 @@ function summarizeBottomUp(thirdPartyBottomUp, parsedTrace) {
49
60
  if (!entity) {
50
61
  continue;
51
62
  }
63
+ // Lets use the mapper events as our source of events, since we use the main thread to construct
64
+ // the bottom up tree. The mapper will give us all related events.
52
65
  const summary = {
53
66
  transferSize: node.transferSize,
54
67
  mainThreadTime: Types.Timing.Milli(node.selfTime),
55
- // Lets use the mapper events as our source of events, since we use the main thread to construct
56
- // the bottom up tree. The mapper will give us all related events.
68
+ entity,
57
69
  relatedEvents: parsedTrace.Renderer.entityMappings.eventsByEntity.get(entity) ?? [],
70
+ };
71
+ summaries.push(summary);
72
+ }
73
+ return summaries;
74
+ }
75
+ function summarizeBottomUpByURL(root, parsedTrace) {
76
+ const summaries = [];
77
+ const allRequests = parsedTrace.NetworkRequests.byTime;
78
+ // Top nodes are URLs.
79
+ const topNodes = [...root.children().values()].flat();
80
+ for (const node of topNodes) {
81
+ if (node.id === '' || typeof node.id !== 'string') {
82
+ continue;
83
+ }
84
+ const entity = parsedTrace.Renderer.entityMappings.entityByEvent.get(node.event);
85
+ if (!entity) {
86
+ continue;
87
+ }
88
+ const url = node.id;
89
+ const request = allRequests.find(r => r.args.data.url === url);
90
+ const summary = {
91
+ request,
92
+ url,
58
93
  entity,
94
+ transferSize: node.transferSize,
95
+ mainThreadTime: Types.Timing.Milli(node.selfTime),
59
96
  };
60
- summaryForEntity.set(entity, summary);
61
97
  summaries.push(summary);
62
98
  }
63
99
  return summaries;
64
100
  }
65
- function getBottomUpTree(mainThreadEvents, parsedTrace, tracebounds) {
66
- const mappings = parsedTrace.Renderer.entityMappings;
67
- const groupingFunction = (event) => {
68
- const entity = mappings?.entityByEvent.get(event);
69
- return entity?.name ?? '';
70
- };
101
+ function getBottomUpTree(mainThreadEvents, tracebounds, groupingFunction) {
71
102
  // Use the same filtering as front_end/panels/timeline/TimelineTreeView.ts.
72
103
  const visibleEvents = Helpers.Trace.VISIBLE_TRACE_EVENT_TYPES.values().toArray();
73
104
  const filter = new TraceFilter.VisibleEventsFilter(visibleEvents.concat(["SyntheticNetworkRequest" /* Types.Events.Name.SYNTHETIC_NETWORK_REQUEST */]));
@@ -1 +1 @@
1
- {"version":3,"file":"ThirdParties.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/extras/ThirdParties.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 ThirdPartyWeb from '../../../third_party/third-party-web/third-party-web.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport * as TraceFilter from './TraceFilter.js';\nimport * as TraceTree from './TraceTree.js';\n\nexport type Entity = typeof ThirdPartyWeb.ThirdPartyWeb.entities[number];\n\nexport interface Summary {\n transferSize: number;\n mainThreadTime: Types.Timing.Milli;\n relatedEvents?: Types.Events.Event[];\n entity: Entity;\n}\n\nexport interface ThirdPartySummary {\n byEntity: Map<Entity, Summary>;\n byUrl: Map<string, Summary>;\n urlsByEntity: Map<Entity, Set<string>>;\n eventsByEntity: Map<Entity, Types.Events.Event[]>;\n madeUpEntityCache: Map<string, Entity>;\n}\n\n/**\n *\n * Returns Main frame main thread events.\n * These events are inline with the ones used by selectedEvents() of TimelineTreeViews\n */\nfunction collectMainThreadActivity(parsedTrace: Handlers.Types.ParsedTrace): Types.Events.Event[] {\n // TODO: Note b/402658800 could be an issue here.\n const mainFrameMainThread = parsedTrace.Renderer.processes.values()\n .find(p => {\n const url = p.url ?? '';\n // Frame url checked a la CompatibilityTracksAppenders's addThreadAppenders\n return p.isOnMainFrame && !url.startsWith('about:') && !url.startsWith('chrome:');\n })\n ?.threads.values()\n .find(t => t.name === 'CrRendererMain');\n\n if (!mainFrameMainThread) {\n return [];\n }\n\n return mainFrameMainThread.entries;\n}\n\n/**\n * @param networkRequests Won't be filtered by trace bounds, so callers should ensure it is filtered.\n */\nexport function summarizeThirdParties(\n parsedTrace: Handlers.Types.ParsedTrace, traceBounds: Types.Timing.TraceWindowMicro): Summary[] {\n const mainThreadEvents = collectMainThreadActivity(parsedTrace).sort(Helpers.Trace.eventTimeComparator);\n const node = getBottomUpTree(mainThreadEvents, parsedTrace, traceBounds);\n const summaries = summarizeBottomUp(node, parsedTrace);\n\n return summaries;\n}\n\nfunction summarizeBottomUp(\n thirdPartyBottomUp: TraceTree.BottomUpRootNode, parsedTrace: Handlers.Types.ParsedTrace): Summary[] {\n const summaryForEntity: Map<Entity, Summary> = new Map<Entity, Summary>();\n const summaries: Summary[] = [];\n\n // Our top nodes are the 3P entities.\n // Tree nodes are built lazily, .children() is essential, it triggers the\n // construction of the root node's child nodes.\n const topNodes = [...thirdPartyBottomUp.children().values()].flat();\n for (const node of topNodes) {\n if (node.id === '') {\n continue;\n }\n const entity = parsedTrace.Renderer.entityMappings.entityByEvent.get(node.event);\n if (!entity) {\n continue;\n }\n\n const summary: Summary = {\n transferSize: node.transferSize,\n mainThreadTime: Types.Timing.Milli(node.selfTime),\n // Lets use the mapper events as our source of events, since we use the main thread to construct\n // the bottom up tree. The mapper will give us all related events.\n relatedEvents: parsedTrace.Renderer.entityMappings.eventsByEntity.get(entity) ?? [],\n entity,\n };\n summaryForEntity.set(entity, summary);\n summaries.push(summary);\n }\n return summaries;\n}\n\nfunction getBottomUpTree(\n mainThreadEvents: Types.Events.Event[], parsedTrace: Handlers.Types.ParsedTrace,\n tracebounds: Types.Timing.TraceWindowMicro): TraceTree.BottomUpRootNode {\n const mappings = parsedTrace.Renderer.entityMappings;\n\n const groupingFunction = (event: Types.Events.Event): string => {\n const entity = mappings?.entityByEvent.get(event);\n return entity?.name ?? '';\n };\n // Use the same filtering as front_end/panels/timeline/TimelineTreeView.ts.\n const visibleEvents = Helpers.Trace.VISIBLE_TRACE_EVENT_TYPES.values().toArray();\n const filter =\n new TraceFilter.VisibleEventsFilter(visibleEvents.concat([Types.Events.Name.SYNTHETIC_NETWORK_REQUEST]));\n\n // The bottom up root node handles all the \"in Tracebounds\" checks we need for the insight.\n const startTime = Helpers.Timing.microToMilli(tracebounds.min);\n const endTime = Helpers.Timing.microToMilli(tracebounds.max);\n const node = new TraceTree.BottomUpRootNode(mainThreadEvents, {\n textFilter: new TraceFilter.ExclusiveNameFilter([]),\n filters: [filter],\n startTime,\n endTime,\n eventGroupIdCallback: groupingFunction,\n calculateTransferSize: true,\n // Ensure we group by 3P alongside eventID for correct 3P grouping.\n forceGroupIdCallback: true,\n }) as TraceTree.BottomUpRootNode;\n return node;\n}\n"]}
1
+ {"version":3,"file":"ThirdParties.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/extras/ThirdParties.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 ThirdPartyWeb from '../../../third_party/third-party-web/third-party-web.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport * as TraceFilter from './TraceFilter.js';\nimport * as TraceTree from './TraceTree.js';\n\nexport type Entity = typeof ThirdPartyWeb.ThirdPartyWeb.entities[number];\n\ninterface BaseSummary {\n entity: Entity;\n transferSize: number;\n mainThreadTime: Types.Timing.Milli;\n}\n\nexport interface EntitySummary extends BaseSummary {\n relatedEvents: Types.Events.Event[];\n}\n\nexport interface URLSummary extends BaseSummary {\n url: string;\n request?: Types.Events.SyntheticNetworkRequest;\n}\n\n/**\n *\n * Returns Main frame main thread events.\n * These events are inline with the ones used by selectedEvents() of TimelineTreeViews\n */\nfunction collectMainThreadActivity(parsedTrace: Handlers.Types.ParsedTrace): Types.Events.Event[] {\n // TODO: Note b/402658800 could be an issue here.\n const mainFrameMainThread = parsedTrace.Renderer.processes.values()\n .find(p => {\n const url = p.url ?? '';\n // Frame url checked a la CompatibilityTracksAppenders's addThreadAppenders\n return p.isOnMainFrame && !url.startsWith('about:') && !url.startsWith('chrome:');\n })\n ?.threads.values()\n .find(t => t.name === 'CrRendererMain');\n\n if (!mainFrameMainThread) {\n return [];\n }\n\n return mainFrameMainThread.entries;\n}\n\nexport function summarizeByThirdParty(\n parsedTrace: Handlers.Types.ParsedTrace, traceBounds: Types.Timing.TraceWindowMicro): EntitySummary[] {\n const mainThreadEvents = collectMainThreadActivity(parsedTrace).sort(Helpers.Trace.eventTimeComparator);\n const groupingFunction = (event: Types.Events.Event): string => {\n const entity = parsedTrace.Renderer.entityMappings.entityByEvent.get(event);\n return entity?.name ?? '';\n };\n const node = getBottomUpTree(mainThreadEvents, traceBounds, groupingFunction);\n const summaries = summarizeBottomUpByEntity(node, parsedTrace);\n\n return summaries;\n}\n\n/**\n * Used only by Lighthouse.\n */\nexport function summarizeByURL(\n parsedTrace: Handlers.Types.ParsedTrace, traceBounds: Types.Timing.TraceWindowMicro): URLSummary[] {\n const mainThreadEvents = collectMainThreadActivity(parsedTrace).sort(Helpers.Trace.eventTimeComparator);\n const groupingFunction = (event: Types.Events.Event): string => {\n return Handlers.Helpers.getNonResolvedURL(event, parsedTrace) ?? '';\n };\n const node = getBottomUpTree(mainThreadEvents, traceBounds, groupingFunction);\n const summaries = summarizeBottomUpByURL(node, parsedTrace);\n\n return summaries;\n}\n\nfunction summarizeBottomUpByEntity(\n root: TraceTree.BottomUpRootNode, parsedTrace: Handlers.Types.ParsedTrace): EntitySummary[] {\n const summaries: EntitySummary[] = [];\n\n // Top nodes are the 3P entities.\n const topNodes = [...root.children().values()].flat();\n for (const node of topNodes) {\n if (node.id === '') {\n continue;\n }\n\n const entity = parsedTrace.Renderer.entityMappings.entityByEvent.get(node.event);\n if (!entity) {\n continue;\n }\n\n // Lets use the mapper events as our source of events, since we use the main thread to construct\n // the bottom up tree. The mapper will give us all related events.\n const summary: EntitySummary = {\n transferSize: node.transferSize,\n mainThreadTime: Types.Timing.Milli(node.selfTime),\n entity,\n relatedEvents: parsedTrace.Renderer.entityMappings.eventsByEntity.get(entity) ?? [],\n };\n summaries.push(summary);\n }\n\n return summaries;\n}\n\nfunction summarizeBottomUpByURL(\n root: TraceTree.BottomUpRootNode, parsedTrace: Handlers.Types.ParsedTrace): URLSummary[] {\n const summaries: URLSummary[] = [];\n const allRequests = parsedTrace.NetworkRequests.byTime;\n\n // Top nodes are URLs.\n const topNodes = [...root.children().values()].flat();\n for (const node of topNodes) {\n if (node.id === '' || typeof node.id !== 'string') {\n continue;\n }\n\n const entity = parsedTrace.Renderer.entityMappings.entityByEvent.get(node.event);\n if (!entity) {\n continue;\n }\n\n const url = node.id;\n const request = allRequests.find(r => r.args.data.url === url);\n\n const summary: URLSummary = {\n request,\n url,\n entity,\n transferSize: node.transferSize,\n mainThreadTime: Types.Timing.Milli(node.selfTime),\n };\n summaries.push(summary);\n }\n\n return summaries;\n}\n\nfunction getBottomUpTree(\n mainThreadEvents: Types.Events.Event[], tracebounds: Types.Timing.TraceWindowMicro,\n groupingFunction: ((arg0: Types.Events.Event) => string)|null): TraceTree.BottomUpRootNode {\n // Use the same filtering as front_end/panels/timeline/TimelineTreeView.ts.\n const visibleEvents = Helpers.Trace.VISIBLE_TRACE_EVENT_TYPES.values().toArray();\n const filter =\n new TraceFilter.VisibleEventsFilter(visibleEvents.concat([Types.Events.Name.SYNTHETIC_NETWORK_REQUEST]));\n\n // The bottom up root node handles all the \"in Tracebounds\" checks we need for the insight.\n const startTime = Helpers.Timing.microToMilli(tracebounds.min);\n const endTime = Helpers.Timing.microToMilli(tracebounds.max);\n const node = new TraceTree.BottomUpRootNode(mainThreadEvents, {\n textFilter: new TraceFilter.ExclusiveNameFilter([]),\n filters: [filter],\n startTime,\n endTime,\n eventGroupIdCallback: groupingFunction,\n calculateTransferSize: true,\n // Ensure we group by 3P alongside eventID for correct 3P grouping.\n forceGroupIdCallback: true,\n }) as TraceTree.BottomUpRootNode;\n return node;\n}\n"]}