Skip to content

Commit 68f4ed9

Browse files
committed
core(network-request): exclude dns from rtt estimates
1 parent 4debf10 commit 68f4ed9

File tree

9 files changed

+124
-90
lines changed

9 files changed

+124
-90
lines changed

core/lib/dependency-graph/simulator/network-analyzer.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,15 @@ class NetworkAnalyzer {
204204
if (!Number.isFinite(timing.sendStart) || timing.sendStart < 0) return;
205205

206206
// Assume everything before sendStart was just DNS + (SSL)? + TCP handshake
207-
// 1 RT for DNS, 1 RT (maybe) for SSL, 1 RT for TCP
208-
let roundTrips = 1;
207+
// 1 RT (maybe) for SSL, 1 RT for TCP
208+
// DNS is not included because
209+
// 1) it is very variable in terms of how many hops it could be (as little as 0, if cached locally)
210+
// 2) it doesn't even communicate with the server, so it is useless for RTT calculation.
211+
let roundTrips = 0;
209212
if (!record.protocol.startsWith('h3')) roundTrips += 1; // TCP
210213
if (record.parsedURL.scheme === 'https') roundTrips += 1;
211-
return timing.sendStart / roundTrips;
214+
const dnsTime = timing.dnsStart >= 0 ? timing.dnsEnd - timing.dnsStart : 0;
215+
return (timing.sendStart - dnsTime) / roundTrips;
212216
}
213217

