@paulirish/trace_engine 0.0.61 → 0.0.62

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 (260) hide show
  1. package/.tmp/tsbuildinfo/analyze-trace.d.mts.map +1 -1
  2. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  3. package/analyze-inspector-issues.mjs +1 -1
  4. package/analyze-trace.mjs +1 -2
  5. package/core/platform/ArrayUtilities.d.ts +2 -0
  6. package/core/platform/ArrayUtilities.js +11 -1
  7. package/core/platform/ArrayUtilities.js.map +1 -1
  8. package/core/platform/HostRuntime.d.ts +4 -0
  9. package/core/platform/HostRuntime.js +25 -0
  10. package/core/platform/HostRuntime.js.map +1 -0
  11. package/core/platform/KeyboardUtilities.d.ts +6 -2
  12. package/core/platform/KeyboardUtilities.js.map +1 -1
  13. package/core/platform/StringUtilities.d.ts +2 -0
  14. package/core/platform/StringUtilities.js +64 -13
  15. package/core/platform/StringUtilities.js.map +1 -1
  16. package/core/platform/api/HostRuntime.d.ts +36 -0
  17. package/core/platform/api/HostRuntime.js +5 -0
  18. package/core/platform/api/HostRuntime.js.map +1 -0
  19. package/core/platform/api/api-tsconfig.json +43 -0
  20. package/core/platform/api/api.d.ts +2 -0
  21. package/core/platform/api/api.js +6 -0
  22. package/core/platform/api/api.js.map +1 -0
  23. package/core/platform/api/api_node_typecheck-tsconfig.json +48 -0
  24. package/core/platform/api/bundle-tsconfig.json +1 -0
  25. package/core/platform/api/devtools_entrypoint-bundle-typescript-tsconfig.json +48 -0
  26. package/core/platform/browser/HostRuntime.d.ts +2 -0
  27. package/core/platform/browser/HostRuntime.js +64 -0
  28. package/core/platform/browser/HostRuntime.js.map +1 -0
  29. package/core/platform/browser/browser-tsconfig.json +48 -0
  30. package/core/platform/browser/browser.d.ts +2 -0
  31. package/core/platform/browser/browser.js +6 -0
  32. package/core/platform/browser/browser.js.map +1 -0
  33. package/core/platform/browser/bundle-tsconfig.json +1 -0
  34. package/core/platform/browser/devtools_entrypoint-bundle-typescript-tsconfig.json +48 -0
  35. package/core/platform/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  36. package/core/platform/node/HostRuntime.d.ts +2 -0
  37. package/core/platform/node/HostRuntime.js +73 -0
  38. package/core/platform/node/HostRuntime.js.map +1 -0
  39. package/core/platform/node/bundle-tsconfig.json +1 -0
  40. package/core/platform/node/devtools_entrypoint-bundle-typescript-tsconfig.json +48 -0
  41. package/core/platform/node/node-tsconfig.json +52 -0
  42. package/core/platform/node/node.d.ts +2 -0
  43. package/core/platform/node/node.js +6 -0
  44. package/core/platform/node/node.js.map +1 -0
  45. package/core/platform/platform-tsconfig.json +17 -5
  46. package/core/platform/platform.d.ts +2 -2
  47. package/core/platform/platform.js +2 -2
  48. package/core/platform/platform.js.map +1 -1
  49. package/core/platform/platform_node_typecheck-tsconfig.json +74 -0
  50. package/generated/protocol.d.ts +1507 -583
  51. package/locales/af.json +74 -38
  52. package/locales/am.json +73 -37
  53. package/locales/ar.json +72 -36
  54. package/locales/as.json +74 -38
  55. package/locales/az.json +73 -37
  56. package/locales/be.json +72 -36
  57. package/locales/bg.json +72 -36
  58. package/locales/bn.json +74 -38
  59. package/locales/bs.json +72 -36
  60. package/locales/ca.json +72 -36
  61. package/locales/cs.json +72 -36
  62. package/locales/cy.json +73 -37
  63. package/locales/da.json +74 -38
  64. package/locales/de.json +72 -36
  65. package/locales/el.json +73 -37
  66. package/locales/en-GB.json +74 -38
  67. package/locales/en-US.json +86 -17
  68. package/locales/en-XL.json +86 -17
  69. package/locales/es-419.json +72 -36
  70. package/locales/es.json +73 -37
  71. package/locales/et.json +74 -38
  72. package/locales/eu.json +72 -36
  73. package/locales/fa.json +73 -37
  74. package/locales/fi.json +72 -36
  75. package/locales/fil.json +74 -38
  76. package/locales/fr-CA.json +72 -36
  77. package/locales/fr.json +162 -126
  78. package/locales/gl.json +73 -37
  79. package/locales/gu.json +73 -37
  80. package/locales/he.json +74 -38
  81. package/locales/hi.json +73 -37
  82. package/locales/hr.json +72 -36
  83. package/locales/hu.json +73 -37
  84. package/locales/hy.json +73 -37
  85. package/locales/id.json +74 -38
  86. package/locales/is.json +73 -37
  87. package/locales/it.json +72 -36
  88. package/locales/ja.json +72 -36
  89. package/locales/ka.json +73 -37
  90. package/locales/kk.json +72 -36
  91. package/locales/km.json +73 -37
  92. package/locales/kn.json +72 -36
  93. package/locales/ko.json +72 -36
  94. package/locales/ky.json +72 -36
  95. package/locales/lo.json +72 -36
  96. package/locales/lt.json +72 -36
  97. package/locales/lv.json +72 -36
  98. package/locales/mk.json +75 -39
  99. package/locales/ml.json +72 -36
  100. package/locales/mn.json +73 -37
  101. package/locales/mr.json +74 -38
  102. package/locales/ms.json +72 -36
  103. package/locales/my.json +72 -36
  104. package/locales/ne.json +73 -37
  105. package/locales/nl.json +73 -37
  106. package/locales/no.json +72 -36
  107. package/locales/or.json +72 -36
  108. package/locales/pa.json +72 -36
  109. package/locales/pl.json +72 -36
  110. package/locales/pt-PT.json +72 -36
  111. package/locales/pt.json +74 -38
  112. package/locales/ro.json +72 -36
  113. package/locales/ru.json +72 -36
  114. package/locales/si.json +72 -36
  115. package/locales/sk.json +72 -36
  116. package/locales/sl.json +72 -36
  117. package/locales/sq.json +72 -36
  118. package/locales/sr-Latn.json +73 -37
  119. package/locales/sr.json +73 -37
  120. package/locales/sv.json +75 -39
  121. package/locales/sw.json +74 -38
  122. package/locales/ta.json +73 -37
  123. package/locales/te.json +72 -36
  124. package/locales/th.json +73 -37
  125. package/locales/tr.json +72 -36
  126. package/locales/uk.json +72 -36
  127. package/locales/ur.json +72 -36
  128. package/locales/uz.json +73 -37
  129. package/locales/vi.json +74 -38
  130. package/locales/zh-HK.json +72 -36
  131. package/locales/zh-TW.json +74 -38
  132. package/locales/zh.json +75 -39
  133. package/locales/zu.json +73 -37
  134. package/models/cpu_profile/CPUProfileDataModel.d.ts +9 -0
  135. package/models/cpu_profile/CPUProfileDataModel.js +9 -7
  136. package/models/cpu_profile/CPUProfileDataModel.js.map +1 -1
  137. package/models/cpu_profile/ProfileTreeModel.d.ts +3 -2
  138. package/models/cpu_profile/ProfileTreeModel.js +6 -7
  139. package/models/cpu_profile/ProfileTreeModel.js.map +1 -1
  140. package/models/cpu_profile/cpu_profile-tsconfig.json +4 -3
  141. package/models/cpu_profile/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  142. package/models/trace/EntityMapper.d.ts +1 -0
  143. package/models/trace/EntityMapper.js +10 -0
  144. package/models/trace/EntityMapper.js.map +1 -1
  145. package/models/trace/EventsSerializer.js +10 -2
  146. package/models/trace/EventsSerializer.js.map +1 -1
  147. package/models/trace/LanternComputationData.d.ts +1 -1
  148. package/models/trace/LanternComputationData.js +3 -8
  149. package/models/trace/LanternComputationData.js.map +1 -1
  150. package/models/trace/ModelImpl.d.ts +1 -0
  151. package/models/trace/ModelImpl.js +9 -6
  152. package/models/trace/ModelImpl.js.map +1 -1
  153. package/models/trace/Processor.js +23 -23
  154. package/models/trace/Processor.js.map +1 -1
  155. package/models/trace/Styles.js +13 -5
  156. package/models/trace/Styles.js.map +1 -1
  157. package/models/trace/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  158. package/models/trace/extras/Initiators.d.ts +12 -0
  159. package/models/trace/extras/Initiators.js +47 -0
  160. package/models/trace/extras/Initiators.js.map +1 -0
  161. package/models/trace/extras/TraceTree.js +13 -5
  162. package/models/trace/extras/TraceTree.js.map +1 -1
  163. package/models/trace/extras/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  164. package/models/trace/extras/extras-tsconfig.json +11 -3
  165. package/models/trace/extras/extras.d.ts +0 -1
  166. package/models/trace/extras/extras.js +0 -1
  167. package/models/trace/extras/extras.js.map +1 -1
  168. package/models/trace/handlers/LargestImagePaintHandler.js +2 -2
  169. package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
  170. package/models/trace/handlers/LayoutShiftsHandler.js +1 -1
  171. package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
  172. package/models/trace/handlers/MetaHandler.d.ts +12 -1
  173. package/models/trace/handlers/MetaHandler.js +10 -1
  174. package/models/trace/handlers/MetaHandler.js.map +1 -1
  175. package/models/trace/handlers/NetworkRequestsHandler.d.ts +8 -1
  176. package/models/trace/handlers/NetworkRequestsHandler.js +22 -4
  177. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  178. package/models/trace/handlers/PageLoadMetricsHandler.d.ts +13 -3
  179. package/models/trace/handlers/PageLoadMetricsHandler.js +71 -27
  180. package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
  181. package/models/trace/handlers/SamplesHandler.js +59 -6
  182. package/models/trace/handlers/SamplesHandler.js.map +1 -1
  183. package/models/trace/handlers/ScriptsHandler.js +24 -0
  184. package/models/trace/handlers/ScriptsHandler.js.map +1 -1
  185. package/models/trace/handlers/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  186. package/models/trace/handlers/handlers-tsconfig.json +13 -3
  187. package/models/trace/helpers/Network.js +1 -1
  188. package/models/trace/helpers/Network.js.map +1 -1
  189. package/models/trace/helpers/SamplesIntegrator.js +1 -8
  190. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  191. package/models/trace/helpers/Timing.d.ts +1 -1
  192. package/models/trace/helpers/Timing.js +9 -2
  193. package/models/trace/helpers/Timing.js.map +1 -1
  194. package/models/trace/helpers/Trace.d.ts +1 -0
  195. package/models/trace/helpers/Trace.js +12 -5
  196. package/models/trace/helpers/Trace.js.map +1 -1
  197. package/models/trace/helpers/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  198. package/models/trace/helpers/helpers-tsconfig.json +7 -3
  199. package/models/trace/insights/CharacterSet.d.ts +49 -0
  200. package/models/trace/insights/CharacterSet.js +132 -0
  201. package/models/trace/insights/CharacterSet.js.map +1 -0
  202. package/models/trace/insights/Common.d.ts +2 -2
  203. package/models/trace/insights/Common.js +1 -6
  204. package/models/trace/insights/Common.js.map +1 -1
  205. package/models/trace/insights/ForcedReflow.d.ts +1 -1
  206. package/models/trace/insights/ForcedReflow.js +1 -1
  207. package/models/trace/insights/ForcedReflow.js.map +1 -1
  208. package/models/trace/insights/LCPBreakdown.d.ts +1 -1
  209. package/models/trace/insights/LCPBreakdown.js +2 -2
  210. package/models/trace/insights/LCPBreakdown.js.map +1 -1
  211. package/models/trace/insights/LCPDiscovery.d.ts +7 -3
  212. package/models/trace/insights/LCPDiscovery.js +16 -10
  213. package/models/trace/insights/LCPDiscovery.js.map +1 -1
  214. package/models/trace/insights/Models.d.ts +1 -0
  215. package/models/trace/insights/Models.js +1 -0
  216. package/models/trace/insights/Models.js.map +1 -1
  217. package/models/trace/insights/NetworkDependencyTree.js +4 -3
  218. package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
  219. package/models/trace/insights/RenderBlocking.d.ts +2 -2
  220. package/models/trace/insights/RenderBlocking.js +6 -6
  221. package/models/trace/insights/RenderBlocking.js.map +1 -1
  222. package/models/trace/insights/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  223. package/models/trace/insights/insights-tsconfig.json +26 -3
  224. package/models/trace/insights/types.d.ts +15 -5
  225. package/models/trace/insights/types.js +1 -0
  226. package/models/trace/insights/types.js.map +1 -1
  227. package/models/trace/lantern/core/core-tsconfig.json +4 -3
  228. package/models/trace/lantern/core/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  229. package/models/trace/lantern/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  230. package/models/trace/lantern/graph/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  231. package/models/trace/lantern/graph/graph-tsconfig.json +4 -3
  232. package/models/trace/lantern/lantern-tsconfig.json +4 -3
  233. package/models/trace/lantern/metrics/FirstContentfulPaint.js +6 -6
  234. package/models/trace/lantern/metrics/FirstContentfulPaint.js.map +1 -1
  235. package/models/trace/lantern/metrics/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  236. package/models/trace/lantern/metrics/metrics-tsconfig.json +4 -3
  237. package/models/trace/lantern/simulation/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  238. package/models/trace/lantern/simulation/simulation-tsconfig.json +4 -3
  239. package/models/trace/lantern/types/Lantern.d.ts +7 -7
  240. package/models/trace/lantern/types/Lantern.js.map +1 -1
  241. package/models/trace/lantern/types/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  242. package/models/trace/lantern/types/types-tsconfig.json +4 -3
  243. package/models/trace/trace-tsconfig.json +7 -3
  244. package/models/trace/types/Configuration.d.ts +1 -4
  245. package/models/trace/types/Configuration.js +0 -1
  246. package/models/trace/types/Configuration.js.map +1 -1
  247. package/models/trace/types/File.d.ts +8 -0
  248. package/models/trace/types/File.js.map +1 -1
  249. package/models/trace/types/TraceEvents.d.ts +97 -15
  250. package/models/trace/types/TraceEvents.js +44 -11
  251. package/models/trace/types/TraceEvents.js.map +1 -1
  252. package/models/trace/types/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  253. package/models/trace/types/types-tsconfig.json +10 -3
  254. package/package.json +1 -1
  255. package/test/test-trace-engine.mjs +8 -9
  256. package/.tmp/tsbuildinfo/models/trace/extras/polyfills.d.ts +0 -4
  257. package/.tmp/tsbuildinfo/models/trace/extras/polyfills.d.ts.map +0 -1
  258. package/core/platform/DOMUtilities.d.ts +0 -16
  259. package/core/platform/DOMUtilities.js +0 -123
  260. package/core/platform/DOMUtilities.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import * as Types from '../types/types.js';
