Skip to content

Commit 30133a2

Browse files
Connor ClarkDevtools-frontend LUCI CQ
authored andcommitted
[RPP] Simplify PageLoadMetricsHandler map
Instead of using a navigation id as the key, use the navigation event object directly. Benefits: * The map can more simply contain soft and hard navs * Usages don't need to know how to lookup the navigation event by an id - a useful property since where to look depends on if its a soft or a hard navigation * Also changed InsightModel to hold the navigation event directly, rather than a navigation id. Insights still don't handle soft-navs yet Bug: 450673887 Change-Id: I58c74cc92fae1f3233fb8191310889caa2d141f1 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7214930 Reviewed-by: Paul Irish <paulirish@chromium.org> Auto-Submit: Connor Clark <cjamcl@chromium.org> Commit-Queue: Connor Clark <cjamcl@chromium.org>
1 parent 802453b commit 30133a2

File tree

13 files changed

+52
-55
lines changed

13 files changed

+52
-55
lines changed

front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ import {bytes, millis} from './UnitFormatters.js';
1313
/**
1414
* For a given frame ID and navigation ID, returns the LCP Event and the LCP Request, if the resource was an image.
1515
*/
16-
function getLCPData(parsedTrace: Trace.TraceModel.ParsedTrace, frameId: string, navigationId: string): {
16+
function getLCPData(
17+
parsedTrace: Trace.TraceModel.ParsedTrace, frameId: string, navigation: Trace.Types.Events.NavigationStart): {
1718
lcpEvent: Trace.Types.Events.LargestContentfulPaintCandidate,
1819
metricScore: Trace.Handlers.ModelHandlers.PageLoadMetrics.LCPMetricScore,
1920
lcpRequest?: Trace.Types.Events.SyntheticNetworkRequest,
2021
}|null {
21-
const navMetrics = parsedTrace.data.PageLoadMetrics.metricScoresByFrameId.get(frameId)?.get(navigationId);
22+
const navMetrics = parsedTrace.data.PageLoadMetrics.metricScoresByFrameId.get(frameId)?.get(navigation);
2223
if (!navMetrics) {
2324
return null;
2425
}
@@ -32,9 +33,12 @@ function getLCPData(parsedTrace: Trace.TraceModel.ParsedTrace, frameId: string,
3233
return null;
3334
}
3435

36+
const navigationId = navigation.args.data?.navigationId;
37+
3538
return {
3639
lcpEvent,
37-
lcpRequest: parsedTrace.data.LargestImagePaint.lcpRequestByNavigationId.get(navigationId),
40+
lcpRequest: navigationId ? parsedTrace.data.LargestImagePaint.lcpRequestByNavigationId.get(navigationId) :
41+
undefined,
3842
metricScore: metric,
3943
};
4044
}
@@ -89,15 +93,15 @@ export class PerformanceInsightFormatter {
8993
* Information about LCP which we pass to the LLM for all insights that relate to LCP.
9094
*/
9195
#lcpMetricSharedContext(): string {
92-
if (!this.#insight.navigationId) {
96+
if (!this.#insight.navigation) {
9397
// No navigation ID = no LCP.
9498
return '';
9599
}
96-
if (!this.#insight.frameId || !this.#insight.navigationId) {
100+
if (!this.#insight.frameId || !this.#insight.navigation) {
97101
return '';
98102
}
99103

100-
const data = getLCPData(this.#parsedTrace, this.#insight.frameId, this.#insight.navigationId);
104+
const data = getLCPData(this.#parsedTrace, this.#insight.frameId, this.#insight.navigation);
101105
if (!data) {
102106
return '';
103107
}

front_end/models/trace/LanternComputationData.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ import type * as Types from './types/types.js';
1010

1111
type NetworkRequest = Lantern.Types.NetworkRequest<Types.Events.SyntheticNetworkRequest>;
1212

13-
function createProcessedNavigation(data: Handlers.Types.HandlerData, frameId: string, navigationId: string):
14-
Lantern.Types.Simulation.ProcessedNavigation {
13+
function createProcessedNavigation(
14+
data: Handlers.Types.HandlerData, frameId: string,
15+
navigation: Types.Events.NavigationStart): Lantern.Types.Simulation.ProcessedNavigation {
1516
const scoresByNav = data.PageLoadMetrics.metricScoresByFrameId.get(frameId);
1617
if (!scoresByNav) {
1718
throw new Lantern.Core.LanternError('missing metric scores for frame');
1819
}
1920

20-
const scores = scoresByNav.get(navigationId);
21+
const scores = scoresByNav.get(navigation);
2122
if (!scores) {
2223
throw new Lantern.Core.LanternError('missing metric scores for specified navigation');
2324
}

front_end/models/trace/Processor.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,8 @@ export class TraceProcessor extends EventTarget {
268268

269269
#createLanternContext(
270270
data: Handlers.Types.HandlerData, traceEvents: readonly Types.Events.Event[], frameId: string,
271-
navigationId: string, options: Types.Configuration.ParseOptions): Insights.Types.LanternContext|undefined {
271+
navigation: Types.Events.NavigationStart,
272+
options: Types.Configuration.ParseOptions): Insights.Types.LanternContext|undefined {
272273
// Check for required handlers.
273274
if (!data.NetworkRequests || !data.Workers || !data.PageLoadMetrics) {
274275
return;
@@ -278,7 +279,7 @@ export class TraceProcessor extends EventTarget {
278279
}
279280

280281
const navStarts = data.Meta.navigationsByFrameId.get(frameId);
281-
const navStartIndex = navStarts?.findIndex(n => n.args.data?.navigationId === navigationId);
282+
const navStartIndex = navStarts?.findIndex(n => n === navigation);
282283
if (!navStarts || navStartIndex === undefined || navStartIndex === -1) {
283284
throw new Lantern.Core.LanternError('Could not find navigation start');
284285
}
@@ -295,7 +296,7 @@ export class TraceProcessor extends EventTarget {
295296

296297
const requests = LanternComputationData.createNetworkRequests(trace, data, startTime, endTime);
297298
const graph = LanternComputationData.createGraph(requests, trace, data);
298-
const processedNavigation = LanternComputationData.createProcessedNavigation(data, frameId, navigationId);
299+
const processedNavigation = LanternComputationData.createProcessedNavigation(data, frameId, navigation);
299300

300301
const networkAnalysis = Lantern.Core.NetworkAnalyzer.analyze(requests);
301302
if (!networkAnalysis) {
@@ -455,7 +456,7 @@ export class TraceProcessor extends EventTarget {
455456
model.frameId = context.frameId;
456457
const navId = context.navigation?.args.data?.navigationId;
457458
if (navId) {
458-
model.navigationId = navId;
459+
model.navigation = context.navigation;
459460
}
460461
model.createOverlays = () => {
461462
// @ts-expect-error: model is a union of all possible insight model types.
@@ -571,7 +572,7 @@ export class TraceProcessor extends EventTarget {
571572
let lantern: Insights.Types.LanternContext|undefined;
572573
try {
573574
options.logger?.start('insights:createLanternContext');
574-
lantern = this.#createLanternContext(data, traceEvents, frameId, navigationId, options);
575+
lantern = this.#createLanternContext(data, traceEvents, frameId, navigation, options);
575576
} catch (e) {
576577
// Handle Lantern errors gracefully
577578
// Don't allow an error in constructing the Lantern graphs to break the rest of the trace processor.

front_end/models/trace/handlers/LargestImagePaintHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export async function finalize(): Promise<void> {
5555
const metricScoresByFrameId = pageLoadMetricsData().metricScoresByFrameId;
5656

5757
for (const [navigationId, navigation] of navigationsByNavigationId) {
58-
const lcpMetric = metricScoresByFrameId.get(navigation.args.frame)?.get(navigationId)?.get(MetricName.LCP);
58+
const lcpMetric = metricScoresByFrameId.get(navigation.args.frame)?.get(navigation)?.get(MetricName.LCP);
5959
const lcpEvent = lcpMetric?.event;
6060
if (!lcpEvent || !Types.Events.isAnyLargestContentfulPaintCandidate(lcpEvent)) {
6161
continue;

front_end/models/trace/handlers/PageLoadMetricsHandler.test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,8 @@ describeWithEnvironment('PageLoadMetricsHandler', function() {
7272
const {Meta, PageLoadMetrics} = data;
7373
const {mainFrameId, navigationsByFrameId} = Meta;
7474
const navigationBeforeMetrics = navigationsByFrameId.get(mainFrameId)?.[0];
75-
const navigationId = navigationBeforeMetrics?.args.data?.navigationId;
76-
if (!navigationBeforeMetrics || !navigationId) {
77-
assert.fail('Could not find expected navigation event or its navigation ID');
75+
if (!navigationBeforeMetrics) {
76+
assert.fail('Could not find expected navigation event');
7877
}
7978
const pageLoadMetricsData = PageLoadMetrics.metricScoresByFrameId;
8079
// Only one frame to deal with
@@ -84,7 +83,7 @@ describeWithEnvironment('PageLoadMetricsHandler', function() {
8483
assert.isOk(pageLoadEventsForMainFrame, 'Page load events for main frame were unexpectedly null.');
8584
// Single FCP event that occurred after the refresh.
8685
assert.strictEqual(pageLoadEventsForMainFrame.size, 1);
87-
const events = pageLoadEventsForMainFrame.get(navigationId);
86+
const events = pageLoadEventsForMainFrame.get(navigationBeforeMetrics);
8887
const allFoundMetricScoresForMainFrame = events ? Array.from(events.values()) : [];
8988
for (const score of allFoundMetricScoresForMainFrame) {
9089
assert.strictEqual(score.navigation, navigationBeforeMetrics);

front_end/models/trace/handlers/PageLoadMetricsHandler.ts

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
/**
66
* This handler stores page load metrics, including web vitals,
77
* and exports them in the shape of a map with the following shape:
8-
* Map(FrameId -> Map(navigationID -> metrics) )
8+
* Map(FrameId -> Map(navigation -> metrics) )
99
*
10-
* It also includes soft navigations as separate "navigations", though since soft
11-
* navs use different events, the "navigationID" for them is created in this handler.
10+
* Includes soft navigations.
1211
*
1312
* It also exports all markers in a trace in an array.
1413
*
@@ -25,7 +24,6 @@ import type {HandlerName} from './types.js';
2524

2625
// Small helpers to make the below type easier to read.
2726
type FrameId = string;
28-
type NavigationId = string|`softnav-${string}`;
2927
type AnyNavigationStart = Types.Events.NavigationStart|Types.Events.SoftNavigationStart;
3028

3129
/**
@@ -34,7 +32,7 @@ type AnyNavigationStart = Types.Events.NavigationStart|Types.Events.SoftNavigati
3432
* The metric scores include the event related to the metric as well as the data regarding
3533
* the score itself.
3634
*/
37-
let metricScoresByFrameId = new Map<FrameId, Map<NavigationId, Map<MetricName, MetricScore>>>();
35+
let metricScoresByFrameId = new Map<FrameId, Map<AnyNavigationStart, Map<MetricName, MetricScore>>>();
3836

3937
/**
4038
* Page load events with no associated duration that happened in the
@@ -70,12 +68,6 @@ export function handleEvent(event: Types.Events.Event): void {
7068

7169
function storePageLoadMetricAgainstNavigationId(
7270
navigation: AnyNavigationStart, event: Types.Events.PageLoadEvent): void {
73-
const navigationId = Types.Events.isSoftNavigationStart(navigation) ?
74-
`softnav-${navigation.args.context.performanceTimelineNavigationId}` :
75-
navigation.args.data?.navigationId;
76-
if (!navigationId) {
77-
throw new Error('Navigation event unexpectedly had no navigation ID.');
78-
}
7971
const frameId = getFrameIdForPageLoadEvent(event);
8072
const {rendererProcessesByFrame} = metaHandlerData();
8173

@@ -102,15 +94,15 @@ function storePageLoadMetricAgainstNavigationId(
10294
const fcpTime = Types.Timing.Micro(event.ts - navigation.ts);
10395
const classification = scoreClassificationForFirstContentfulPaint(fcpTime);
10496
const metricScore = {event, metricName: MetricName.FCP, classification, navigation, timing: fcpTime};
105-
storeMetricScore(frameId, navigationId, metricScore);
97+
storeMetricScore(frameId, navigation, metricScore);
10698
return;
10799
}
108100

109101
if (Types.Events.isFirstPaint(event)) {
110102
const paintTime = Types.Timing.Micro(event.ts - navigation.ts);
111103
const classification = ScoreClassification.UNCLASSIFIED;
112104
const metricScore = {event, metricName: MetricName.FP, classification, navigation, timing: paintTime};
113-
storeMetricScore(frameId, navigationId, metricScore);
105+
storeMetricScore(frameId, navigation, metricScore);
114106
return;
115107
}
116108

@@ -123,7 +115,7 @@ function storePageLoadMetricAgainstNavigationId(
123115
navigation,
124116
timing: dclTime,
125117
};
126-
storeMetricScore(frameId, navigationId, metricScore);
118+
storeMetricScore(frameId, navigation, metricScore);
127119
return;
128120
}
129121

@@ -136,7 +128,7 @@ function storePageLoadMetricAgainstNavigationId(
136128
navigation,
137129
timing: ttiValue,
138130
};
139-
storeMetricScore(frameId, navigationId, tti);
131+
storeMetricScore(frameId, navigation, tti);
140132

141133
const tbtValue = Helpers.Timing.milliToMicro(Types.Timing.Milli(event.args.args.total_blocking_time_ms));
142134
const tbt = {
@@ -146,7 +138,7 @@ function storePageLoadMetricAgainstNavigationId(
146138
navigation,
147139
timing: tbtValue,
148140
};
149-
storeMetricScore(frameId, navigationId, tbt);
141+
storeMetricScore(frameId, navigation, tbt);
150142
return;
151143
}
152144

@@ -159,7 +151,7 @@ function storePageLoadMetricAgainstNavigationId(
159151
navigation,
160152
timing: loadTime,
161153
};
162-
storeMetricScore(frameId, navigationId, metricScore);
154+
storeMetricScore(frameId, navigation, metricScore);
163155
return;
164156
}
165157

@@ -177,11 +169,11 @@ function storePageLoadMetricAgainstNavigationId(
177169
timing: lcpTime,
178170
};
179171
const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());
180-
const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());
172+
const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());
181173
const lastLCPCandidate = metrics.get(MetricName.LCP);
182174
if (lastLCPCandidate === undefined) {
183175
selectedLCPCandidateEvents.add(lcp.event);
184-
storeMetricScore(frameId, navigationId, lcp);
176+
storeMetricScore(frameId, navigation, lcp);
185177
return;
186178
}
187179
const lastLCPCandidateEvent = lastLCPCandidate.event;
@@ -199,7 +191,7 @@ function storePageLoadMetricAgainstNavigationId(
199191
if (lastCandidateIndex < candidateIndex) {
200192
selectedLCPCandidateEvents.delete(lastLCPCandidateEvent);
201193
selectedLCPCandidateEvents.add(lcp.event);
202-
storeMetricScore(frameId, navigationId, lcp);
194+
storeMetricScore(frameId, navigation, lcp);
203195
}
204196
return;
205197
}
@@ -212,9 +204,9 @@ function storePageLoadMetricAgainstNavigationId(
212204
return Platform.assertNever(event, `Unexpected event type: ${event}`);
213205
}
214206

215-
function storeMetricScore(frameId: string, navigationId: string, metricScore: MetricScore): void {
207+
function storeMetricScore(frameId: string, navigation: AnyNavigationStart, metricScore: MetricScore): void {
216208
const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());
217-
const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());
209+
const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());
218210
// If an entry with that metric name is present, delete it so that the new entry that
219211
// will replace it is added at the end of the map. This way we guarantee the map entries
220212
// are ordered in ASC manner by timestamp.
@@ -416,9 +408,9 @@ export interface PageLoadMetricsData {
416408
* The metric scores include the event related to the metric as well as the data regarding
417409
* the score itself.
418410
*
419-
* Soft navigations have a faked NavigationId that starts with `softnav-`.
411+
* Includes soft navigations.
420412
*/
421-
metricScoresByFrameId: Map<string, Map<NavigationId, Map<MetricName, MetricScore>>>;
413+
metricScoresByFrameId: Map<string, Map<AnyNavigationStart, Map<MetricName, MetricScore>>>;
422414
/**
423415
* Page load events with no associated duration that happened in the
424416
* main frame.

front_end/models/trace/helpers/Trace.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,15 @@ describeWithEnvironment('Trace helpers', function() {
124124
it('returns the correct navigation for a page load event', async function() {
125125
const parsedTrace = await TraceLoader.traceEngine(this, 'multiple-navigations.json.gz');
126126
const {Meta, PageLoadMetrics} = parsedTrace.data;
127-
const firstNavigationId = Meta.navigationsByNavigationId.keys().next().value!;
127+
const firstNavigation = Meta.navigationsByNavigationId.values().next().value!;
128128

129129
const fcp = PageLoadMetrics.metricScoresByFrameId.get(Meta.mainFrameId)
130-
?.get(firstNavigationId)
130+
?.get(firstNavigation)
131131
?.get(Trace.Handlers.ModelHandlers.PageLoadMetrics.MetricName.FCP);
132132
assert.isOk(fcp?.event, 'FCP not found');
133133
const navigationForFirstRequest =
134134
Trace.Helpers.Trace.getNavigationForTraceEvent(fcp.event, Meta.mainFrameId, Meta.navigationsByFrameId);
135-
assert.strictEqual(navigationForFirstRequest?.args.data?.navigationId, firstNavigationId);
135+
assert.strictEqual(navigationForFirstRequest, firstNavigation);
136136
});
137137
});
138138

front_end/models/trace/insights/LCPBreakdown.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ export function generateInsight(
218218
throw new Error('no frame metrics');
219219
}
220220

221-
const navMetrics = frameMetrics.get(context.navigationId);
221+
const navMetrics = frameMetrics.get(context.navigation);
222222
if (!navMetrics) {
223223
throw new Error('no navigation metrics');
224224
}

front_end/models/trace/insights/LCPDiscovery.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export function generateInsight(
108108
throw new Error('no frame metrics');
109109
}
110110

111-
const navMetrics = frameMetrics.get(context.navigationId);
111+
const navMetrics = frameMetrics.get(context.navigation);
112112
if (!navMetrics) {
113113
throw new Error('no navigation metrics');
114114
}

front_end/models/trace/insights/RenderBlocking.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export function generateInsight(
185185
}
186186

187187
const firstPaintTs = data.PageLoadMetrics.metricScoresByFrameId.get(context.frameId)
188-
?.get(context.navigationId)
188+
?.get(context.navigation)
189189
?.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.FP)
190190
?.event?.ts;
191191
if (!firstPaintTs) {

0 commit comments

Comments
 (0)