@vpalmisano/webrtcperf 4.4.1 → 4.4.3
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/app.min.js +1 -1
- package/build/src/config.d.ts +1 -0
- package/build/src/config.js +11 -1
- package/build/src/config.js.map +1 -1
- package/build/src/docker.js +1 -1
- package/build/src/docker.js.map +1 -1
- package/build/src/session.d.ts +6 -1
- package/build/src/session.js +128 -79
- package/build/src/session.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +22 -22
- package/src/config.ts +11 -1
- package/src/docker.ts +1 -1
- package/src/session.ts +124 -72
package/src/session.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getSessionThrottleValues, throttleLauncher } from '@vpalmisano/throttler'
|
|
1
|
+
import { getSessionThrottleValues, throttleLauncher, throttleNotifier } from '@vpalmisano/throttler'
|
|
2
2
|
import assert from 'assert'
|
|
3
3
|
import axios from 'axios'
|
|
4
4
|
import EventEmitter from 'events'
|
|
@@ -30,8 +30,8 @@ import { gunzipSync } from 'zlib'
|
|
|
30
30
|
import { RtcStats, rtcStatKey, updateRtcStats } from './rtcstats'
|
|
31
31
|
import { FastStats } from './stats'
|
|
32
32
|
import {
|
|
33
|
-
PeerConnectionExternal,
|
|
34
|
-
PeerConnectionExternalMethod,
|
|
33
|
+
/* PeerConnectionExternal,
|
|
34
|
+
PeerConnectionExternalMethod, */
|
|
35
35
|
checkChromeExecutable,
|
|
36
36
|
downloadUrl,
|
|
37
37
|
enabledForSession,
|
|
@@ -163,6 +163,7 @@ export interface SessionParams {
|
|
|
163
163
|
userAgent: string
|
|
164
164
|
id: number
|
|
165
165
|
throttleIndex: number
|
|
166
|
+
useBrowserThrottling: boolean
|
|
166
167
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
167
168
|
evaluateAfter?: any[]
|
|
168
169
|
exposedFunctions?: string
|
|
@@ -279,6 +280,8 @@ export class Session extends EventEmitter {
|
|
|
279
280
|
readonly id: number
|
|
280
281
|
/** The throttle configuration index assigned to the session. */
|
|
281
282
|
readonly throttleIndex: number
|
|
283
|
+
/** If true, the network will be throttled using the browser internal throttling mechanism. */
|
|
284
|
+
readonly useBrowserThrottling: boolean
|
|
282
285
|
/** The test page url. */
|
|
283
286
|
readonly url: string
|
|
284
287
|
/** The url query. */
|
|
@@ -378,6 +381,7 @@ export class Session extends EventEmitter {
|
|
|
378
381
|
userAgent,
|
|
379
382
|
id,
|
|
380
383
|
throttleIndex,
|
|
384
|
+
useBrowserThrottling,
|
|
381
385
|
evaluateAfter,
|
|
382
386
|
exposedFunctions,
|
|
383
387
|
scriptParams,
|
|
@@ -475,6 +479,7 @@ export class Session extends EventEmitter {
|
|
|
475
479
|
this.emulateCpuThrottling = emulateCpuThrottling
|
|
476
480
|
|
|
477
481
|
this.throttleIndex = throttleIndex
|
|
482
|
+
this.useBrowserThrottling = useBrowserThrottling
|
|
478
483
|
this.evaluateAfter = evaluateAfter || []
|
|
479
484
|
this.exposedFunctions = exposedFunctions || {}
|
|
480
485
|
if (scriptParams) {
|
|
@@ -892,6 +897,9 @@ webrtcperf.config.AUDIO_URL = "http${this.serverUseHttps ? 's' : ''}://localhost
|
|
|
892
897
|
|
|
893
898
|
const page = await this.getNewPage(tabIndex)
|
|
894
899
|
|
|
900
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
901
|
+
const pageCDPSession = (page as any)._client() as CDPSession
|
|
902
|
+
|
|
895
903
|
await page.setBypassCSP(true)
|
|
896
904
|
|
|
897
905
|
if (this.userAgent) {
|
|
@@ -932,8 +940,7 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
|
|
|
932
940
|
// Clear cookies.
|
|
933
941
|
if (this.clearCookies) {
|
|
934
942
|
try {
|
|
935
|
-
|
|
936
|
-
await client.send('Network.clearBrowserCookies')
|
|
943
|
+
await pageCDPSession.send('Network.clearBrowserCookies')
|
|
937
944
|
} catch (err) {
|
|
938
945
|
log.error(`clearCookies error: ${(err as Error).stack}`)
|
|
939
946
|
}
|
|
@@ -977,8 +984,6 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
|
|
|
977
984
|
// Enable request interception.
|
|
978
985
|
let setRequestInterceptionState = true
|
|
979
986
|
|
|
980
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
981
|
-
const pageCDPSession = (page as any)._client() as CDPSession
|
|
982
987
|
await pageCDPSession.send('Network.setBypassServiceWorker', {
|
|
983
988
|
bypass: true,
|
|
984
989
|
})
|
|
@@ -1181,7 +1186,7 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
|
|
|
1181
1186
|
}
|
|
1182
1187
|
|
|
1183
1188
|
// PeerConnectionExternal
|
|
1184
|
-
await page.exposeFunction(
|
|
1189
|
+
/* await page.exposeFunction(
|
|
1185
1190
|
'createPeerConnectionExternal',
|
|
1186
1191
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1187
1192
|
async (options: any) => {
|
|
@@ -1199,7 +1204,7 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
|
|
|
1199
1204
|
return pc[name](arg)
|
|
1200
1205
|
}
|
|
1201
1206
|
},
|
|
1202
|
-
)
|
|
1207
|
+
)*/
|
|
1203
1208
|
|
|
1204
1209
|
// Simulate keypress
|
|
1205
1210
|
await page.exposeFunction('keypressText', async (selector: string, text: string, delay = 20) => {
|
|
@@ -1362,77 +1367,32 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
|
|
|
1362
1367
|
}
|
|
1363
1368
|
})
|
|
1364
1369
|
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
sentBytes: 0,
|
|
1368
|
-
recvBytes: 0,
|
|
1369
|
-
recvLatency: new FastStats({ store_data: false }),
|
|
1370
|
-
wsSentBytes: 0,
|
|
1371
|
-
wsRecvBytes: 0,
|
|
1372
|
-
wsRecvLatency: new FastStats({ store_data: false }),
|
|
1373
|
-
}
|
|
1374
|
-
this.httpResourcesStats.set(index, resourcesStats)
|
|
1375
|
-
|
|
1376
|
-
const pendingRequests = new Map<string, { url: string; timestamp: number }>()
|
|
1377
|
-
pageCDPSession.on('Network.requestWillBeSent', event => {
|
|
1378
|
-
if (event.request.url.startsWith('data:')) return
|
|
1379
|
-
const { requestId, request, timestamp } = event
|
|
1380
|
-
const sentBytes = request.postDataEntries?.reduce((acc, entry) => acc + (entry.bytes?.length || 0), 0)
|
|
1381
|
-
//log.log('Network.requestWillBeSent', event.type, request.url, sentBytes)
|
|
1382
|
-
if (sentBytes) resourcesStats.sentBytes += sentBytes
|
|
1383
|
-
pendingRequests.set(requestId, { url: request.url, timestamp })
|
|
1384
|
-
})
|
|
1385
|
-
|
|
1386
|
-
pageCDPSession.on('Network.responseReceived', event => {
|
|
1387
|
-
const request = pendingRequests.get(event.requestId)
|
|
1388
|
-
if (!request) return
|
|
1389
|
-
const { response } = event
|
|
1390
|
-
if (response.fromDiskCache) {
|
|
1391
|
-
pendingRequests.delete(event.requestId)
|
|
1392
|
-
return
|
|
1393
|
-
}
|
|
1394
|
-
resourcesStats.recvBytes += response.encodedDataLength
|
|
1370
|
+
await page.exposeFunction('webrtcperf_reload', () => {
|
|
1371
|
+
return page.reload()
|
|
1395
1372
|
})
|
|
1396
1373
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
if (!request) return
|
|
1400
|
-
resourcesStats.recvBytes += event.encodedDataLength
|
|
1401
|
-
})
|
|
1402
|
-
|
|
1403
|
-
pageCDPSession.on('Network.loadingFinished', event => {
|
|
1404
|
-
const request = pendingRequests.get(event.requestId)
|
|
1405
|
-
if (!request) return
|
|
1406
|
-
pendingRequests.delete(event.requestId)
|
|
1407
|
-
const { timestamp } = event
|
|
1408
|
-
resourcesStats.recvLatency.push(timestamp - request.timestamp)
|
|
1409
|
-
})
|
|
1410
|
-
|
|
1411
|
-
pageCDPSession.on('Network.webSocketCreated', event => {
|
|
1412
|
-
pendingRequests.set(event.requestId, { url: event.url, timestamp: Date.now() })
|
|
1413
|
-
})
|
|
1414
|
-
|
|
1415
|
-
pageCDPSession.on('Network.webSocketHandshakeResponseReceived', event => {
|
|
1416
|
-
const request = pendingRequests.get(event.requestId)
|
|
1417
|
-
if (!request) return
|
|
1418
|
-
pendingRequests.delete(event.requestId)
|
|
1419
|
-
resourcesStats.wsRecvLatency.push((Date.now() - request.timestamp) / 1000)
|
|
1420
|
-
})
|
|
1421
|
-
|
|
1422
|
-
pageCDPSession.on('Network.webSocketFrameSent', event => {
|
|
1423
|
-
resourcesStats.wsSentBytes += event.response.payloadData.length
|
|
1424
|
-
})
|
|
1425
|
-
|
|
1426
|
-
pageCDPSession.on('Network.webSocketFrameReceived', event => {
|
|
1427
|
-
resourcesStats.wsRecvBytes += event.response.payloadData.length
|
|
1428
|
-
})
|
|
1374
|
+
// HTTP stats.
|
|
1375
|
+
this.setupPageNetworkStats(pageCDPSession, index)
|
|
1429
1376
|
|
|
1430
|
-
//
|
|
1377
|
+
// Hardware concurrency.
|
|
1431
1378
|
if (this.hardwareConcurrency) {
|
|
1432
1379
|
const plugin = NavigatorHardwareConcurrency({ hardwareConcurrency: this.hardwareConcurrency })
|
|
1433
1380
|
await plugin.onPageCreated(page)
|
|
1434
1381
|
}
|
|
1435
1382
|
|
|
1383
|
+
// Network throttling.
|
|
1384
|
+
if (this.throttleIndex > -1 && (process.platform !== 'linux' || this.useBrowserThrottling)) {
|
|
1385
|
+
log.debug(`Using internal network throttling`)
|
|
1386
|
+
await pageCDPSession.send('Network.emulateNetworkConditions', {
|
|
1387
|
+
offline: false,
|
|
1388
|
+
uploadThroughput: 100000000 / 8,
|
|
1389
|
+
downloadThroughput: 100000000 / 8,
|
|
1390
|
+
latency: 0,
|
|
1391
|
+
packetLoss: 0,
|
|
1392
|
+
packetQueueLength: 0,
|
|
1393
|
+
})
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1436
1396
|
// Load page script.
|
|
1437
1397
|
{
|
|
1438
1398
|
const filePath = resolvePackagePath('node_modules/@vpalmisano/webrtcperf-js/dist/webrtcperf.js')
|
|
@@ -1492,6 +1452,13 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
|
|
|
1492
1452
|
// add to pages map
|
|
1493
1453
|
this.pages.set(index, page)
|
|
1494
1454
|
|
|
1455
|
+
if (this.throttleIndex > -1 && (process.platform !== 'linux' || this.useBrowserThrottling)) {
|
|
1456
|
+
await this.applyNetworkThrottling(pageCDPSession)
|
|
1457
|
+
throttleNotifier.on('change', async () => {
|
|
1458
|
+
await this.applyNetworkThrottling(pageCDPSession)
|
|
1459
|
+
})
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1495
1462
|
log.debug(`Page ${index + 1} "${url}" loaded in ${(Date.now() - pageLoadTime) / 1000}s`)
|
|
1496
1463
|
|
|
1497
1464
|
for (let i = 0; i < this.evaluateAfter.length; i++) {
|
|
@@ -1503,6 +1470,91 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
|
|
|
1503
1470
|
}
|
|
1504
1471
|
}
|
|
1505
1472
|
|
|
1473
|
+
private setupPageNetworkStats(pageCDPSession: CDPSession, index: number) {
|
|
1474
|
+
const resourcesStats = {
|
|
1475
|
+
sentBytes: 0,
|
|
1476
|
+
recvBytes: 0,
|
|
1477
|
+
recvLatency: new FastStats({ store_data: false }),
|
|
1478
|
+
wsSentBytes: 0,
|
|
1479
|
+
wsRecvBytes: 0,
|
|
1480
|
+
wsRecvLatency: new FastStats({ store_data: false }),
|
|
1481
|
+
}
|
|
1482
|
+
this.httpResourcesStats.set(index, resourcesStats)
|
|
1483
|
+
|
|
1484
|
+
const pendingRequests = new Map<string, { url: string; timestamp: number }>()
|
|
1485
|
+
pageCDPSession.on('Network.requestWillBeSent', event => {
|
|
1486
|
+
if (event.request.url.startsWith('data:')) return
|
|
1487
|
+
const { requestId, request, timestamp } = event
|
|
1488
|
+
const sentBytes = request.postDataEntries?.reduce((acc, entry) => acc + (entry.bytes?.length || 0), 0)
|
|
1489
|
+
//log.log('Network.requestWillBeSent', event.type, request.url, sentBytes)
|
|
1490
|
+
if (sentBytes) resourcesStats.sentBytes += sentBytes
|
|
1491
|
+
pendingRequests.set(requestId, { url: request.url, timestamp })
|
|
1492
|
+
})
|
|
1493
|
+
|
|
1494
|
+
pageCDPSession.on('Network.responseReceived', event => {
|
|
1495
|
+
const request = pendingRequests.get(event.requestId)
|
|
1496
|
+
if (!request) return
|
|
1497
|
+
const { response } = event
|
|
1498
|
+
if (response.fromDiskCache) {
|
|
1499
|
+
pendingRequests.delete(event.requestId)
|
|
1500
|
+
return
|
|
1501
|
+
}
|
|
1502
|
+
resourcesStats.recvBytes += response.encodedDataLength
|
|
1503
|
+
})
|
|
1504
|
+
|
|
1505
|
+
pageCDPSession.on('Network.dataReceived', event => {
|
|
1506
|
+
const request = pendingRequests.get(event.requestId)
|
|
1507
|
+
if (!request) return
|
|
1508
|
+
resourcesStats.recvBytes += event.encodedDataLength
|
|
1509
|
+
})
|
|
1510
|
+
|
|
1511
|
+
pageCDPSession.on('Network.loadingFinished', event => {
|
|
1512
|
+
const request = pendingRequests.get(event.requestId)
|
|
1513
|
+
if (!request) return
|
|
1514
|
+
pendingRequests.delete(event.requestId)
|
|
1515
|
+
const { timestamp } = event
|
|
1516
|
+
resourcesStats.recvLatency.push(timestamp - request.timestamp)
|
|
1517
|
+
})
|
|
1518
|
+
|
|
1519
|
+
pageCDPSession.on('Network.webSocketCreated', event => {
|
|
1520
|
+
pendingRequests.set(event.requestId, { url: event.url, timestamp: Date.now() })
|
|
1521
|
+
})
|
|
1522
|
+
|
|
1523
|
+
pageCDPSession.on('Network.webSocketHandshakeResponseReceived', event => {
|
|
1524
|
+
const request = pendingRequests.get(event.requestId)
|
|
1525
|
+
if (!request) return
|
|
1526
|
+
pendingRequests.delete(event.requestId)
|
|
1527
|
+
resourcesStats.wsRecvLatency.push((Date.now() - request.timestamp) / 1000)
|
|
1528
|
+
})
|
|
1529
|
+
|
|
1530
|
+
pageCDPSession.on('Network.webSocketFrameSent', event => {
|
|
1531
|
+
resourcesStats.wsSentBytes += event.response.payloadData.length
|
|
1532
|
+
})
|
|
1533
|
+
|
|
1534
|
+
pageCDPSession.on('Network.webSocketFrameReceived', event => {
|
|
1535
|
+
resourcesStats.wsRecvBytes += event.response.payloadData.length
|
|
1536
|
+
})
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
private async applyNetworkThrottling(pageCDPSession: CDPSession) {
|
|
1540
|
+
const throttleUpValues = getSessionThrottleValues(this.throttleIndex, 'up')
|
|
1541
|
+
const throttleDownValues = getSessionThrottleValues(this.throttleIndex, 'down')
|
|
1542
|
+
const params = {
|
|
1543
|
+
offline: false,
|
|
1544
|
+
uploadThroughput: throttleUpValues.rate || -1,
|
|
1545
|
+
downloadThroughput: throttleDownValues.rate || -1,
|
|
1546
|
+
latency: Math.max(throttleUpValues.delay || 0, throttleDownValues.delay || 0),
|
|
1547
|
+
packetLoss: Math.max(throttleUpValues.loss || 0, throttleDownValues.loss || 0),
|
|
1548
|
+
packetQueueLength: Math.max(throttleUpValues.queue || 0, throttleDownValues.queue || 0),
|
|
1549
|
+
}
|
|
1550
|
+
log.debug(`Apply internal network throttling: ${JSON.stringify(params)}`)
|
|
1551
|
+
await pageCDPSession.send('Network.emulateNetworkConditions', {
|
|
1552
|
+
...params,
|
|
1553
|
+
uploadThroughput: params.uploadThroughput !== -1 ? params.uploadThroughput / 8 : -1,
|
|
1554
|
+
downloadThroughput: params.downloadThroughput !== -1 ? params.downloadThroughput / 8 : -1,
|
|
1555
|
+
})
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1506
1558
|
private async getNewPage(tabIndex: number): Promise<Page> {
|
|
1507
1559
|
log.debug(`getNewPage ${tabIndex}`)
|
|
1508
1560
|
assert(this.context, 'NoBrowserContextCreated')
|