2
2
  import type { HandlerName } from './types.js';
3
+ type AnyNavigationStart = Types.Events.NavigationStart | Types.Events.SoftNavigationStart;
3
4
  export declare function reset(): void;
4
5
  export declare function handleEvent(event: Types.Events.Event): void;
5
6
  export declare function getFrameIdForPageLoadEvent(event: Types.Events.PageLoadEvent): string;
@@ -34,13 +35,19 @@ export interface PageLoadMetricsData {
34
35
  * Given a frame id, the map points to another map from navigation id to metric scores.
35
36
  * The metric scores include the event related to the metric as well as the data regarding
36
37
  * the score itself.
38
+ *
39
+ * Includes soft navigations.
37
40
  */
38
- metricScoresByFrameId: Map<string, Map<string, Map<MetricName, MetricScore>>>;
41
+ metricScoresByFrameId: Map<string, Map<AnyNavigationStart, Map<MetricName, MetricScore>>>;
39
42
  /**
40
43
  * Page load events with no associated duration that happened in the
41
44
  * main frame.
42
45
  */
43
46
  allMarkerEvents: Types.Events.PageLoadEvent[];
47
+ /**
48
+ * MetaCharsetCheck events grouped by navigation.
49
+ */
50
+ metaCharsetCheckEventsByNavigation: Map<AnyNavigationStart, Types.Events.MetaCharsetCheck[]>;
44
51
  }
45
52
  export declare function data(): PageLoadMetricsData;
46
53
  export declare function deps(): HandlerName[];
@@ -59,13 +66,15 @@ export declare enum MetricName {
59
66
  TTI = "TTI",
60
67
  TBT = "TBT",
61
68
  CLS = "CLS",
62
- NAV = "Nav"
69
+ NAV = "Nav",
70
+ SOFT_NAV = "Nav*",
71
+ SOFT_LCP = "LCP*"
63
72
  }
64
73
  export interface MetricScore {
65
74
  metricName: MetricName;
66
75
  classification: ScoreClassification;
67
76
  event?: Types.Events.PageLoadEvent;
68
- navigation?: Types.Events.NavigationStart;
77
+ navigation?: AnyNavigationStart;
69
78
  estimated?: boolean;
70
79
  timing: Types.Timing.Micro;
71
80
  }
@@ -74,3 +83,4 @@ export type LCPMetricScore = MetricScore & {
74
83
  metricName: MetricName.LCP;
75
84
  };
76
85
  export declare function metricIsLCP(metric: MetricScore): metric is LCPMetricScore;
86
+ export {};
@@ -4,7 +4,9 @@
4
4
  /**
5
5
  * This handler stores page load metrics, including web vitals,
6
6
  * and exports them in the shape of a map with the following shape:
7
- * Map(FrameId -> Map(navigationID -> metrics) )
7
+ * Map(FrameId -> Map(navigation -> metrics) )
8
+ *
9
+ * Includes soft navigations.
8
10
  *
9
11
  * It also exports all markers in a trace in an array.
10
12
  *
@@ -27,11 +29,16 @@ let metricScoresByFrameId = new Map();
27
29
  * main frame.
28
30
  */
