Skip to content

Commit 808905c

Browse files
finnurbrekiDevtools-frontend LUCI CQ
authored andcommitted
Agentize the Network Dependency Tree.
Example response: https://screenshot.googleplex.com/8bNPxUeb5GS6oNt.png Bug: 425273273 Change-Id: I2069e5088d549275ce72687cc764dae62d587501 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6901176 Reviewed-by: Connor Clark <[email protected]> Commit-Queue: Finnur Thorarinsson <[email protected]>
1 parent 0a1237f commit 808905c

File tree

7 files changed

+187
-2
lines changed

7 files changed

+187
-2
lines changed

front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,3 +723,62 @@ This image file is larger than it needs to be (2048x1356) for its displayed dime
723723
## External resources:
724724
- https://developer.chrome.com/docs/lighthouse/performance/uses-optimized-images/
725725
=== end content
726+
727+
Title: PerformanceInsightFormatter NetworkDependencyTree serializes correctly when there are no results
728+
Content:
729+
## Insight Title: Network dependency tree
730+
731+
## Insight Summary:
732+
This insight analyzes the network dependency tree to identify:
733+
- The maximum critical path latency (the longest chain of network requests that the browser must download before it can render the page).
734+
- Whether current [preconnect] tags are appropriate, according to the following rules:
735+
1. They should all be in use (no unnecessary preconnects).
736+
2. All preconnects should specify cross-origin correctly.
737+
3. The maximum of 4 preconnects should be respected.
738+
- Opportunities to add [preconnect] for a faster loading experience.
739+
740+
## Detailed analysis:
741+
The network dependency tree checks found no problems, but optimization suggestions may be available.
742+
743+
No rendering tasks impacted by network dependencies.
744+
745+
no origins were preconnected.
746+
747+
## Estimated savings: none
748+
749+
## External resources:
750+
- https://web.dev/learn/performance/understanding-the-critical-path
751+
- https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/
752+
=== end content
753+
754+
Title: PerformanceInsightFormatter NetworkDependencyTree serializes the correct details when there are problems found in the network dependency tree
755+
Content:
756+
## Insight Title: Network dependency tree
757+
758+
## Insight Summary:
759+
This insight analyzes the network dependency tree to identify:
760+
- The maximum critical path latency (the longest chain of network requests that the browser must download before it can render the page).
761+
- Whether current [preconnect] tags are appropriate, according to the following rules:
762+
1. They should all be in use (no unnecessary preconnects).
763+
2. All preconnects should specify cross-origin correctly.
764+
3. The maximum of 4 preconnects should be respected.
765+
- Opportunities to add [preconnect] for a faster loading experience.
766+
767+
## Detailed analysis:
768+
The network dependency tree checks found one or more problems.
769+
770+
Max critical path latency is 5,014.91 ms
771+
772+
The following is the critical request chain:
773+
- http://localhost:8787/lcp-iframes/index.html (5,005.59 ms) (longest chain)
774+
- http://localhost:8787/lcp-iframes/app.js (5,014.91 ms) (longest chain)
775+
- http://localhost:8787/lcp-iframes/app.css (5,010.12 ms)
776+
777+
no origins were preconnected.
778+
779+
## Estimated savings: none
780+
781+
## External resources:
782+
- https://web.dev/learn/performance/understanding-the-critical-path
783+
- https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/
784+
=== end content

front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,4 +364,26 @@ describeWithEnvironment('PerformanceInsightFormatter', () => {
364364
snapshotTester.assert(this, output);
365365
});
366366
});
367+
368+
describe('NetworkDependencyTree', () => {
369+
it('serializes correctly when there are no results', async function() {
370+
const {parsedTrace, insights} = await TraceLoader.traceEngine(this, 'web-dev-with-commit.json.gz');
371+
assert.isOk(insights);
372+
const firstNav = getFirstOrError(parsedTrace.Meta.navigationsByNavigationId.values());
373+
const insight = getInsightOrError('NetworkDependencyTree', insights, firstNav);
374+
const formatter = new PerformanceInsightFormatter(parsedTrace, insight);
375+
const output = formatter.formatInsight();
376+
snapshotTester.assert(this, output);
377+
});
378+
379+
it('serializes the correct details when there are problems found in the network dependency tree', async function() {
380+
const {parsedTrace, insights} = await TraceLoader.traceEngine(this, 'lcp-multiple-frames.json.gz');
381+
assert.isOk(insights);
382+
const firstNav = getFirstOrError(parsedTrace.Meta.navigationsByNavigationId.values());
383+
const insight = getInsightOrError('NetworkDependencyTree', insights, firstNav);
384+
const formatter = new PerformanceInsightFormatter(parsedTrace, insight);
385+
const output = formatter.formatInsight();
386+
snapshotTester.assert(this, output);
387+
});
388+
});
367389
});

