lighthouse 12.1.0-dev.20240630 → 12.1.0-dev.20240702
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.
- package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +5 -7
- package/core/audits/byte-efficiency/byte-efficiency-audit.js +3 -6
- package/core/audits/byte-efficiency/render-blocking-resources.d.ts +3 -7
- package/core/audits/byte-efficiency/render-blocking-resources.js +10 -16
- package/core/audits/dobetterweb/uses-http2.d.ts +4 -6
- package/core/audits/dobetterweb/uses-http2.js +2 -5
- package/core/audits/long-tasks.d.ts +6 -6
- package/core/audits/long-tasks.js +4 -4
- package/core/audits/prioritize-lcp-image.d.ts +1 -1
- package/core/audits/uses-rel-preload.d.ts +4 -3
- package/core/audits/uses-rel-preload.js +8 -6
- package/core/computed/critical-request-chains.d.ts +4 -3
- package/core/computed/critical-request-chains.js +5 -4
- package/core/computed/document-urls.js +1 -1
- package/core/computed/load-simulator.d.ts +3 -4
- package/core/computed/load-simulator.js +1 -1
- package/core/computed/main-resource.js +1 -1
- package/core/computed/metrics/lantern-first-contentful-paint.d.ts +2 -4
- package/core/computed/metrics/lantern-first-contentful-paint.js +1 -3
- package/core/computed/metrics/lantern-interactive.d.ts +2 -4
- package/core/computed/metrics/lantern-interactive.js +1 -3
- package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +2 -4
- package/core/computed/metrics/lantern-largest-contentful-paint.js +1 -3
- package/core/computed/metrics/lantern-max-potential-fid.d.ts +2 -4
- package/core/computed/metrics/lantern-max-potential-fid.js +1 -3
- package/core/computed/metrics/lantern-metric.d.ts +8 -8
- package/core/computed/metrics/lantern-metric.js +1 -1
- package/core/computed/metrics/lantern-speed-index.d.ts +2 -4
- package/core/computed/metrics/lantern-speed-index.js +1 -3
- package/core/computed/metrics/lantern-total-blocking-time.d.ts +2 -4
- package/core/computed/metrics/lantern-total-blocking-time.js +1 -3
- package/core/computed/metrics/total-blocking-time.js +1 -1
- package/core/computed/network-analysis.js +1 -1
- package/core/computed/page-dependency-graph.d.ts +3 -6
- package/core/computed/page-dependency-graph.js +3 -4
- package/core/computed/tbt-impact-tasks.js +2 -2
- package/core/lib/asset-saver.js +1 -1
- package/core/lib/lantern/lantern.d.ts +2 -19
- package/core/lib/lantern/lantern.js +2 -45
- package/core/lib/lantern-trace-saver.d.ts +4 -6
- package/core/lib/lantern-trace-saver.js +2 -3
- package/core/lib/navigation-error.js +2 -2
- package/core/lib/network-recorder.js +1 -1
- package/core/lib/network-request.d.ts +4 -4
- package/core/lib/network-request.js +2 -2
- package/package.json +2 -2
- package/tsconfig.json +0 -11
- package/types/artifacts.d.ts +2 -2
- package/types/gatherer.d.ts +4 -5
- package/core/lib/lantern/BaseNode.d.ts +0 -163
- package/core/lib/lantern/BaseNode.js +0 -369
- package/core/lib/lantern/BaseNode.test.js +0 -385
- package/core/lib/lantern/CpuNode.d.ts +0 -43
- package/core/lib/lantern/CpuNode.js +0 -99
- package/core/lib/lantern/LanternError.d.ts +0 -8
- package/core/lib/lantern/LanternError.js +0 -9
- package/core/lib/lantern/Metric.d.ts +0 -69
- package/core/lib/lantern/Metric.js +0 -137
- package/core/lib/lantern/NetworkNode.d.ts +0 -49
- package/core/lib/lantern/NetworkNode.js +0 -136
- package/core/lib/lantern/PageDependencyGraph.d.ts +0 -82
- package/core/lib/lantern/PageDependencyGraph.js +0 -610
- package/core/lib/lantern/PageDependencyGraph.test.js +0 -654
- package/core/lib/lantern/TBTUtils.d.ts +0 -44
- package/core/lib/lantern/TBTUtils.js +0 -76
- package/core/lib/lantern/TBTUtils.test.d.ts +0 -2
- package/core/lib/lantern/TBTUtils.test.js +0 -130
- package/core/lib/lantern/TraceEngineComputationData.d.ts +0 -25
- package/core/lib/lantern/TraceEngineComputationData.js +0 -466
- package/core/lib/lantern/metrics/FirstContentfulPaint.d.ts +0 -79
- package/core/lib/lantern/metrics/FirstContentfulPaint.js +0 -198
- package/core/lib/lantern/metrics/FirstContentfulPaint.test.js +0 -54
- package/core/lib/lantern/metrics/Interactive.d.ts +0 -20
- package/core/lib/lantern/metrics/Interactive.js +0 -109
- package/core/lib/lantern/metrics/Interactive.test.js +0 -56
- package/core/lib/lantern/metrics/LargestContentfulPaint.d.ts +0 -19
- package/core/lib/lantern/metrics/LargestContentfulPaint.js +0 -105
- package/core/lib/lantern/metrics/LargestContentfulPaint.test.js +0 -42
- package/core/lib/lantern/metrics/MaxPotentialFID.d.ts +0 -24
- package/core/lib/lantern/metrics/MaxPotentialFID.js +0 -91
- package/core/lib/lantern/metrics/MetricTestUtils.d.ts +0 -19
- package/core/lib/lantern/metrics/MetricTestUtils.js +0 -48
- package/core/lib/lantern/metrics/SpeedIndex.d.ts +0 -32
- package/core/lib/lantern/metrics/SpeedIndex.js +0 -142
- package/core/lib/lantern/metrics/SpeedIndex.test.js +0 -83
- package/core/lib/lantern/metrics/TotalBlockingTime.d.ts +0 -25
- package/core/lib/lantern/metrics/TotalBlockingTime.js +0 -125
- package/core/lib/lantern/metrics/__snapshots__/FirstContentfulPaint.test.js.snap +0 -11
- package/core/lib/lantern/metrics/__snapshots__/Interactive.test.js.snap +0 -17
- package/core/lib/lantern/metrics/metrics.d.ts +0 -9
- package/core/lib/lantern/metrics/metrics.js +0 -16
- package/core/lib/lantern/simulation/ConnectionPool.d.ts +0 -48
- package/core/lib/lantern/simulation/ConnectionPool.js +0 -152
- package/core/lib/lantern/simulation/ConnectionPool.test.js +0 -195
- package/core/lib/lantern/simulation/Constants.d.ts +0 -52
- package/core/lib/lantern/simulation/Constants.js +0 -48
- package/core/lib/lantern/simulation/DNSCache.d.ts +0 -42
- package/core/lib/lantern/simulation/DNSCache.js +0 -74
- package/core/lib/lantern/simulation/DNSCache.test.js +0 -72
- package/core/lib/lantern/simulation/NetworkAnalyzer.d.ts +0 -209
- package/core/lib/lantern/simulation/NetworkAnalyzer.js +0 -597
- package/core/lib/lantern/simulation/NetworkAnalyzer.test.js +0 -475
- package/core/lib/lantern/simulation/SimulationTimingMap.d.ts +0 -153
- package/core/lib/lantern/simulation/SimulationTimingMap.js +0 -219
- package/core/lib/lantern/simulation/Simulator.d.ts +0 -157
- package/core/lib/lantern/simulation/Simulator.js +0 -593
- package/core/lib/lantern/simulation/Simulator.test.js +0 -434
- package/core/lib/lantern/simulation/TCPConnection.test.d.ts +0 -2
- package/core/lib/lantern/simulation/TCPConnection.test.js +0 -374
- package/core/lib/lantern/simulation/TcpConnection.d.ts +0 -89
- package/core/lib/lantern/simulation/TcpConnection.js +0 -230
- package/core/lib/lantern/simulation/simulation.d.ts +0 -21
- package/core/lib/lantern/simulation/simulation.js +0 -28
- package/core/lib/lantern/types/lantern.d.ts +0 -256
- package/core/lib/lantern/types/lantern.js +0 -7
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2017 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import assert from 'assert/strict';
|
|
8
|
-
|
|
9
|
-
import * as Lantern from '../lantern.js';
|
|
10
|
-
|
|
11
|
-
const {TcpConnection} = Lantern.Simulation;
|
|
12
|
-
|
|
13
|
-
describe('DependencyGraph/Simulator/TcpConnection', () => {
|
|
14
|
-
describe('#constructor', () => {
|
|
15
|
-
it('should create the connection', () => {
|
|
16
|
-
const rtt = 150;
|
|
17
|
-
const throughput = 1600 * 1024;
|
|
18
|
-
const connection = new TcpConnection(rtt, throughput);
|
|
19
|
-
assert.ok(connection);
|
|
20
|
-
assert.equal(connection._rtt, rtt);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe('#maximumSaturatedConnections', () => {
|
|
25
|
-
it('should compute number of supported simulated requests', () => {
|
|
26
|
-
const availableThroughput = 1460 * 8 * 10; // 10 TCP segments/second
|
|
27
|
-
assert.equal(TcpConnection.maximumSaturatedConnections(100, availableThroughput), 1);
|
|
28
|
-
assert.equal(TcpConnection.maximumSaturatedConnections(300, availableThroughput), 3);
|
|
29
|
-
assert.equal(TcpConnection.maximumSaturatedConnections(1000, availableThroughput), 10);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe('.setWarmed', () => {
|
|
34
|
-
it('adjusts the time to download appropriately', () => {
|
|
35
|
-
const connection = new TcpConnection(100, Infinity);
|
|
36
|
-
assert.equal(connection.simulateDownloadUntil(0).timeElapsed, 300);
|
|
37
|
-
connection.setWarmed(true);
|
|
38
|
-
assert.equal(connection.simulateDownloadUntil(0).timeElapsed, 100);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe('.setCongestionWindow', () => {
|
|
43
|
-
it('adjusts the time to download appropriately', () => {
|
|
44
|
-
const connection = new TcpConnection(100, Infinity);
|
|
45
|
-
assert.deepEqual(connection.simulateDownloadUntil(50000), {
|
|
46
|
-
bytesDownloaded: 50000,
|
|
47
|
-
extraBytesDownloaded: 0,
|
|
48
|
-
congestionWindow: 40,
|
|
49
|
-
roundTrips: 5,
|
|
50
|
-
timeElapsed: 500,
|
|
51
|
-
connectionTiming: {
|
|
52
|
-
connectionTime: 250,
|
|
53
|
-
dnsResolutionTime: 0,
|
|
54
|
-
sslTime: 100,
|
|
55
|
-
timeToFirstByte: 300,
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
connection.setCongestionWindow(40); // will download all in one round trip
|
|
59
|
-
assert.deepEqual(connection.simulateDownloadUntil(50000), {
|
|
60
|
-
bytesDownloaded: 50000,
|
|
61
|
-
extraBytesDownloaded: 0,
|
|
62
|
-
congestionWindow: 40,
|
|
63
|
-
roundTrips: 3,
|
|
64
|
-
timeElapsed: 300,
|
|
65
|
-
connectionTiming: {
|
|
66
|
-
connectionTime: 250,
|
|
67
|
-
dnsResolutionTime: 0,
|
|
68
|
-
sslTime: 100,
|
|
69
|
-
timeToFirstByte: 300,
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe('.setH2OverflowBytesDownloaded', () => {
|
|
76
|
-
it('adjusts the time to download appropriately for H2 connections', () => {
|
|
77
|
-
const connection = new TcpConnection(100, Infinity, 0, true, true);
|
|
78
|
-
connection.setWarmed(true);
|
|
79
|
-
assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
|
|
80
|
-
connection.setH2OverflowBytesDownloaded(20000);
|
|
81
|
-
assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 100);
|
|
82
|
-
connection.setH2OverflowBytesDownloaded(50000);
|
|
83
|
-
assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 0);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('does not adjust the time to download for non-H2 connections', () => {
|
|
87
|
-
const connection = new TcpConnection(100, Infinity, 0, true, false);
|
|
88
|
-
connection.setWarmed(true);
|
|
89
|
-
assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
|
|
90
|
-
connection.setH2OverflowBytesDownloaded(20000);
|
|
91
|
-
assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
|
|
92
|
-
connection.setH2OverflowBytesDownloaded(50000);
|
|
93
|
-
assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe('.simulateDownloadUntil', () => {
|
|
98
|
-
describe('when maximumTime is not set', () => {
|
|
99
|
-
it('should provide the correct values small payload non-SSL', () => {
|
|
100
|
-
const connection = new TcpConnection(100, Infinity, 0, false);
|
|
101
|
-
assert.deepEqual(connection.simulateDownloadUntil(7300), {
|
|
102
|
-
bytesDownloaded: 7300,
|
|
103
|
-
extraBytesDownloaded: 0,
|
|
104
|
-
congestionWindow: 10,
|
|
105
|
-
roundTrips: 2,
|
|
106
|
-
timeElapsed: 200,
|
|
107
|
-
connectionTiming: {
|
|
108
|
-
connectionTime: 150,
|
|
109
|
-
dnsResolutionTime: 0,
|
|
110
|
-
sslTime: undefined, // non-SSL
|
|
111
|
-
timeToFirstByte: 200,
|
|
112
|
-
},
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should provide the correct values small payload SSL', () => {
|
|
117
|
-
const connection = new TcpConnection(100, Infinity, 0, true);
|
|
118
|
-
assert.deepEqual(connection.simulateDownloadUntil(7300), {
|
|
119
|
-
bytesDownloaded: 7300,
|
|
120
|
-
extraBytesDownloaded: 0,
|
|
121
|
-
congestionWindow: 10,
|
|
122
|
-
roundTrips: 3,
|
|
123
|
-
timeElapsed: 300,
|
|
124
|
-
connectionTiming: {
|
|
125
|
-
connectionTime: 250,
|
|
126
|
-
dnsResolutionTime: 0,
|
|
127
|
-
sslTime: 100,
|
|
128
|
-
timeToFirstByte: 300,
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should provide the correct values small payload H2', () => {
|
|
134
|
-
const connection = new TcpConnection(100, Infinity, 0, true, true);
|
|
135
|
-
assert.deepEqual(connection.simulateDownloadUntil(7300), {
|
|
136
|
-
bytesDownloaded: 7300,
|
|
137
|
-
extraBytesDownloaded: 7300,
|
|
138
|
-
congestionWindow: 10,
|
|
139
|
-
roundTrips: 3,
|
|
140
|
-
timeElapsed: 300,
|
|
141
|
-
connectionTiming: {
|
|
142
|
-
connectionTime: 250,
|
|
143
|
-
dnsResolutionTime: 0,
|
|
144
|
-
sslTime: 100,
|
|
145
|
-
timeToFirstByte: 300,
|
|
146
|
-
},
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should provide the correct values response time', () => {
|
|
151
|
-
const responseTime = 78;
|
|
152
|
-
const connection = new TcpConnection(100, Infinity, responseTime, true);
|
|
153
|
-
assert.deepEqual(connection.simulateDownloadUntil(7300), {
|
|
154
|
-
bytesDownloaded: 7300,
|
|
155
|
-
extraBytesDownloaded: 0,
|
|
156
|
-
congestionWindow: 10,
|
|
157
|
-
roundTrips: 3,
|
|
158
|
-
timeElapsed: 300 + responseTime,
|
|
159
|
-
connectionTiming: {
|
|
160
|
-
connectionTime: 250,
|
|
161
|
-
dnsResolutionTime: 0,
|
|
162
|
-
sslTime: 100,
|
|
163
|
-
timeToFirstByte: 378,
|
|
164
|
-
},
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('should provide the correct values large payload', () => {
|
|
169
|
-
const connection = new TcpConnection(100, 8 * 1000 * 1000);
|
|
170
|
-
const bytesToDownload = 10 * 1000 * 1000; // 10 mb
|
|
171
|
-
assert.deepEqual(connection.simulateDownloadUntil(bytesToDownload), {
|
|
172
|
-
bytesDownloaded: bytesToDownload,
|
|
173
|
-
extraBytesDownloaded: 0,
|
|
174
|
-
congestionWindow: 68,
|
|
175
|
-
roundTrips: 105,
|
|
176
|
-
timeElapsed: 10500,
|
|
177
|
-
connectionTiming: {
|
|
178
|
-
connectionTime: 250,
|
|
179
|
-
dnsResolutionTime: 0,
|
|
180
|
-
sslTime: 100,
|
|
181
|
-
timeToFirstByte: 300,
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('should provide the correct values resumed small payload', () => {
|
|
187
|
-
const connection = new TcpConnection(100, Infinity, 0, true);
|
|
188
|
-
assert.deepEqual(connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 250}), {
|
|
189
|
-
bytesDownloaded: 7300,
|
|
190
|
-
extraBytesDownloaded: 0,
|
|
191
|
-
congestionWindow: 10,
|
|
192
|
-
roundTrips: 3,
|
|
193
|
-
timeElapsed: 50,
|
|
194
|
-
connectionTiming: {
|
|
195
|
-
connectionTime: 250,
|
|
196
|
-
dnsResolutionTime: 0,
|
|
197
|
-
sslTime: 100,
|
|
198
|
-
timeToFirstByte: 300,
|
|
199
|
-
},
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it('should provide the correct values resumed small payload H2', () => {
|
|
204
|
-
const connection = new TcpConnection(100, Infinity, 0, true, true);
|
|
205
|
-
connection.setWarmed(true);
|
|
206
|
-
connection.setH2OverflowBytesDownloaded(10000);
|
|
207
|
-
assert.deepEqual(connection.simulateDownloadUntil(7300), {
|
|
208
|
-
bytesDownloaded: 0,
|
|
209
|
-
extraBytesDownloaded: 2700, // 10000 - 7300
|
|
210
|
-
congestionWindow: 10,
|
|
211
|
-
roundTrips: 0,
|
|
212
|
-
timeElapsed: 0,
|
|
213
|
-
connectionTiming: {
|
|
214
|
-
timeToFirstByte: 0,
|
|
215
|
-
},
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it('should provide the correct values resumed large payload', () => {
|
|
220
|
-
const connection = new TcpConnection(100, 8 * 1000 * 1000);
|
|
221
|
-
const bytesToDownload = 5 * 1000 * 1000; // 5 mb
|
|
222
|
-
connection.setCongestionWindow(68);
|
|
223
|
-
assert.deepEqual(
|
|
224
|
-
connection.simulateDownloadUntil(bytesToDownload, {timeAlreadyElapsed: 5234}),
|
|
225
|
-
{
|
|
226
|
-
bytesDownloaded: bytesToDownload,
|
|
227
|
-
extraBytesDownloaded: 0,
|
|
228
|
-
congestionWindow: 68,
|
|
229
|
-
roundTrips: 51, // 5 mb / (1460 * 68)
|
|
230
|
-
timeElapsed: 5100,
|
|
231
|
-
connectionTiming: {
|
|
232
|
-
connectionTime: 250,
|
|
233
|
-
dnsResolutionTime: 0,
|
|
234
|
-
sslTime: 100,
|
|
235
|
-
timeToFirstByte: 300,
|
|
236
|
-
},
|
|
237
|
-
}
|
|
238
|
-
);
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
describe('when maximumTime is set', () => {
|
|
243
|
-
it('should provide the correct values less than TTFB', () => {
|
|
244
|
-
const connection = new TcpConnection(100, Infinity, 0, false);
|
|
245
|
-
assert.deepEqual(
|
|
246
|
-
connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 0, maximumTimeToElapse: 68}),
|
|
247
|
-
{
|
|
248
|
-
bytesDownloaded: 7300,
|
|
249
|
-
extraBytesDownloaded: 0,
|
|
250
|
-
congestionWindow: 10,
|
|
251
|
-
roundTrips: 2,
|
|
252
|
-
timeElapsed: 200,
|
|
253
|
-
connectionTiming: {
|
|
254
|
-
connectionTime: 150,
|
|
255
|
-
dnsResolutionTime: 0,
|
|
256
|
-
sslTime: undefined, // non-SSL
|
|
257
|
-
timeToFirstByte: 200,
|
|
258
|
-
},
|
|
259
|
-
}
|
|
260
|
-
);
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
it('should provide the correct values just over TTFB', () => {
|
|
264
|
-
const connection = new TcpConnection(100, Infinity, 0, false);
|
|
265
|
-
assert.deepEqual(
|
|
266
|
-
connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 0, maximumTimeToElapse: 250}),
|
|
267
|
-
{
|
|
268
|
-
bytesDownloaded: 7300,
|
|
269
|
-
extraBytesDownloaded: 0,
|
|
270
|
-
congestionWindow: 10,
|
|
271
|
-
roundTrips: 2,
|
|
272
|
-
timeElapsed: 200,
|
|
273
|
-
connectionTiming: {
|
|
274
|
-
connectionTime: 150,
|
|
275
|
-
dnsResolutionTime: 0,
|
|
276
|
-
sslTime: undefined, // non-SSL
|
|
277
|
-
timeToFirstByte: 200,
|
|
278
|
-
},
|
|
279
|
-
}
|
|
280
|
-
);
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
it('should provide the correct values with already elapsed', () => {
|
|
284
|
-
const connection = new TcpConnection(100, Infinity, 0, false);
|
|
285
|
-
assert.deepEqual(
|
|
286
|
-
connection.simulateDownloadUntil(7300, {
|
|
287
|
-
timeAlreadyElapsed: 75,
|
|
288
|
-
maximumTimeToElapse: 250,
|
|
289
|
-
}),
|
|
290
|
-
{
|
|
291
|
-
bytesDownloaded: 7300,
|
|
292
|
-
extraBytesDownloaded: 0,
|
|
293
|
-
congestionWindow: 10,
|
|
294
|
-
roundTrips: 2,
|
|
295
|
-
timeElapsed: 125,
|
|
296
|
-
connectionTiming: {
|
|
297
|
-
connectionTime: 150,
|
|
298
|
-
dnsResolutionTime: 0,
|
|
299
|
-
sslTime: undefined, // non-SSL
|
|
300
|
-
timeToFirstByte: 200,
|
|
301
|
-
},
|
|
302
|
-
}
|
|
303
|
-
);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
it('should provide the correct values large payloads', () => {
|
|
307
|
-
const connection = new TcpConnection(100, 8 * 1000 * 1000);
|
|
308
|
-
const bytesToDownload = 10 * 1000 * 1000; // 10 mb
|
|
309
|
-
assert.deepEqual(
|
|
310
|
-
connection.simulateDownloadUntil(bytesToDownload, {
|
|
311
|
-
timeAlreadyElapsed: 500,
|
|
312
|
-
maximumTimeToElapse: 740,
|
|
313
|
-
}),
|
|
314
|
-
{
|
|
315
|
-
bytesDownloaded: 683280, // should be less than 68 * 1460 * 8
|
|
316
|
-
extraBytesDownloaded: 0,
|
|
317
|
-
congestionWindow: 68,
|
|
318
|
-
roundTrips: 8,
|
|
319
|
-
timeElapsed: 800, // skips the handshake because time already elapsed
|
|
320
|
-
connectionTiming: {
|
|
321
|
-
connectionTime: 250,
|
|
322
|
-
dnsResolutionTime: 0,
|
|
323
|
-
sslTime: 100,
|
|
324
|
-
timeToFirstByte: 300,
|
|
325
|
-
},
|
|
326
|
-
}
|
|
327
|
-
);
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
it('should all add up', () => {
|
|
331
|
-
const connection = new TcpConnection(100, 8 * 1000 * 1000);
|
|
332
|
-
const bytesToDownload = 10 * 1000 * 1000; // 10 mb
|
|
333
|
-
const firstStoppingPoint = 5234;
|
|
334
|
-
const secondStoppingPoint = 315;
|
|
335
|
-
const thirdStoppingPoint = 10500 - firstStoppingPoint - secondStoppingPoint;
|
|
336
|
-
|
|
337
|
-
const firstSegment = connection.simulateDownloadUntil(bytesToDownload, {
|
|
338
|
-
timeAlreadyElapsed: 0,
|
|
339
|
-
maximumTimeToElapse: firstStoppingPoint,
|
|
340
|
-
});
|
|
341
|
-
const firstOvershoot = firstSegment.timeElapsed - firstStoppingPoint;
|
|
342
|
-
|
|
343
|
-
connection.setCongestionWindow(firstSegment.congestionWindow);
|
|
344
|
-
const secondSegment = connection.simulateDownloadUntil(
|
|
345
|
-
bytesToDownload - firstSegment.bytesDownloaded,
|
|
346
|
-
{
|
|
347
|
-
timeAlreadyElapsed: firstSegment.timeElapsed,
|
|
348
|
-
maximumTimeToElapse: secondStoppingPoint - firstOvershoot,
|
|
349
|
-
}
|
|
350
|
-
);
|
|
351
|
-
const secondOvershoot = firstOvershoot + secondSegment.timeElapsed - secondStoppingPoint;
|
|
352
|
-
|
|
353
|
-
connection.setCongestionWindow(secondSegment.congestionWindow);
|
|
354
|
-
const thirdSegment = connection.simulateDownloadUntil(
|
|
355
|
-
bytesToDownload - firstSegment.bytesDownloaded - secondSegment.bytesDownloaded,
|
|
356
|
-
{timeAlreadyElapsed: firstSegment.timeElapsed + secondSegment.timeElapsed}
|
|
357
|
-
);
|
|
358
|
-
const thirdOvershoot = secondOvershoot + thirdSegment.timeElapsed - thirdStoppingPoint;
|
|
359
|
-
|
|
360
|
-
assert.equal(thirdOvershoot, 0);
|
|
361
|
-
assert.equal(
|
|
362
|
-
firstSegment.bytesDownloaded +
|
|
363
|
-
secondSegment.bytesDownloaded +
|
|
364
|
-
thirdSegment.bytesDownloaded,
|
|
365
|
-
bytesToDownload
|
|
366
|
-
);
|
|
367
|
-
assert.equal(
|
|
368
|
-
firstSegment.timeElapsed + secondSegment.timeElapsed + thirdSegment.timeElapsed,
|
|
369
|
-
10500
|
|
370
|
-
);
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
});
|
|
374
|
-
});
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
export type ConnectionTiming = import('./SimulationTimingMap.js').ConnectionTiming;
|
|
2
|
-
export type DownloadOptions = {
|
|
3
|
-
dnsResolutionTime?: number | undefined;
|
|
4
|
-
timeAlreadyElapsed?: number | undefined;
|
|
5
|
-
maximumTimeToElapse?: number | undefined;
|
|
6
|
-
};
|
|
7
|
-
export type DownloadResults = {
|
|
8
|
-
roundTrips: number;
|
|
9
|
-
timeElapsed: number;
|
|
10
|
-
bytesDownloaded: number;
|
|
11
|
-
extraBytesDownloaded: number;
|
|
12
|
-
congestionWindow: number;
|
|
13
|
-
connectionTiming: ConnectionTiming;
|
|
14
|
-
};
|
|
15
|
-
export class TcpConnection {
|
|
16
|
-
/**
|
|
17
|
-
* @param {number} rtt
|
|
18
|
-
* @param {number} availableThroughput
|
|
19
|
-
* @return {number}
|
|
20
|
-
*/
|
|
21
|
-
static maximumSaturatedConnections(rtt: number, availableThroughput: number): number;
|
|
22
|
-
/**
|
|
23
|
-
* @param {number} rtt
|
|
24
|
-
* @param {number} throughput
|
|
25
|
-
* @param {number=} serverLatency
|
|
26
|
-
* @param {boolean=} ssl
|
|
27
|
-
* @param {boolean=} h2
|
|
28
|
-
*/
|
|
29
|
-
constructor(rtt: number, throughput: number, serverLatency?: number | undefined, ssl?: boolean | undefined, h2?: boolean | undefined);
|
|
30
|
-
_warmed: boolean;
|
|
31
|
-
_ssl: boolean;
|
|
32
|
-
_h2: boolean;
|
|
33
|
-
_rtt: number;
|
|
34
|
-
_throughput: number;
|
|
35
|
-
_serverLatency: number;
|
|
36
|
-
_congestionWindow: number;
|
|
37
|
-
_h2OverflowBytesDownloaded: number;
|
|
38
|
-
/**
|
|
39
|
-
* @return {number}
|
|
40
|
-
*/
|
|
41
|
-
_computeMaximumCongestionWindowInSegments(): number;
|
|
42
|
-
/**
|
|
43
|
-
* @param {number} throughput
|
|
44
|
-
*/
|
|
45
|
-
setThroughput(throughput: number): void;
|
|
46
|
-
/**
|
|
47
|
-
* @param {number} congestion
|
|
48
|
-
*/
|
|
49
|
-
setCongestionWindow(congestion: number): void;
|
|
50
|
-
/**
|
|
51
|
-
* @param {boolean} warmed
|
|
52
|
-
*/
|
|
53
|
-
setWarmed(warmed: boolean): void;
|
|
54
|
-
/**
|
|
55
|
-
* @return {boolean}
|
|
56
|
-
*/
|
|
57
|
-
isWarm(): boolean;
|
|
58
|
-
/**
|
|
59
|
-
* @return {boolean}
|
|
60
|
-
*/
|
|
61
|
-
isH2(): boolean;
|
|
62
|
-
/**
|
|
63
|
-
* @return {number}
|
|
64
|
-
*/
|
|
65
|
-
get congestionWindow(): number;
|
|
66
|
-
/**
|
|
67
|
-
* Sets the number of excess bytes that are available to this connection on future downloads, only
|
|
68
|
-
* applies to H2 connections.
|
|
69
|
-
* @param {number} bytes
|
|
70
|
-
*/
|
|
71
|
-
setH2OverflowBytesDownloaded(bytes: number): void;
|
|
72
|
-
/**
|
|
73
|
-
* @return {TcpConnection}
|
|
74
|
-
*/
|
|
75
|
-
clone(): TcpConnection;
|
|
76
|
-
/**
|
|
77
|
-
* Simulates a network download of a particular number of bytes over an optional maximum amount of time
|
|
78
|
-
* and returns information about the ending state.
|
|
79
|
-
*
|
|
80
|
-
* See https://hpbn.co/building-blocks-of-tcp/#three-way-handshake and
|
|
81
|
-
* https://hpbn.co/transport-layer-security-tls/#tls-handshake for details.
|
|
82
|
-
*
|
|
83
|
-
* @param {number} bytesToDownload
|
|
84
|
-
* @param {DownloadOptions} [options]
|
|
85
|
-
* @return {DownloadResults}
|
|
86
|
-
*/
|
|
87
|
-
simulateDownloadUntil(bytesToDownload: number, options?: DownloadOptions | undefined): DownloadResults;
|
|
88
|
-
}
|
|
89
|
-
//# sourceMappingURL=TcpConnection.d.ts.map
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2017 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/** @typedef {import('./SimulationTimingMap.js').ConnectionTiming} ConnectionTiming */
|
|
8
|
-
|
|
9
|
-
const INITIAL_CONGESTION_WINDOW = 10;
|
|
10
|
-
const TCP_SEGMENT_SIZE = 1460;
|
|
11
|
-
|
|
12
|
-
class TcpConnection {
|
|
13
|
-
/**
|
|
14
|
-
* @param {number} rtt
|
|
15
|
-
* @param {number} throughput
|
|
16
|
-
* @param {number=} serverLatency
|
|
17
|
-
* @param {boolean=} ssl
|
|
18
|
-
* @param {boolean=} h2
|
|
19
|
-
*/
|
|
20
|
-
constructor(rtt, throughput, serverLatency = 0, ssl = true, h2 = false) {
|
|
21
|
-
this._warmed = false;
|
|
22
|
-
this._ssl = ssl;
|
|
23
|
-
this._h2 = h2;
|
|
24
|
-
this._rtt = rtt;
|
|
25
|
-
this._throughput = throughput;
|
|
26
|
-
this._serverLatency = serverLatency;
|
|
27
|
-
this._congestionWindow = INITIAL_CONGESTION_WINDOW;
|
|
28
|
-
this._h2OverflowBytesDownloaded = 0;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @param {number} rtt
|
|
33
|
-
* @param {number} availableThroughput
|
|
34
|
-
* @return {number}
|
|
35
|
-
*/
|
|
36
|
-
static maximumSaturatedConnections(rtt, availableThroughput) {
|
|
37
|
-
const roundTripsPerSecond = 1000 / rtt;
|
|
38
|
-
const bytesPerRoundTrip = TCP_SEGMENT_SIZE;
|
|
39
|
-
const bytesPerSecond = roundTripsPerSecond * bytesPerRoundTrip;
|
|
40
|
-
const minimumThroughputRequiredPerRequest = bytesPerSecond * 8;
|
|
41
|
-
return Math.floor(availableThroughput / minimumThroughputRequiredPerRequest);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @return {number}
|
|
46
|
-
*/
|
|
47
|
-
_computeMaximumCongestionWindowInSegments() {
|
|
48
|
-
const bytesPerSecond = this._throughput / 8;
|
|
49
|
-
const secondsPerRoundTrip = this._rtt / 1000;
|
|
50
|
-
const bytesPerRoundTrip = bytesPerSecond * secondsPerRoundTrip;
|
|
51
|
-
return Math.floor(bytesPerRoundTrip / TCP_SEGMENT_SIZE);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @param {number} throughput
|
|
56
|
-
*/
|
|
57
|
-
setThroughput(throughput) {
|
|
58
|
-
this._throughput = throughput;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* @param {number} congestion
|
|
63
|
-
*/
|
|
64
|
-
setCongestionWindow(congestion) {
|
|
65
|
-
this._congestionWindow = congestion;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* @param {boolean} warmed
|
|
70
|
-
*/
|
|
71
|
-
setWarmed(warmed) {
|
|
72
|
-
this._warmed = warmed;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* @return {boolean}
|
|
77
|
-
*/
|
|
78
|
-
isWarm() {
|
|
79
|
-
return this._warmed;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* @return {boolean}
|
|
84
|
-
*/
|
|
85
|
-
isH2() {
|
|
86
|
-
return this._h2;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* @return {number}
|
|
91
|
-
*/
|
|
92
|
-
get congestionWindow() {
|
|
93
|
-
return this._congestionWindow;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Sets the number of excess bytes that are available to this connection on future downloads, only
|
|
98
|
-
* applies to H2 connections.
|
|
99
|
-
* @param {number} bytes
|
|
100
|
-
*/
|
|
101
|
-
setH2OverflowBytesDownloaded(bytes) {
|
|
102
|
-
if (!this._h2) return;
|
|
103
|
-
this._h2OverflowBytesDownloaded = bytes;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* @return {TcpConnection}
|
|
108
|
-
*/
|
|
109
|
-
clone() {
|
|
110
|
-
return Object.assign(new TcpConnection(this._rtt, this._throughput), this);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Simulates a network download of a particular number of bytes over an optional maximum amount of time
|
|
115
|
-
* and returns information about the ending state.
|
|
116
|
-
*
|
|
117
|
-
* See https://hpbn.co/building-blocks-of-tcp/#three-way-handshake and
|
|
118
|
-
* https://hpbn.co/transport-layer-security-tls/#tls-handshake for details.
|
|
119
|
-
*
|
|
120
|
-
* @param {number} bytesToDownload
|
|
121
|
-
* @param {DownloadOptions} [options]
|
|
122
|
-
* @return {DownloadResults}
|
|
123
|
-
*/
|
|
124
|
-
simulateDownloadUntil(bytesToDownload, options) {
|
|
125
|
-
const {timeAlreadyElapsed = 0, maximumTimeToElapse = Infinity, dnsResolutionTime = 0} =
|
|
126
|
-
options || {};
|
|
127
|
-
|
|
128
|
-
if (this._warmed && this._h2) {
|
|
129
|
-
bytesToDownload -= this._h2OverflowBytesDownloaded;
|
|
130
|
-
}
|
|
131
|
-
const twoWayLatency = this._rtt;
|
|
132
|
-
const oneWayLatency = twoWayLatency / 2;
|
|
133
|
-
const maximumCongestionWindow = this._computeMaximumCongestionWindowInSegments();
|
|
134
|
-
|
|
135
|
-
let handshakeAndRequest = oneWayLatency;
|
|
136
|
-
if (!this._warmed) {
|
|
137
|
-
handshakeAndRequest =
|
|
138
|
-
// DNS lookup
|
|
139
|
-
dnsResolutionTime +
|
|
140
|
-
// SYN
|
|
141
|
-
oneWayLatency +
|
|
142
|
-
// SYN ACK
|
|
143
|
-
oneWayLatency +
|
|
144
|
-
// ACK + initial request
|
|
145
|
-
oneWayLatency +
|
|
146
|
-
// ClientHello/ServerHello assuming TLS False Start is enabled (https://istlsfastyet.com/#server-performance).
|
|
147
|
-
(this._ssl ? twoWayLatency : 0);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
let roundTrips = Math.ceil(handshakeAndRequest / twoWayLatency);
|
|
151
|
-
let timeToFirstByte = handshakeAndRequest + this._serverLatency + oneWayLatency;
|
|
152
|
-
if (this._warmed && this._h2) timeToFirstByte = 0;
|
|
153
|
-
|
|
154
|
-
const timeElapsedForTTFB = Math.max(timeToFirstByte - timeAlreadyElapsed, 0);
|
|
155
|
-
const maximumDownloadTimeToElapse = maximumTimeToElapse - timeElapsedForTTFB;
|
|
156
|
-
|
|
157
|
-
let congestionWindow = Math.min(this._congestionWindow, maximumCongestionWindow);
|
|
158
|
-
let totalBytesDownloaded = 0;
|
|
159
|
-
if (timeElapsedForTTFB > 0) {
|
|
160
|
-
totalBytesDownloaded = congestionWindow * TCP_SEGMENT_SIZE;
|
|
161
|
-
} else {
|
|
162
|
-
roundTrips = 0;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
let downloadTimeElapsed = 0;
|
|
166
|
-
let bytesRemaining = bytesToDownload - totalBytesDownloaded;
|
|
167
|
-
while (bytesRemaining > 0 && downloadTimeElapsed <= maximumDownloadTimeToElapse) {
|
|
168
|
-
roundTrips++;
|
|
169
|
-
downloadTimeElapsed += twoWayLatency;
|
|
170
|
-
congestionWindow = Math.max(Math.min(maximumCongestionWindow, congestionWindow * 2), 1);
|
|
171
|
-
|
|
172
|
-
const bytesDownloadedInWindow = congestionWindow * TCP_SEGMENT_SIZE;
|
|
173
|
-
totalBytesDownloaded += bytesDownloadedInWindow;
|
|
174
|
-
bytesRemaining -= bytesDownloadedInWindow;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const timeElapsed = timeElapsedForTTFB + downloadTimeElapsed;
|
|
178
|
-
const extraBytesDownloaded = this._h2 ? Math.max(totalBytesDownloaded - bytesToDownload, 0) : 0;
|
|
179
|
-
const bytesDownloaded = Math.max(Math.min(totalBytesDownloaded, bytesToDownload), 0);
|
|
180
|
-
|
|
181
|
-
/** @type {ConnectionTiming} */
|
|
182
|
-
let connectionTiming;
|
|
183
|
-
if (!this._warmed) {
|
|
184
|
-
connectionTiming = {
|
|
185
|
-
dnsResolutionTime,
|
|
186
|
-
connectionTime: handshakeAndRequest - dnsResolutionTime,
|
|
187
|
-
sslTime: this._ssl ? twoWayLatency : undefined,
|
|
188
|
-
timeToFirstByte,
|
|
189
|
-
};
|
|
190
|
-
} else if (this._h2) {
|
|
191
|
-
// TODO: timing information currently difficult to model for warm h2 connections.
|
|
192
|
-
connectionTiming = {
|
|
193
|
-
timeToFirstByte,
|
|
194
|
-
};
|
|
195
|
-
} else {
|
|
196
|
-
connectionTiming = {
|
|
197
|
-
connectionTime: handshakeAndRequest,
|
|
198
|
-
timeToFirstByte,
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
roundTrips,
|
|
204
|
-
timeElapsed,
|
|
205
|
-
bytesDownloaded,
|
|
206
|
-
extraBytesDownloaded,
|
|
207
|
-
congestionWindow,
|
|
208
|
-
connectionTiming,
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export {TcpConnection};
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* @typedef DownloadOptions
|
|
217
|
-
* @property {number} [dnsResolutionTime]
|
|
218
|
-
* @property {number} [timeAlreadyElapsed]
|
|
219
|
-
* @property {number} [maximumTimeToElapse]
|
|
220
|
-
*/
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* @typedef DownloadResults
|
|
224
|
-
* @property {number} roundTrips
|
|
225
|
-
* @property {number} timeElapsed
|
|
226
|
-
* @property {number} bytesDownloaded
|
|
227
|
-
* @property {number} extraBytesDownloaded
|
|
228
|
-
* @property {number} congestionWindow
|
|
229
|
-
* @property {ConnectionTiming} connectionTiming
|
|
230
|
-
*/
|