29
31
  let allMarkerEvents = [];
32
+ // Grouped by navigation to make it easier for insights to scope checks.
33
+ let metaCharsetCheckEventsByNavigation = new Map();
34
+ let metaCharsetCheckEventsArray = [];
30
35
  export function reset() {
31
36
  metricScoresByFrameId = new Map();
32
37
  pageLoadEventsArray = [];
33
38
  allMarkerEvents = [];
34
39
  selectedLCPCandidateEvents = new Set();
40
+ metaCharsetCheckEventsByNavigation = new Map();
41
+ metaCharsetCheckEventsArray = [];
35
42
  }
36
43
  let pageLoadEventsArray = [];
37
44
  // Once we've found the LCP events in the trace we want to fetch their DOM Node
@@ -44,16 +51,16 @@ let pageLoadEventsArray = [];
44
51
  // the candidates that were the actual LCP events.
45
52
  let selectedLCPCandidateEvents = new Set();
46
53
  export function handleEvent(event) {
54
+ if (Types.Events.isMetaCharsetCheck(event)) {
55
+ metaCharsetCheckEventsArray.push(event);
56
+ return;
57
+ }
47
58
  if (!Types.Events.eventIsPageLoadEvent(event)) {
48
59
  return;
49
60
  }
50
61
  pageLoadEventsArray.push(event);
51
62
  }