front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,86 @@ export class PerformanceInsightFormatter {
180180
}
181181
}
182182

183+
/**
184+
* Create an AI prompt string out of the NetworkDependencyTree Insight model to use with Ask AI.
185+
* Note: This function accesses the UIStrings within NetworkDependencyTree to help build the
186+
* AI prompt, but does not (and should not) call i18nString to localize these strings. They
187+
* should all be sent in English (at least for now).
188+
* @param insight The Network Dependency Tree Insight Model to query.
189+
* @returns a string formatted for sending to Ask AI.
190+
*/
191+
formatNetworkDependencyTreeInsight(
192+
insight: Trace.Insights.Models.NetworkDependencyTree.NetworkDependencyTreeInsightModel): string {
193+
let output = insight.fail ?
194+
'The network dependency tree checks found one or more problems.\n\n' :
195+
'The network dependency tree checks found no problems, but optimization suggestions may be available.\n\n';
196+
197+
const rootNodes = insight.rootNodes;
198+
if (rootNodes.length > 0) {
199+
output += `Max critical path latency is ${formatMicroToMilli(insight.maxTime)}\n\n`;
200+
output += 'The following is the critical request chain:\n';
201+
202+
function formatNode(
203+
node: Trace.Insights.Models.NetworkDependencyTree.CriticalRequestNode, indent: string): string {
204+
const url = node.request.args.data.url;
205+
const time = formatMicroToMilli(node.timeFromInitialRequest);
206+
const isLongest = node.isLongest ? ' (longest chain)' : '';
207+
let nodeString = `${indent}- ${url} (${time})${isLongest}\n`;
208+
for (const child of node.children) {
209+
nodeString += formatNode(child, indent + ' ');
210+
}
211+
return nodeString;
212+
}
213+
214+
for (const rootNode of rootNodes) {
215+
output += formatNode(rootNode, '');
216+
}
217+
output += '\n';
218+
} else {
219+
output += `${Trace.Insights.Models.NetworkDependencyTree.UIStrings.noNetworkDependencyTree}.\n\n`;
220+
}
221+
222+
if (insight.preconnectedOrigins?.length > 0) {
223+
output += `${Trace.Insights.Models.NetworkDependencyTree.UIStrings.preconnectOriginsTableTitle}:\n`;
224+
output += `${Trace.Insights.Models.NetworkDependencyTree.UIStrings.preconnectOriginsTableDescription}\n`;
225+
for (const origin of insight.preconnectedOrigins) {
226+
const headerText = 'headerText' in origin ? `'${origin.headerText}'` : ``;
227+
output += `
228+
- ${origin.url}
229+
- ${Trace.Insights.Models.NetworkDependencyTree.UIStrings.columnSource}: '${origin.source}'`;
230+
if (headerText) {
231+
output += `\n - Header: ${headerText}`;
232+
}
233+
if (origin.unused) {
234+
output += `\n - Warning: ${Trace.Insights.Models.NetworkDependencyTree.UIStrings.unusedWarning}`;
235+
}
236+
if (origin.crossorigin) {
237+
output += `\n - Warning: ${Trace.Insights.Models.NetworkDependencyTree.UIStrings.crossoriginWarning}`;
238+
}
239+
}
240+
if (insight.preconnectedOrigins.length >
241+
Trace.Insights.Models.NetworkDependencyTree.TOO_MANY_PRECONNECTS_THRESHOLD) {
242+
output +=
243+
`\n\n**Warning**: ${Trace.Insights.Models.NetworkDependencyTree.UIStrings.tooManyPreconnectLinksWarning}`;
244+
}
245+
} else {
246+
output += `${Trace.Insights.Models.NetworkDependencyTree.UIStrings.noPreconnectOrigins}.`;
247+
}
248+
249+
if (insight.preconnectCandidates.length > 0 &&
250+
insight.preconnectedOrigins.length <
251+
Trace.Insights.Models.NetworkDependencyTree.TOO_MANY_PRECONNECTS_THRESHOLD) {
252+
output += `\n\n${Trace.Insights.Models.NetworkDependencyTree.UIStrings.estSavingTableTitle}:\n${
253+
Trace.Insights.Models.NetworkDependencyTree.UIStrings.estSavingTableDescription}\n`;
254+
for (const candidate of insight.preconnectCandidates) {
255+
output +=
256+
`\nAdding [preconnect] to origin '${candidate.origin}' would save ${formatMilli(candidate.wastedMs)}.`;
257+
}
258+
}
259+
260+
return output;
261+
}
262+
183263
/**
184264
* Formats and outputs the insight's data.
185265
* Pass `{headingLevel: X}` to determine what heading level to use for the
@@ -430,6 +510,10 @@ Legacy JavaScript by file:
430510
${filesFormatted}`;
431511
}
432512

513+
if (Trace.Insights.Models.NetworkDependencyTree.isNetworkDependencyTree(this.#insight)) {
514+
return this.formatNetworkDependencyTreeInsight(this.#insight);
515+
}
516+
433517
return '';
434518
}
435519

@@ -473,7 +557,8 @@ ${filesFormatted}`;
473557
return `- https://web.dev/articles/lcp
474558
- https://web.dev/articles/optimize-lcp`;
475559
case 'NetworkDependencyTree':
476-
return '';
560+
return `- https://web.dev/learn/performance/understanding-the-critical-path
561+
- https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/`;
477562
case 'RenderBlocking':
478563
return `- https://web.dev/articles/lcp
479564
- https://web.dev/articles/optimize-lcp`;
@@ -538,7 +623,13 @@ It is important that all of these checks pass to minimize the delay between the
538623
case 'LCPBreakdown':
539624
return 'This insight is used to analyze the time spent that contributed to the final LCP time and identify which of the 4 phases (or 2 if there was no LCP resource) are contributing most to the delay in rendering the LCP element.';
540625
case 'NetworkDependencyTree':
541-
return '';
626+
return `This insight analyzes the network dependency tree to identify:
627+
- The maximum critical path latency (the longest chain of network requests that the browser must download before it can render the page).
628+
- Whether current [preconnect] tags are appropriate, according to the following rules:
629+
1. They should all be in use (no unnecessary preconnects).
630+
2. All preconnects should specify cross-origin correctly.
631+
3. The maximum of 4 preconnects should be respected.
632+
- Opportunities to add [preconnect] for a faster loading experience.`;
542633
case 'RenderBlocking':
543634
return 'This insight identifies network requests that were render blocking. Render blocking requests are impactful because they are deemed critical to the page and therefore the browser stops rendering the page until it has dealt with these resources. For this insight make sure you fully inspect the details of each render blocking network request and prioritize your suggestions to the user based on the impact of each render blocking request.';
544635
case 'SlowCSSSelector':

front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,10 @@ Available insights:
876876
relevant trace bounds: {min: 157425604232, max: 157426760958}
877877
example question: Help me optimize my CLS score
878878
example question: How can I prevent layout shifts on this page?
879+
- insight name: NetworkDependencyTree
880+
description: [Avoid chaining critical requests](https://developer.chrome.com/docs/lighthouse/performance/critical-request-chains) by reducing the length of chains, reducing the download size of resources, or deferring the download of unnecessary resources to improve page load.
881+
relevant trace bounds: {min: 157423489126, max: 157426527569}
882+
example question: How do I optimize my network dependency tree?
879883
- insight name: ImageDelivery
880884
description: Reducing the download time of images can improve the perceived load time of the page and LCP. [Learn more about optimizing image size](https://developer.chrome.com/docs/lighthouse/performance/uses-optimized-images/)
881885
relevant trace bounds: {min: 157423794709, max: 157424082831}

front_end/models/trace/insights/NetworkDependencyTree.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,10 @@ export function generatePreconnectCandidates(
666666
return preconnectCandidates.slice(0, TOO_MANY_PRECONNECTS_THRESHOLD);
667667
}
668668

669+
export function isNetworkDependencyTree(model: InsightModel): model is NetworkDependencyTreeInsightModel {
670+
return model.insightKey === InsightKeys.NETWORK_DEPENDENCY_TREE;
671+
}
672+
669673
export function generateInsight(
670674
parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): NetworkDependencyTreeInsightModel {
671675
if (!context.navigation) {

front_end/panels/timeline/components/insights/NetworkDependencyTree.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export class NetworkDependencyTree extends BaseInsightComponent<NetworkDependenc
3333
#relatedRequests: Set<Trace.Types.Events.SyntheticNetworkRequest>|null = null;
3434
#countOfChains = 0;
3535

36+
protected override hasAskAiSupport(): boolean {
37+
return true;
38+
}
39+
3640
#createOverlayForChain(requests: Set<Trace.Types.Events.SyntheticNetworkRequest>):
3741
Trace.Types.Overlays.EntryOutline[] {
3842
const overlays: Trace.Types.Overlays.EntryOutline[] = [];

front_end/ui/visual_logging/KnownContextValues.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3793,6 +3793,7 @@ export const knownContextValues = new Set([
37933793
'timeline.insight-ask-ai.legacy-javascript ',
37943794
'timeline.insight-ask-ai.long-critical-network-tree',
37953795
'timeline.insight-ask-ai.modern-http',
3796+
'timeline.insight-ask-ai.network-dependency-tree',
37963797
'timeline.insight-ask-ai.render-blocking-requests',
37973798
'timeline.insight-ask-ai.slow-css-selector',
37983799
'timeline.insight-ask-ai.third-parties',

0 commit comments

Comments
 (0)