214218
/**
@@ -237,13 +241,15 @@ class NetworkAnalyzer {
237241
// When connection was fresh...
238242
// TTFB = DNS + (SSL)? + TCP handshake + 1 RT for request + server response time
239243
if (!connectionReused) {
240-
roundTrips += 1; // DNS
244+
// We purposely exclude DNS from RTT estimate, as it is unrelated to RTT to the server.
241245
if (!record.protocol.startsWith('h3')) roundTrips += 1; // TCP
242246
if (record.parsedURL.scheme === 'https') roundTrips += 1; // SSL
243247
}
244248

245-
// subtract out our estimated server response time
246-
return Math.max((timing.receiveHeadersEnd - estimatedServerResponseTime) / roundTrips, 3);
249+
// subtract out our estimated server response time and dns time
250+
const dnsTime = timing.dnsStart >= 0 ? timing.dnsEnd - timing.dnsStart : 0;
251+
const duration = timing.receiveHeadersEnd - estimatedServerResponseTime - dnsTime;
252+
return Math.max(duration / roundTrips, 3);
247253
}
248254

249255
/**

core/test/audits/largest-contentful-paint-element-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,11 @@ describe('Performance: largest-contentful-paint-element audit', () => {
114114
expect(auditResult.details.items[1].items[0].phase).toBeDisplayString('TTFB');
115115
expect(auditResult.details.items[1].items[0].timing).toBeCloseTo(800, 0.1);
116116
expect(auditResult.details.items[1].items[1].phase).toBeDisplayString('Load Delay');
117-
expect(auditResult.details.items[1].items[1].timing).toBeCloseTo(651, 0.1);
117+
expect(auditResult.details.items[1].items[1].timing).toBeCloseTo(650.25, 0.1);
118118
expect(auditResult.details.items[1].items[2].phase).toBeDisplayString('Load Time');
119-
expect(auditResult.details.items[1].items[2].timing).toBeCloseTo(1813.7, 0.1);
119+
expect(auditResult.details.items[1].items[2].timing).toBeCloseTo(1812.8, 0.1);
120120
expect(auditResult.details.items[1].items[3].phase).toBeDisplayString('Render Delay');
121-
expect(auditResult.details.items[1].items[3].timing).toBeCloseTo(2539.2, 0.1);
121+
expect(auditResult.details.items[1].items[3].timing).toBeCloseTo(2537.9, 0.1);
122122
});
123123

124124
it('doesn\'t throw an error when there is nothing to show', async () => {

core/test/computed/metrics/lantern-largest-contentful-paint-test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ describe('Metrics: Lantern LCP', () => {
2424
);
2525

2626
expect({
27-
timing: Math.round(result.timing),
28-
optimistic: Math.round(result.optimisticEstimate.timeInMs),
29-
pessimistic: Math.round(result.pessimisticEstimate.timeInMs)}).
27+
timing: Math.round(result.timing),
28+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
29+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs) }).
3030
toMatchInlineSnapshot(`
3131
Object {
32-
"optimistic": 2294,
33-
"pessimistic": 3233,
34-
"timing": 2764,
32+
"optimistic": 2293,
33+
"pessimistic": 3232,
34+
"timing": 2763,
3535
}
3636
`);
3737
assert.equal(result.optimisticEstimate.nodeTimings.size, 12);

core/test/computed/metrics/largest-contentful-paint-test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ describe('Metrics: LCP', () => {
2525
settings, URL}, context);
2626

2727
expect({
28-
timing: Math.round(result.timing),
29-
optimistic: Math.round(result.optimisticEstimate.timeInMs),
30-
pessimistic: Math.round(result.pessimisticEstimate.timeInMs)}).
28+
timing: Math.round(result.timing),
29+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
30+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs) }).
3131
toMatchInlineSnapshot(`
3232
Object {
33-
"optimistic": 2294,
34-
"pessimistic": 3233,
35-
"timing": 2764,
33+
"optimistic": 2293,
34+
"pessimistic": 3232,
35+
"timing": 2763,
3636
}
3737
`);
3838
});

core/test/computed/metrics/lcp-breakdown-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ describe('LCPBreakdown', () => {
129129
const result = await LCPBreakdown.request(data, {computedCache: new Map()});
130130

131131
expect(result.ttfb).toBeCloseTo(800, 0.1);
132-
expect(result.loadStart).toBeCloseTo(2579.5, 0.1);
133-
expect(result.loadEnd).toBeCloseTo(5804, 0.1);
132+
expect(result.loadStart).toBeCloseTo(2578.2, 0.1);
133+
expect(result.loadEnd).toBeCloseTo(5801, 0.1);
134134
});
135135

136136
it('returns observed for image LCP', async () => {

core/test/computed/metrics/time-to-first-byte-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ describe('Metrics: TTFB', () => {
9191

9292
// 3 * 150 RTT + 99 server response time
9393
// 99 Comes from (100ms observed TTFB - 1ms observed RTT)
94-
expect(result.timing).toEqual(549);
94+
expect(result.timing).toEqual(548.5);
9595
expect(result.timestamp).toBeUndefined();
9696
});
9797

@@ -105,7 +105,7 @@ describe('Metrics: TTFB', () => {
105105

106106
// 4 * 150 RTT + 99.1 server response time
107107
// 99.1 Comes from (100ms observed TTFB - 0.9ms observed RTT)
108-
expect(result.timing).toEqual(699.1);
108+
expect(result.timing).toEqual(699);
109109
expect(result.timestamp).toBeUndefined();
110110
});
111111

core/test/computed/network-analysis-test.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,24 @@ Map {
4646
});
4747

4848
const result = await NetworkAnalysis.request(mutatedLog, {computedCache: new Map()});
49-
// If the connection timings were not removed, this would be the 1.045 estimate as seen in
49+
// If the connection timings were not removed, these estimates would be the same as in
5050
// the test above. However, without connection timings we fall back to a coarse estimate and
51-
// get this instead.
52-
expect(result.additionalRttByOrigin.get('https://www.google-analytics.com')).toBeCloseTo(2.86);
51+
// get slightly different results.
52+
expect(result.additionalRttByOrigin).toMatchInlineSnapshot(`
53+
Map {
54+
"https://pwa.rocks" => 0.8417000135522703,
55+
"https://www.googletagmanager.com" => 0.4456999959075678,
56+
"https://www.google-analytics.com" => 0,
57+
"__SUMMARY__" => 0,
58+
}
59+
`);
60+
expect(result.serverResponseTimeByOrigin).toMatchInlineSnapshot(`
61+
Map {
62+
"https://pwa.rocks" => 159.70249997917608,
63+
"https://www.googletagmanager.com" => 153.03200000198592,
64+
"https://www.google-analytics.com" => 161.04569999879467,
65+
"__SUMMARY__" => 159.70249997917608,
66+
}
67+
`);
5368
});
5469
});

0 commit comments

Comments
 (0)