52
63
  function storePageLoadMetricAgainstNavigationId(navigation, event) {
53
- const navigationId = navigation.args.data?.navigationId;
54
- if (!navigationId) {
55
- throw new Error('Navigation event unexpectedly had no navigation ID.');
56
- }
57
64
  const frameId = getFrameIdForPageLoadEvent(event);
58
65
  const { rendererProcessesByFrame } = metaHandlerData();
59
66
  // If either of these pieces of data do not exist, the most likely
@@ -77,14 +84,14 @@ function storePageLoadMetricAgainstNavigationId(navigation, event) {
77
84
  const fcpTime = Types.Timing.Micro(event.ts - navigation.ts);
78
85
  const classification = scoreClassificationForFirstContentfulPaint(fcpTime);
79
86
  const metricScore = { event, metricName: MetricName.FCP, classification, navigation, timing: fcpTime };
80
- storeMetricScore(frameId, navigationId, metricScore);
87
+ storeMetricScore(frameId, navigation, metricScore);
81
88
  return;
82
89
  }
83
90
  if (Types.Events.isFirstPaint(event)) {
84
91
  const paintTime = Types.Timing.Micro(event.ts - navigation.ts);
85
92
  const classification = ScoreClassification.UNCLASSIFIED;
86
93
  const metricScore = { event, metricName: MetricName.FP, classification, navigation, timing: paintTime };
87
- storeMetricScore(frameId, navigationId, metricScore);
94
+ storeMetricScore(frameId, navigation, metricScore);
88
95
  return;
89
96
  }
90
97
  if (Types.Events.isMarkDOMContent(event)) {
@@ -96,7 +103,7 @@ function storePageLoadMetricAgainstNavigationId(navigation, event) {
96
103
  navigation,
97
104
  timing: dclTime,
98
105
  };
99
- storeMetricScore(frameId, navigationId, metricScore);
106
+ storeMetricScore(frameId, navigation, metricScore);
100
107
  return;
101
108
  }
102
109
  if (Types.Events.isInteractiveTime(event)) {
@@ -108,7 +115,7 @@ function storePageLoadMetricAgainstNavigationId(navigation, event) {
108
115
  navigation,
109
116
  timing: ttiValue,
110
117
  };
111
- storeMetricScore(frameId, navigationId, tti);
118
+ storeMetricScore(frameId, navigation, tti);
112
119
  const tbtValue = Helpers.Timing.milliToMicro(Types.Timing.Milli(event.args.args.total_blocking_time_ms));
113
120
  const tbt = {
114
121
  event,
@@ -117,7 +124,7 @@ function storePageLoadMetricAgainstNavigationId(navigation, event) {
117
124
  navigation,
118
125
  timing: tbtValue,
119
126
  };
120
- storeMetricScore(frameId, navigationId, tbt);
127
+ storeMetricScore(frameId, navigation, tbt);
121
128
  return;
122
129
  }
123
130
  if (Types.Events.isMarkLoad(event)) {
@@ -129,10 +136,10 @@ function storePageLoadMetricAgainstNavigationId(navigation, event) {
129
136
  navigation,
130
137
  timing: loadTime,
131
138
  };
132
- storeMetricScore(frameId, navigationId, metricScore);
139
+ storeMetricScore(frameId, navigation, metricScore);
133
140
  return;
134
141
  }
135
- if (Types.Events.isLargestContentfulPaintCandidate(event)) {
142
+ if (Types.Events.isAnyLargestContentfulPaintCandidate(event)) {
136
143
  const candidateIndex = event.args.data?.candidateIndex;
137
144
  if (!candidateIndex) {
138
145
  throw new Error('Largest Contentful Paint unexpectedly had no candidateIndex.');
@@ -146,15 +153,15 @@ function storePageLoadMetricAgainstNavigationId(navigation, event) {
146
153
  timing: lcpTime,
147
154
  };
148
155
  const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());
149
- const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());
156
+ const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());
150
157
  const lastLCPCandidate = metrics.get(MetricName.LCP);
151
158
  if (lastLCPCandidate === undefined) {
152
159
  selectedLCPCandidateEvents.add(lcp.event);
153
- storeMetricScore(frameId, navigationId, lcp);
160
+ storeMetricScore(frameId, navigation, lcp);
154
161
  return;
155
162
  }
156
163
  const lastLCPCandidateEvent = lastLCPCandidate.event;
157
- if (!Types.Events.isLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {
164
+ if (!Types.Events.isAnyLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {
158
165
  return;
159
166
  }
160
167
  const lastCandidateIndex = lastLCPCandidateEvent.args.data?.candidateIndex;
@@ -167,18 +174,21 @@ function storePageLoadMetricAgainstNavigationId(navigation, event) {
167
174
  if (lastCandidateIndex < candidateIndex) {
168
175
  selectedLCPCandidateEvents.delete(lastLCPCandidateEvent);
169
176
  selectedLCPCandidateEvents.add(lcp.event);
170
- storeMetricScore(frameId, navigationId, lcp);
177
+ storeMetricScore(frameId, navigation, lcp);
171
178
  }
172
179
  return;
173
180
  }
174
181
  if (Types.Events.isLayoutShift(event)) {
175
182
  return;
176
183
  }
184
+ if (Types.Events.isSoftNavigationStart(event)) {
185
+ return;
186
+ }
177
187
  return Platform.assertNever(event, `Unexpected event type: ${event}`);
178
188
  }
179
- function storeMetricScore(frameId, navigationId, metricScore) {
189
+ function storeMetricScore(frameId, navigation, metricScore) {
180
190
  const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());
181
- const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());
191
+ const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());
182
192
  // If an entry with that metric name is present, delete it so that the new entry that
183
193
  // will replace it is added at the end of the map. This way we guarantee the map entries
184
194
  // are ordered in ASC manner by timestamp.
@@ -187,8 +197,9 @@ function storeMetricScore(frameId, navigationId, metricScore) {
187
197
  }
188
198
  export function getFrameIdForPageLoadEvent(event) {
189
199
  if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isInteractiveTime(event) ||
190
- Types.Events.isLargestContentfulPaintCandidate(event) || Types.Events.isNavigationStart(event) ||
191
- Types.Events.isLayoutShift(event) || Types.Events.isFirstPaint(event)) {
200
+ Types.Events.isAnyLargestContentfulPaintCandidate(event) || Types.Events.isNavigationStart(event) ||
201
+ Types.Events.isSoftNavigationStart(event) || Types.Events.isLayoutShift(event) ||
202
+ Types.Events.isFirstPaint(event)) {
192
203
  return event.args.frame;
193
204
  }
194
205
  if (Types.Events.isMarkDOMContent(event) || Types.Events.isMarkLoad(event)) {
@@ -201,20 +212,35 @@ export function getFrameIdForPageLoadEvent(event) {
201
212
  Platform.assertNever(event, `Unexpected event type: ${event}`);
202
213
  }
203
214
  function getNavigationForPageLoadEvent(event) {
204
- if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isLargestContentfulPaintCandidate(event) ||
215
+ if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isAnyLargestContentfulPaintCandidate(event) ||
205
216
  Types.Events.isFirstPaint(event)) {
206
- const navigationId = event.args.data?.navigationId;
207
- if (!navigationId) {
208
- throw new Error('Trace event unexpectedly had no navigation ID.');
217
+ const { navigationsByNavigationId, softNavigationsById } = metaHandlerData();
218
+ let navigation;
219
+ if (event.name === Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION &&
220
+ event.args.data?.performanceTimelineNavigationId) {
221
+ navigation = softNavigationsById.get(event.args.data.performanceTimelineNavigationId);
222
+ if (!navigation) {
223
+ // The most recent soft navigation must have been before the trace started.
224
+ return null;
225
+ }
226
+ }
227
+ else {
228
+ const navigationId = event.args.data?.navigationId;
229
+ if (!navigationId) {
230
+ throw new Error(`Trace event unexpectedly had no navigation ID: ${JSON.stringify(event, null, 2)}`);
231
+ }
232
+ navigation = navigationsByNavigationId.get(navigationId);
209
233
  }
210
- const { navigationsByNavigationId } = metaHandlerData();
211
- const navigation = navigationsByNavigationId.get(navigationId);
212
234
  if (!navigation) {
213
235
  // This event's navigation has been filtered out by the meta handler as a noise event.
214
236
  return null;
215
237
  }
216
238
  return navigation;
217
239
  }
240
+ if (Types.Events.isSoftNavigationStart(event)) {
241
+ const { softNavigationsById } = metaHandlerData();
242
+ return softNavigationsById.get(event.args.context.performanceTimelineNavigationId) ?? null;
243
+ }
218
244
  if (Types.Events.isMarkDOMContent(event) || Types.Events.isInteractiveTime(event) ||
219
245
  Types.Events.isLayoutShift(event) || Types.Events.isMarkLoad(event)) {
220
246
  const frameId = getFrameIdForPageLoadEvent(event);
@@ -324,12 +350,26 @@ export async function finalize() {
324
350
  storePageLoadMetricAgainstNavigationId(navigation, pageLoadEvent);
325
351
  }
326
352
  }
353
+ const { navigationsByFrameId } = metaHandlerData();
354
+ metaCharsetCheckEventsArray.sort((a, b) => a.ts - b.ts);
355
+ for (const metaCharsetCheckEvent of metaCharsetCheckEventsArray) {
356
+ const frameId = metaCharsetCheckEvent.args.data?.frame;
357
+ if (!frameId) {
358
+ continue;
359
+ }
360
+ const navigation = Helpers.Trace.getNavigationForTraceEvent(metaCharsetCheckEvent, frameId, navigationsByFrameId);
361
+ if (!navigation) {
362
+ continue;
363
+ }
364
+ const eventsForNavigation = Platform.MapUtilities.getWithDefault(metaCharsetCheckEventsByNavigation, navigation, () => []);
365
+ eventsForNavigation.push(metaCharsetCheckEvent);
366
+ }
327
367
  // NOTE: if you are looking for the TBT calculation, it has temporarily been
328
368
  // removed. See crbug.com/1424335 for details.
329
369
  const allFinalLCPEvents = gatherFinalLCPEvents();
330
370
  const mainFrame = metaHandlerData().mainFrameId;
331
371
  // Filter out LCP candidates to use only definitive LCP values
332
- const allEventsButLCP = pageLoadEventsArray.filter(event => !Types.Events.isLargestContentfulPaintCandidate(event));
372
+ const allEventsButLCP = pageLoadEventsArray.filter(event => !Types.Events.isAnyLargestContentfulPaintCandidate(event));
333
373
  const markerEvents = [...allFinalLCPEvents, ...allEventsButLCP].filter(Types.Events.isMarkerEvent);
334
374
  // Filter by main frame and sort.
335
375
  allMarkerEvents =
@@ -339,6 +379,7 @@ export function data() {
339
379
  return {
340
380
  metricScoresByFrameId,
341
381
  allMarkerEvents,
382
+ metaCharsetCheckEventsByNavigation,
342
383
  };
343
384
  }
344
385
  export function deps() {
@@ -371,6 +412,9 @@ export var MetricName;
371
412
  MetricName["CLS"] = "CLS";
372
413
  // Navigation
373
414
  MetricName["NAV"] = "Nav";
415
+ // Soft Navigation and Soft Metrics
416
+ MetricName["SOFT_NAV"] = "Nav*";
417
+ MetricName["SOFT_LCP"] = "LCP*";
374
418
  // Note: INP is handled in UserInteractionsHandler
375
419
  })(MetricName || (MetricName = {}));
376
420
  export function metricIsLCP(metric) {
@@ -1 +1 @@
1
- {"version":3,"file":"PageLoadMetricsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/PageLoadMetricsHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2022 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * This handler stores page load metrics, including web vitals,\n * and exports them in the shape of a map with the following shape:\n * Map(FrameId -> Map(navigationID -> metrics) )\n *\n * It also exports all markers in a trace in an array.\n *\n * Some metrics are taken directly from a page load events (AKA markers) like DCL.\n * Others require processing multiple events to be determined, like CLS and TBT.\n */\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport type {HandlerName} from './types.js';\n\n// Small helpers to make the below type easier to read.\ntype FrameId = string;\ntype NavigationId = string;\n/**\n * This represents the metric scores for all navigations, for all frames in a trace.\n * Given a frame id, the map points to another map from navigation id to metric scores.\n * The metric scores include the event related to the metric as well as the data regarding\n * the score itself.\n */\nlet metricScoresByFrameId = new Map<FrameId, Map<NavigationId, Map<MetricName, MetricScore>>>();\n\n/**\n * Page load events with no associated duration that happened in the\n * main frame.\n */\nlet allMarkerEvents: Types.Events.PageLoadEvent[] = [];\n\nexport function reset(): void {\n metricScoresByFrameId = new Map();\n pageLoadEventsArray = [];\n allMarkerEvents = [];\n selectedLCPCandidateEvents = new Set();\n}\n\nlet pageLoadEventsArray: Types.Events.PageLoadEvent[] = [];\n\n// Once we've found the LCP events in the trace we want to fetch their DOM Node\n// from the backend. We could do this by parsing through our Map of frame =>\n// navigation => metric, but it's easier to keep a set of LCP events. As we\n// parse the trace, any time we store an LCP candidate as the potential LCP\n// event, we store the event here. If we later find a new candidate in the\n// trace, we store that and delete the prior event. When we've parsed the\n// entire trace this set will contain all the LCP events that were used - e.g.\n// the candidates that were the actual LCP events.\nlet selectedLCPCandidateEvents = new Set<Types.Events.LargestContentfulPaintCandidate>();\n\nexport function handleEvent(event: Types.Events.Event): void {\n if (!Types.Events.eventIsPageLoadEvent(event)) {\n return;\n }\n pageLoadEventsArray.push(event);\n}\n\nfunction storePageLoadMetricAgainstNavigationId(\n navigation: Types.Events.NavigationStart, event: Types.Events.PageLoadEvent): void {\n const navigationId = navigation.args.data?.navigationId;\n if (!navigationId) {\n throw new Error('Navigation event unexpectedly had no navigation ID.');\n }\n const frameId = getFrameIdForPageLoadEvent(event);\n const {rendererProcessesByFrame} = metaHandlerData();\n\n // If either of these pieces of data do not exist, the most likely\n // explanation is that the page load metric we found is for a frame/process\n // combo that the MetaHandler discarded. This typically happens if we get a\n // navigation event with an empty URL. Therefore, we will silently return and\n // drop this metric. If we didn't care about the navigation, we certainly do\n // not need to care about metrics for that navigation.\n const rendererProcessesInFrame = rendererProcessesByFrame.get(frameId);\n if (!rendererProcessesInFrame) {\n return;\n }\n const processData = rendererProcessesInFrame.get(event.pid);\n if (!processData) {\n return;\n }\n\n if (Types.Events.isNavigationStart(event)) {\n return;\n }\n\n if (Types.Events.isFirstContentfulPaint(event)) {\n const fcpTime = Types.Timing.Micro(event.ts - navigation.ts);\n const classification = scoreClassificationForFirstContentfulPaint(fcpTime);\n const metricScore = {event, metricName: MetricName.FCP, classification, navigation, timing: fcpTime};\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.Events.isFirstPaint(event)) {\n const paintTime = Types.Timing.Micro(event.ts - navigation.ts);\n const classification = ScoreClassification.UNCLASSIFIED;\n const metricScore = {event, metricName: MetricName.FP, classification, navigation, timing: paintTime};\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.Events.isMarkDOMContent(event)) {\n const dclTime = Types.Timing.Micro(event.ts - navigation.ts);\n const metricScore = {\n event,\n metricName: MetricName.DCL,\n classification: scoreClassificationForDOMContentLoaded(dclTime),\n navigation,\n timing: dclTime,\n };\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.Events.isInteractiveTime(event)) {\n const ttiValue = Types.Timing.Micro(event.ts - navigation.ts);\n const tti = {\n event,\n metricName: MetricName.TTI,\n classification: scoreClassificationForTimeToInteractive(ttiValue),\n navigation,\n timing: ttiValue,\n };\n storeMetricScore(frameId, navigationId, tti);\n\n const tbtValue = Helpers.Timing.milliToMicro(Types.Timing.Milli(event.args.args.total_blocking_time_ms));\n const tbt = {\n event,\n metricName: MetricName.TBT,\n classification: scoreClassificationForTotalBlockingTime(tbtValue),\n navigation,\n timing: tbtValue,\n };\n storeMetricScore(frameId, navigationId, tbt);\n return;\n }\n\n if (Types.Events.isMarkLoad(event)) {\n const loadTime = Types.Timing.Micro(event.ts - navigation.ts);\n const metricScore = {\n event,\n metricName: MetricName.L,\n classification: ScoreClassification.UNCLASSIFIED,\n navigation,\n timing: loadTime,\n };\n storeMetricScore(frameId, navigationId, metricScore);\n return;\n }\n\n if (Types.Events.isLargestContentfulPaintCandidate(event)) {\n const candidateIndex = event.args.data?.candidateIndex;\n if (!candidateIndex) {\n throw new Error('Largest Contentful Paint unexpectedly had no candidateIndex.');\n }\n const lcpTime = Types.Timing.Micro(event.ts - navigation.ts);\n const lcp = {\n event,\n metricName: MetricName.LCP,\n classification: scoreClassificationForLargestContentfulPaint(lcpTime),\n navigation,\n timing: lcpTime,\n };\n const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());\n const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());\n const lastLCPCandidate = metrics.get(MetricName.LCP);\n if (lastLCPCandidate === undefined) {\n selectedLCPCandidateEvents.add(lcp.event);\n storeMetricScore(frameId, navigationId, lcp);\n return;\n }\n const lastLCPCandidateEvent = lastLCPCandidate.event;\n\n if (!Types.Events.isLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {\n return;\n }\n const lastCandidateIndex = lastLCPCandidateEvent.args.data?.candidateIndex;\n if (!lastCandidateIndex) {\n // lastCandidateIndex cannot be undefined because we don't store candidates with\n // with an undefined candidateIndex value. This check is only to make TypeScript\n // treat the field as not undefined below.\n return;\n }\n if (lastCandidateIndex < candidateIndex) {\n selectedLCPCandidateEvents.delete(lastLCPCandidateEvent);\n selectedLCPCandidateEvents.add(lcp.event);\n storeMetricScore(frameId, navigationId, lcp);\n }\n return;\n }\n if (Types.Events.isLayoutShift(event)) {\n return;\n }\n return Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\nfunction storeMetricScore(frameId: string, navigationId: string, metricScore: MetricScore): void {\n const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());\n const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());\n // If an entry with that metric name is present, delete it so that the new entry that\n // will replace it is added at the end of the map. This way we guarantee the map entries\n // are ordered in ASC manner by timestamp.\n metrics.delete(metricScore.metricName);\n metrics.set(metricScore.metricName, metricScore);\n}\n\nexport function getFrameIdForPageLoadEvent(event: Types.Events.PageLoadEvent): string {\n if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isInteractiveTime(event) ||\n Types.Events.isLargestContentfulPaintCandidate(event) || Types.Events.isNavigationStart(event) ||\n Types.Events.isLayoutShift(event) || Types.Events.isFirstPaint(event)) {\n return event.args.frame;\n }\n if (Types.Events.isMarkDOMContent(event) || Types.Events.isMarkLoad(event)) {\n const frameId = event.args.data?.frame;\n if (!frameId) {\n throw new Error('MarkDOMContent unexpectedly had no frame ID.');\n }\n return frameId;\n }\n Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\nfunction getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent): Types.Events.NavigationStart|null {\n if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isLargestContentfulPaintCandidate(event) ||\n Types.Events.isFirstPaint(event)) {\n const navigationId = event.args.data?.navigationId;\n if (!navigationId) {\n throw new Error('Trace event unexpectedly had no navigation ID.');\n }\n const {navigationsByNavigationId} = metaHandlerData();\n const navigation = navigationsByNavigationId.get(navigationId);\n\n if (!navigation) {\n // This event's navigation has been filtered out by the meta handler as a noise event.\n return null;\n }\n return navigation;\n }\n\n if (Types.Events.isMarkDOMContent(event) || Types.Events.isInteractiveTime(event) ||\n Types.Events.isLayoutShift(event) || Types.Events.isMarkLoad(event)) {\n const frameId = getFrameIdForPageLoadEvent(event);\n const {navigationsByFrameId} = metaHandlerData();\n return Helpers.Trace.getNavigationForTraceEvent(event, frameId, navigationsByFrameId);\n }\n\n if (Types.Events.isNavigationStart(event)) {\n // We don't want to compute metrics of the navigation relative to itself, so we'll avoid avoid all that.\n return null;\n }\n\n return Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/fcp/\n */\nexport function scoreClassificationForFirstContentfulPaint(fcpScoreInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n const FCP_GOOD_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(1.8));\n const FCP_MEDIUM_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(3.0));\n let scoreClassification = ScoreClassification.BAD;\n if (fcpScoreInMicroseconds <= FCP_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (fcpScoreInMicroseconds <= FCP_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/interactive/#how-lighthouse-determines-your-tti-score\n */\n\nexport function scoreClassificationForTimeToInteractive(ttiTimeInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n const TTI_GOOD_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(3.8));\n const TTI_MEDIUM_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(7.3));\n let scoreClassification = ScoreClassification.BAD;\n if (ttiTimeInMicroseconds <= TTI_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (ttiTimeInMicroseconds <= TTI_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/lcp/#what-is-lcp\n */\n\nexport function scoreClassificationForLargestContentfulPaint(lcpTimeInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n const LCP_GOOD_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(2.5));\n const LCP_MEDIUM_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(4));\n let scoreClassification = ScoreClassification.BAD;\n if (lcpTimeInMicroseconds <= LCP_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (lcpTimeInMicroseconds <= LCP_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * DCL does not have a classification.\n */\nexport function scoreClassificationForDOMContentLoaded(_dclTimeInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n return ScoreClassification.UNCLASSIFIED;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/lighthouse-total-blocking-#time/\n */\n\nexport function scoreClassificationForTotalBlockingTime(tbtTimeInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n const TBT_GOOD_TIMING = Helpers.Timing.milliToMicro(Types.Timing.Milli(200));\n const TBT_MEDIUM_TIMING = Helpers.Timing.milliToMicro(Types.Timing.Milli(600));\n let scoreClassification = ScoreClassification.BAD;\n if (tbtTimeInMicroseconds <= TBT_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (tbtTimeInMicroseconds <= TBT_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Gets all the Largest Contentful Paint scores of all the frames in the\n * trace.\n */\nfunction gatherFinalLCPEvents(): Types.Events.PageLoadEvent[] {\n const allFinalLCPEvents: Types.Events.PageLoadEvent[] = [];\n const dataForAllFrames = [...metricScoresByFrameId.values()];\n const dataForAllNavigations = dataForAllFrames.flatMap(frameData => [...frameData.values()]);\n for (let i = 0; i < dataForAllNavigations.length; i++) {\n const navigationData = dataForAllNavigations[i];\n const lcpInNavigation = navigationData.get(MetricName.LCP);\n if (!lcpInNavigation?.event) {\n continue;\n }\n\n allFinalLCPEvents.push(lcpInNavigation.event);\n }\n return allFinalLCPEvents;\n}\n\nexport async function finalize(): Promise<void> {\n pageLoadEventsArray.sort((a, b) => a.ts - b.ts);\n\n for (const pageLoadEvent of pageLoadEventsArray) {\n const navigation = getNavigationForPageLoadEvent(pageLoadEvent);\n if (navigation) {\n // Event's navigation was not filtered out as noise.\n storePageLoadMetricAgainstNavigationId(navigation, pageLoadEvent);\n }\n }\n // NOTE: if you are looking for the TBT calculation, it has temporarily been\n // removed. See crbug.com/1424335 for details.\n const allFinalLCPEvents = gatherFinalLCPEvents();\n const mainFrame = metaHandlerData().mainFrameId;\n // Filter out LCP candidates to use only definitive LCP values\n const allEventsButLCP = pageLoadEventsArray.filter(event => !Types.Events.isLargestContentfulPaintCandidate(event));\n const markerEvents = [...allFinalLCPEvents, ...allEventsButLCP].filter(Types.Events.isMarkerEvent);\n // Filter by main frame and sort.\n allMarkerEvents =\n markerEvents.filter(event => getFrameIdForPageLoadEvent(event) === mainFrame).sort((a, b) => a.ts - b.ts);\n}\n\nexport interface PageLoadMetricsData {\n /**\n * This represents the metric scores for all navigations, for all frames in a trace.\n * Given a frame id, the map points to another map from navigation id to metric scores.\n * The metric scores include the event related to the metric as well as the data regarding\n * the score itself.\n */\n metricScoresByFrameId: Map<string, Map<string, Map<MetricName, MetricScore>>>;\n /**\n * Page load events with no associated duration that happened in the\n * main frame.\n */\n allMarkerEvents: Types.Events.PageLoadEvent[];\n}\n\nexport function data(): PageLoadMetricsData {\n return {\n metricScoresByFrameId,\n allMarkerEvents,\n };\n}\n\nexport function deps(): HandlerName[] {\n return ['Meta'];\n}\n\nexport enum ScoreClassification {\n GOOD = 'good',\n OK = 'ok',\n BAD = 'bad',\n // Some metrics (such as DOMContentLoaded) don't have a Good/OK/Bad classification, hence this additional entry.\n UNCLASSIFIED = 'unclassified',\n}\n\nexport enum MetricName {\n // First Contentful Paint\n FCP = 'FCP',\n // First Paint\n FP = 'FP',\n // MarkLoad\n L = 'L',\n LCP = 'LCP',\n // Mark DOM Content\n DCL = 'DCL',\n // Time To Interactive\n TTI = 'TTI',\n // Total Blocking Time\n TBT = 'TBT',\n // Cumulative Layout Shift\n CLS = 'CLS',\n // Navigation\n NAV = 'Nav',\n // Note: INP is handled in UserInteractionsHandler\n}\n\nexport interface MetricScore {\n metricName: MetricName;\n classification: ScoreClassification;\n event?: Types.Events.PageLoadEvent;\n // The last navigation that occurred before this metric score.\n navigation?: Types.Events.NavigationStart;\n estimated?: boolean;\n timing: Types.Timing.Micro;\n}\n\nexport type LCPMetricScore = MetricScore&{\n event: Types.Events.LargestContentfulPaintCandidate,\n metricName: MetricName.LCP,\n};\n\nexport function metricIsLCP(metric: MetricScore): metric is LCPMetricScore {\n return metric.metricName === MetricName.LCP;\n}\n"]}
1
+ {"version":3,"file":"PageLoadMetricsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/PageLoadMetricsHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2022 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * This handler stores page load metrics, including web vitals,\n * and exports them in the shape of a map with the following shape:\n * Map(FrameId -> Map(navigation -> metrics) )\n *\n * Includes soft navigations.\n *\n * It also exports all markers in a trace in an array.\n *\n * Some metrics are taken directly from a page load events (AKA markers) like DCL.\n * Others require processing multiple events to be determined, like CLS and TBT.\n */\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport type {HandlerName} from './types.js';\n\n// Small helpers to make the below type easier to read.\ntype FrameId = string;\ntype AnyNavigationStart = Types.Events.NavigationStart|Types.Events.SoftNavigationStart;\n\n/**\n * This represents the metric scores for all navigations, for all frames in a trace.\n * Given a frame id, the map points to another map from navigation id to metric scores.\n * The metric scores include the event related to the metric as well as the data regarding\n * the score itself.\n */\nlet metricScoresByFrameId = new Map<FrameId, Map<AnyNavigationStart, Map<MetricName, MetricScore>>>();\n\n/**\n * Page load events with no associated duration that happened in the\n * main frame.\n */\nlet allMarkerEvents: Types.Events.PageLoadEvent[] = [];\n\n// Grouped by navigation to make it easier for insights to scope checks.\nlet metaCharsetCheckEventsByNavigation = new Map<AnyNavigationStart, Types.Events.MetaCharsetCheck[]>();\nlet metaCharsetCheckEventsArray: Types.Events.MetaCharsetCheck[] = [];\n\nexport function reset(): void {\n metricScoresByFrameId = new Map();\n pageLoadEventsArray = [];\n allMarkerEvents = [];\n selectedLCPCandidateEvents = new Set();\n metaCharsetCheckEventsByNavigation = new Map();\n metaCharsetCheckEventsArray = [];\n}\n\nlet pageLoadEventsArray: Types.Events.PageLoadEvent[] = [];\n\n// Once we've found the LCP events in the trace we want to fetch their DOM Node\n// from the backend. We could do this by parsing through our Map of frame =>\n// navigation => metric, but it's easier to keep a set of LCP events. As we\n// parse the trace, any time we store an LCP candidate as the potential LCP\n// event, we store the event here. If we later find a new candidate in the\n// trace, we store that and delete the prior event. When we've parsed the\n// entire trace this set will contain all the LCP events that were used - e.g.\n// the candidates that were the actual LCP events.\nlet selectedLCPCandidateEvents = new Set<Types.Events.AnyLargestContentfulPaintCandidate>();\n\nexport function handleEvent(event: Types.Events.Event): void {\n if (Types.Events.isMetaCharsetCheck(event)) {\n metaCharsetCheckEventsArray.push(event);\n return;\n }\n\n if (!Types.Events.eventIsPageLoadEvent(event)) {\n return;\n }\n pageLoadEventsArray.push(event);\n}\n\nfunction storePageLoadMetricAgainstNavigationId(\n navigation: AnyNavigationStart, event: Types.Events.PageLoadEvent): void {\n const frameId = getFrameIdForPageLoadEvent(event);\n const {rendererProcessesByFrame} = metaHandlerData();\n\n // If either of these pieces of data do not exist, the most likely\n // explanation is that the page load metric we found is for a frame/process\n // combo that the MetaHandler discarded. This typically happens if we get a\n // navigation event with an empty URL. Therefore, we will silently return and\n // drop this metric. If we didn't care about the navigation, we certainly do\n // not need to care about metrics for that navigation.\n const rendererProcessesInFrame = rendererProcessesByFrame.get(frameId);\n if (!rendererProcessesInFrame) {\n return;\n }\n const processData = rendererProcessesInFrame.get(event.pid);\n if (!processData) {\n return;\n }\n\n if (Types.Events.isNavigationStart(event)) {\n return;\n }\n\n if (Types.Events.isFirstContentfulPaint(event)) {\n const fcpTime = Types.Timing.Micro(event.ts - navigation.ts);\n const classification = scoreClassificationForFirstContentfulPaint(fcpTime);\n const metricScore = {event, metricName: MetricName.FCP, classification, navigation, timing: fcpTime};\n storeMetricScore(frameId, navigation, metricScore);\n return;\n }\n\n if (Types.Events.isFirstPaint(event)) {\n const paintTime = Types.Timing.Micro(event.ts - navigation.ts);\n const classification = ScoreClassification.UNCLASSIFIED;\n const metricScore = {event, metricName: MetricName.FP, classification, navigation, timing: paintTime};\n storeMetricScore(frameId, navigation, metricScore);\n return;\n }\n\n if (Types.Events.isMarkDOMContent(event)) {\n const dclTime = Types.Timing.Micro(event.ts - navigation.ts);\n const metricScore = {\n event,\n metricName: MetricName.DCL,\n classification: scoreClassificationForDOMContentLoaded(dclTime),\n navigation,\n timing: dclTime,\n };\n storeMetricScore(frameId, navigation, metricScore);\n return;\n }\n\n if (Types.Events.isInteractiveTime(event)) {\n const ttiValue = Types.Timing.Micro(event.ts - navigation.ts);\n const tti = {\n event,\n metricName: MetricName.TTI,\n classification: scoreClassificationForTimeToInteractive(ttiValue),\n navigation,\n timing: ttiValue,\n };\n storeMetricScore(frameId, navigation, tti);\n\n const tbtValue = Helpers.Timing.milliToMicro(Types.Timing.Milli(event.args.args.total_blocking_time_ms));\n const tbt = {\n event,\n metricName: MetricName.TBT,\n classification: scoreClassificationForTotalBlockingTime(tbtValue),\n navigation,\n timing: tbtValue,\n };\n storeMetricScore(frameId, navigation, tbt);\n return;\n }\n\n if (Types.Events.isMarkLoad(event)) {\n const loadTime = Types.Timing.Micro(event.ts - navigation.ts);\n const metricScore = {\n event,\n metricName: MetricName.L,\n classification: ScoreClassification.UNCLASSIFIED,\n navigation,\n timing: loadTime,\n };\n storeMetricScore(frameId, navigation, metricScore);\n return;\n }\n\n if (Types.Events.isAnyLargestContentfulPaintCandidate(event)) {\n const candidateIndex = event.args.data?.candidateIndex;\n if (!candidateIndex) {\n throw new Error('Largest Contentful Paint unexpectedly had no candidateIndex.');\n }\n const lcpTime = Types.Timing.Micro(event.ts - navigation.ts);\n const lcp = {\n event,\n metricName: MetricName.LCP,\n classification: scoreClassificationForLargestContentfulPaint(lcpTime),\n navigation,\n timing: lcpTime,\n };\n const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());\n const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());\n const lastLCPCandidate = metrics.get(MetricName.LCP);\n if (lastLCPCandidate === undefined) {\n selectedLCPCandidateEvents.add(lcp.event);\n storeMetricScore(frameId, navigation, lcp);\n return;\n }\n const lastLCPCandidateEvent = lastLCPCandidate.event;\n\n if (!Types.Events.isAnyLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {\n return;\n }\n const lastCandidateIndex = lastLCPCandidateEvent.args.data?.candidateIndex;\n if (!lastCandidateIndex) {\n // lastCandidateIndex cannot be undefined because we don't store candidates with\n // with an undefined candidateIndex value. This check is only to make TypeScript\n // treat the field as not undefined below.\n return;\n }\n if (lastCandidateIndex < candidateIndex) {\n selectedLCPCandidateEvents.delete(lastLCPCandidateEvent);\n selectedLCPCandidateEvents.add(lcp.event);\n storeMetricScore(frameId, navigation, lcp);\n }\n return;\n }\n if (Types.Events.isLayoutShift(event)) {\n return;\n }\n if (Types.Events.isSoftNavigationStart(event)) {\n return;\n }\n return Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\nfunction storeMetricScore(frameId: string, navigation: AnyNavigationStart, metricScore: MetricScore): void {\n const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());\n const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());\n // If an entry with that metric name is present, delete it so that the new entry that\n // will replace it is added at the end of the map. This way we guarantee the map entries\n // are ordered in ASC manner by timestamp.\n metrics.delete(metricScore.metricName);\n metrics.set(metricScore.metricName, metricScore);\n}\n\nexport function getFrameIdForPageLoadEvent(event: Types.Events.PageLoadEvent): string {\n if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isInteractiveTime(event) ||\n Types.Events.isAnyLargestContentfulPaintCandidate(event) || Types.Events.isNavigationStart(event) ||\n Types.Events.isSoftNavigationStart(event) || Types.Events.isLayoutShift(event) ||\n Types.Events.isFirstPaint(event)) {\n return event.args.frame;\n }\n if (Types.Events.isMarkDOMContent(event) || Types.Events.isMarkLoad(event)) {\n const frameId = event.args.data?.frame;\n if (!frameId) {\n throw new Error('MarkDOMContent unexpectedly had no frame ID.');\n }\n return frameId;\n }\n Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\nfunction getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent): AnyNavigationStart|null {\n if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isAnyLargestContentfulPaintCandidate(event) ||\n Types.Events.isFirstPaint(event)) {\n const {navigationsByNavigationId, softNavigationsById} = metaHandlerData();\n\n let navigation;\n if (event.name === Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION &&\n event.args.data?.performanceTimelineNavigationId) {\n navigation = softNavigationsById.get(event.args.data.performanceTimelineNavigationId);\n if (!navigation) {\n // The most recent soft navigation must have been before the trace started.\n return null;\n }\n } else {\n const navigationId = event.args.data?.navigationId;\n if (!navigationId) {\n throw new Error(`Trace event unexpectedly had no navigation ID: ${JSON.stringify(event, null, 2)}`);\n }\n\n navigation = navigationsByNavigationId.get(navigationId);\n }\n\n if (!navigation) {\n // This event's navigation has been filtered out by the meta handler as a noise event.\n return null;\n }\n return navigation;\n }\n\n if (Types.Events.isSoftNavigationStart(event)) {\n const {softNavigationsById} = metaHandlerData();\n return softNavigationsById.get(event.args.context.performanceTimelineNavigationId) ?? null;\n }\n\n if (Types.Events.isMarkDOMContent(event) || Types.Events.isInteractiveTime(event) ||\n Types.Events.isLayoutShift(event) || Types.Events.isMarkLoad(event)) {\n const frameId = getFrameIdForPageLoadEvent(event);\n const {navigationsByFrameId} = metaHandlerData();\n return Helpers.Trace.getNavigationForTraceEvent(event, frameId, navigationsByFrameId);\n }\n\n if (Types.Events.isNavigationStart(event)) {\n // We don't want to compute metrics of the navigation relative to itself, so we'll avoid avoid all that.\n return null;\n }\n\n return Platform.assertNever(event, `Unexpected event type: ${event}`);\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/fcp/\n */\nexport function scoreClassificationForFirstContentfulPaint(fcpScoreInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n const FCP_GOOD_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(1.8));\n const FCP_MEDIUM_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(3.0));\n let scoreClassification = ScoreClassification.BAD;\n if (fcpScoreInMicroseconds <= FCP_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (fcpScoreInMicroseconds <= FCP_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/interactive/#how-lighthouse-determines-your-tti-score\n */\n\nexport function scoreClassificationForTimeToInteractive(ttiTimeInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n const TTI_GOOD_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(3.8));\n const TTI_MEDIUM_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(7.3));\n let scoreClassification = ScoreClassification.BAD;\n if (ttiTimeInMicroseconds <= TTI_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (ttiTimeInMicroseconds <= TTI_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/lcp/#what-is-lcp\n */\n\nexport function scoreClassificationForLargestContentfulPaint(lcpTimeInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n const LCP_GOOD_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(2.5));\n const LCP_MEDIUM_TIMING = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(4));\n let scoreClassification = ScoreClassification.BAD;\n if (lcpTimeInMicroseconds <= LCP_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (lcpTimeInMicroseconds <= LCP_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * DCL does not have a classification.\n */\nexport function scoreClassificationForDOMContentLoaded(_dclTimeInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n return ScoreClassification.UNCLASSIFIED;\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/lighthouse-total-blocking-#time/\n */\n\nexport function scoreClassificationForTotalBlockingTime(tbtTimeInMicroseconds: Types.Timing.Micro):\n ScoreClassification {\n const TBT_GOOD_TIMING = Helpers.Timing.milliToMicro(Types.Timing.Milli(200));\n const TBT_MEDIUM_TIMING = Helpers.Timing.milliToMicro(Types.Timing.Milli(600));\n let scoreClassification = ScoreClassification.BAD;\n if (tbtTimeInMicroseconds <= TBT_MEDIUM_TIMING) {\n scoreClassification = ScoreClassification.OK;\n }\n if (tbtTimeInMicroseconds <= TBT_GOOD_TIMING) {\n scoreClassification = ScoreClassification.GOOD;\n }\n return scoreClassification;\n}\n\n/**\n * Gets all the Largest Contentful Paint scores of all the frames in the\n * trace.\n */\nfunction gatherFinalLCPEvents(): Types.Events.PageLoadEvent[] {\n const allFinalLCPEvents: Types.Events.PageLoadEvent[] = [];\n const dataForAllFrames = [...metricScoresByFrameId.values()];\n const dataForAllNavigations = dataForAllFrames.flatMap(frameData => [...frameData.values()]);\n for (let i = 0; i < dataForAllNavigations.length; i++) {\n const navigationData = dataForAllNavigations[i];\n const lcpInNavigation = navigationData.get(MetricName.LCP);\n if (!lcpInNavigation?.event) {\n continue;\n }\n\n allFinalLCPEvents.push(lcpInNavigation.event);\n }\n return allFinalLCPEvents;\n}\n\nexport async function finalize(): Promise<void> {\n pageLoadEventsArray.sort((a, b) => a.ts - b.ts);\n\n for (const pageLoadEvent of pageLoadEventsArray) {\n const navigation = getNavigationForPageLoadEvent(pageLoadEvent);\n if (navigation) {\n // Event's navigation was not filtered out as noise.\n storePageLoadMetricAgainstNavigationId(navigation, pageLoadEvent);\n }\n }\n\n const {navigationsByFrameId} = metaHandlerData();\n metaCharsetCheckEventsArray.sort((a, b) => a.ts - b.ts);\n for (const metaCharsetCheckEvent of metaCharsetCheckEventsArray) {\n const frameId = metaCharsetCheckEvent.args.data?.frame;\n if (!frameId) {\n continue;\n }\n const navigation = Helpers.Trace.getNavigationForTraceEvent(metaCharsetCheckEvent, frameId, navigationsByFrameId);\n if (!navigation) {\n continue;\n }\n const eventsForNavigation =\n Platform.MapUtilities.getWithDefault(metaCharsetCheckEventsByNavigation, navigation, () => []);\n eventsForNavigation.push(metaCharsetCheckEvent);\n }\n\n // NOTE: if you are looking for the TBT calculation, it has temporarily been\n // removed. See crbug.com/1424335 for details.\n const allFinalLCPEvents = gatherFinalLCPEvents();\n const mainFrame = metaHandlerData().mainFrameId;\n // Filter out LCP candidates to use only definitive LCP values\n const allEventsButLCP =\n pageLoadEventsArray.filter(event => !Types.Events.isAnyLargestContentfulPaintCandidate(event));\n const markerEvents = [...allFinalLCPEvents, ...allEventsButLCP].filter(Types.Events.isMarkerEvent);\n // Filter by main frame and sort.\n allMarkerEvents =\n markerEvents.filter(event => getFrameIdForPageLoadEvent(event) === mainFrame).sort((a, b) => a.ts - b.ts);\n}\n\nexport interface PageLoadMetricsData {\n /**\n * This represents the metric scores for all navigations, for all frames in a trace.\n * Given a frame id, the map points to another map from navigation id to metric scores.\n * The metric scores include the event related to the metric as well as the data regarding\n * the score itself.\n *\n * Includes soft navigations.\n */\n metricScoresByFrameId: Map<string, Map<AnyNavigationStart, Map<MetricName, MetricScore>>>;\n /**\n * Page load events with no associated duration that happened in the\n * main frame.\n */\n allMarkerEvents: Types.Events.PageLoadEvent[];\n /**\n * MetaCharsetCheck events grouped by navigation.\n */\n metaCharsetCheckEventsByNavigation: Map<AnyNavigationStart, Types.Events.MetaCharsetCheck[]>;\n}\n\nexport function data(): PageLoadMetricsData {\n return {\n metricScoresByFrameId,\n allMarkerEvents,\n metaCharsetCheckEventsByNavigation,\n };\n}\n\nexport function deps(): HandlerName[] {\n return ['Meta'];\n}\n\nexport enum ScoreClassification {\n GOOD = 'good',\n OK = 'ok',\n BAD = 'bad',\n // Some metrics (such as DOMContentLoaded) don't have a Good/OK/Bad classification, hence this additional entry.\n UNCLASSIFIED = 'unclassified',\n}\n\nexport enum MetricName {\n // First Contentful Paint\n FCP = 'FCP',\n // First Paint\n FP = 'FP',\n // MarkLoad\n L = 'L',\n LCP = 'LCP',\n // Mark DOM Content\n DCL = 'DCL',\n // Time To Interactive\n TTI = 'TTI',\n // Total Blocking Time\n TBT = 'TBT',\n // Cumulative Layout Shift\n CLS = 'CLS',\n // Navigation\n NAV = 'Nav',\n // Soft Navigation and Soft Metrics\n SOFT_NAV = 'Nav*',\n SOFT_LCP = 'LCP*',\n // Note: INP is handled in UserInteractionsHandler\n}\n\nexport interface MetricScore {\n metricName: MetricName;\n classification: ScoreClassification;\n event?: Types.Events.PageLoadEvent;\n // The last navigation that occurred before this metric score.\n navigation?: AnyNavigationStart;\n estimated?: boolean;\n timing: Types.Timing.Micro;\n}\n\nexport type LCPMetricScore = MetricScore&{\n event: Types.Events.LargestContentfulPaintCandidate,\n metricName: MetricName.LCP,\n};\n\nexport function metricIsLCP(metric: MetricScore): metric is LCPMetricScore {\n return metric.metricName === MetricName.LCP;\n}\n"]}
@@ -17,23 +17,66 @@ let entryToNode = new Map();
17
17
  // are matched by profile id, which we then finish processing to export
18
18
  // events matched by thread id.
19
19
  let preprocessedData = new Map();
20
+ /**
21
+ * Profile source selection priority when multiple profiles exist for the same thread.
22
+ *
23
+ * Profile sources and their typical scenarios:
24
+ * - 'Internal': Browser-initiated profiling performance panel traces.
25
+ * This is the profiling mechanism when users click "Record" in the Devtools UI.
26
+ * - 'Inspector': User-initiated via console.profile()/profileEnd() calls.
27
+ * Represents explicit developer intent to profile specific code.
28
+ * - 'SelfProfiling': Page-initiated via JS Self-Profiling API.
29
+ * Lower signal vs the two above; treated as fallback.
30
+ *
31
+ * Selection strategy:
32
+ * - CPU Profile mode: Prefer 'Inspector' (explicit user request).
33
+ * - Performance trace: Prefer 'Internal' (integrated timeline context), then 'Inspector'.
34
+ * - Sources not in the priority list (including 'SelfProfiling') act as fallbacks.
35
+ * When no priority source matches, the first candidate profile is selected.
36
+ */
37
+ const PROFILE_SOURCES_BY_PRIORITY = {
38
+ cpuProfile: ['Inspector'],
39
+ performanceTrace: ['Internal', 'Inspector'],
40
+ };
20
41
  function parseCPUProfileData(parseOptions) {
42
+ const priorityList = parseOptions.isCPUProfile ? PROFILE_SOURCES_BY_PRIORITY.cpuProfile : PROFILE_SOURCES_BY_PRIORITY.performanceTrace;
21
43
  for (const [processId, profiles] of preprocessedData) {
44
+ const profilesByThread = new Map();
22
45
  for (const [profileId, preProcessedData] of profiles) {
23
46
  const threadId = preProcessedData.threadId;
24
- if (!preProcessedData.rawProfile.nodes.length || threadId === undefined) {
47
+ if (threadId === undefined) {
48
+ continue;
49
+ }
50
+ const listForThread = Platform.MapUtilities.getWithDefault(profilesByThread, threadId, () => []);
51
+ listForThread.push({ id: profileId, data: preProcessedData });
52
+ }
53
+ for (const [threadId, candidates] of profilesByThread) {
54
+ if (!candidates.length) {
55
+ continue;
56
+ }
57
+ let chosen = candidates[0];
58
+ for (const source of priorityList) {
59
+ const match = candidates.find(p => p.data.source === source);
60
+ if (match) {
61
+ chosen = match;
62
+ break;
63
+ }
64
+ }
65
+ const chosenData = chosen.data;
66
+ if (!chosenData.rawProfile.nodes.length) {
25
67
  continue;
26
68
  }
27
69
  const indexStack = [];
28
- const profileModel = new CPUProfile.CPUProfileDataModel.CPUProfileDataModel(preProcessedData.rawProfile);
70
+ const profileModel = new CPUProfile.CPUProfileDataModel.CPUProfileDataModel(chosenData.rawProfile);
29
71
  const profileTree = Helpers.TreeHelpers.makeEmptyTraceEntryTree();
30
72
  profileTree.maxDepth = profileModel.maxDepth;
73
+ const selectedProfileId = chosen.id;
31
74
  const finalizedData = {
32
- rawProfile: preProcessedData.rawProfile,
75
+ rawProfile: chosenData.rawProfile,
33
76
  parsedProfile: profileModel,
34
77
  profileCalls: [],
35
78
  profileTree,
36
- profileId,
79
+ profileId: selectedProfileId,
37
80
  };
38
81
  const dataByThread = Platform.MapUtilities.getWithDefault(profilesInProcess, processId, () => new Map());
39
82
  dataByThread.set(threadId, finalizedData);
@@ -49,7 +92,7 @@ function parseCPUProfileData(parseOptions) {
49
92
  }
50
93
  const ts = Helpers.Timing.milliToMicro(Types.Timing.Milli(timeStampMilliseconds));
51
94
  const nodeId = node.id;
52
- const profileCall = Helpers.Trace.makeProfileCall(node, profileId, sampleIndex, ts, processId, threadId);
95
+ const profileCall = Helpers.Trace.makeProfileCall(node, selectedProfileId, sampleIndex, ts, processId, threadId);
53
96
  finalizedData.profileCalls.push(profileCall);
54
97
  indexStack.push(finalizedData.profileCalls.length - 1);
55
98
  const traceEntryNode = Helpers.TreeHelpers.makeEmptyTraceEntryNode(profileCall, nodeId);
@@ -68,7 +111,7 @@ function parseCPUProfileData(parseOptions) {
68
111
  }
69
112
  const { callFrame, ts, pid, tid } = profileCall;
70
113
  const traceEntryNode = entryToNode.get(profileCall);
71
- if (callFrame === undefined || ts === undefined || pid === undefined || profileId === undefined ||
114
+ if (callFrame === undefined || ts === undefined || pid === undefined || selectedProfileId === undefined ||
72
115
  tid === undefined || traceEntryNode === undefined) {
73
116
  return;
74
117
  }
@@ -119,6 +162,7 @@ export function handleEvent(event) {
119
162
  const profileData = getOrCreatePreProcessedData(event.pid, event.id);
120
163
  profileData.rawProfile.startTime = event.ts;
121
164
  profileData.threadId = event.tid;
165
+ assignProfileSourceIfKnown(profileData, event.args?.data?.source);
122
166
  return;
123
167
  }
124
168
  if (Types.Events.isProfileChunk(event)) {
@@ -146,9 +190,11 @@ export function handleEvent(event) {
146
190
  }
147
191
  const timeDeltas = event.args.data?.timeDeltas || [];
148
192
  const lines = event.args.data?.lines || Array(samples.length).fill(0);
193
+ const columns = event.args.data?.columns || Array(samples.length).fill(0);
149
194
  cdpProfile.samples?.push(...samples);
150
195
  cdpProfile.timeDeltas?.push(...timeDeltas);
151
196
  cdpProfile.lines?.push(...lines);
197
+ cdpProfile.columns?.push(...columns);
152
198
  if (traceIds) {
153
199
  cdpProfile.traceIds ??= {};
154
200
  for (const key in traceIds) {
@@ -163,12 +209,18 @@ export function handleEvent(event) {
163
209
  const timeDeltas = cdpProfile.timeDeltas;
164
210
  cdpProfile.endTime = timeDeltas.reduce((x, y) => x + y, cdpProfile.startTime);
165
211
  }
212
+ assignProfileSourceIfKnown(profileData, event.args?.data?.source);
166
213
  return;
167
214
  }
168
215
  }
169
216
  export async function finalize(parseOptions = {}) {
170
217
  parseCPUProfileData(parseOptions);
171
218
  }
219
+ function assignProfileSourceIfKnown(profileData, source) {
220
+ if (Types.Events.VALID_PROFILE_SOURCES.includes(source)) {
221
+ profileData.source = source;
222
+ }
223
+ }
172
224
  export function data() {
173
225
  return {
174
226
  profilesInProcess,
@@ -185,6 +237,7 @@ function getOrCreatePreProcessedData(processId, profileId) {
185
237
  samples: [],
186
238
  timeDeltas: [],
187
239
  lines: [],
240
+ columns: [],
188
241
  },
189
242
  profileId,
190
243
  }));