From be2ab516578228f7d0b570ab0d429e1e4f45a7c3 Mon Sep 17 00:00:00 2001 From: Connor Clark Date: Tue, 4 Jun 2024 12:05:43 -0700 Subject: [PATCH] core(lantern): rename NetworkRequest record to rawRequest (#16037) --- core/audits/uses-rel-preload.js | 18 +-- core/computed/critical-request-chains.js | 6 +- core/lib/lantern-trace-saver.js | 2 +- core/lib/lantern/network-node.js | 6 +- core/lib/lantern/page-dependency-graph.js | 88 +++++++-------- core/lib/lantern/simulator/connection-pool.js | 44 ++++---- core/lib/lantern/simulator/dns-cache.js | 2 +- .../lib/lantern/simulator/network-analyzer.js | 106 +++++++++--------- core/lib/lantern/simulator/simulator.js | 32 +++--- core/lib/lantern/types/lantern.d.ts | 11 +- core/lib/network-request.js | 2 +- .../lib/lantern/page-dependency-graph-test.js | 78 ++++++------- .../lantern/simulator/connection-pool-test.js | 78 ++++++------- .../lib/lantern/simulator/dns-cache-test.js | 2 +- .../simulator/network-analyzer-test.js | 62 +++++----- .../lib/lantern/simulator/simulator-test.js | 12 +- 16 files changed, 275 insertions(+), 274 deletions(-) diff --git a/core/audits/uses-rel-preload.js b/core/audits/uses-rel-preload.js index 4bb79844e7bf..c74dd1b20269 100644 --- a/core/audits/uses-rel-preload.js +++ b/core/audits/uses-rel-preload.js @@ -61,8 +61,8 @@ class UsesRelPreloadAudit extends Audit { if (node.type !== 'network') return; // Don't include the node itself or any CPU nodes in the initiatorPath const path = traversalPath.slice(1).filter(initiator => initiator.type === 'network'); - if (!UsesRelPreloadAudit.shouldPreloadRequest(node.record, mainResource, path)) return; - urls.add(node.record.url); + if (!UsesRelPreloadAudit.shouldPreloadRequest(node.rawRequest, mainResource, path)) return; + urls.add(node.rawRequest.url); }); return urls; @@ -77,7 +77,7 @@ class UsesRelPreloadAudit extends Audit { static getURLsFailedToPreload(graph) { /** @type {Array} */ const requests = []; - graph.traverse(node => node.type === 'network' && requests.push(node.record)); + graph.traverse(node => node.type === 'network' && requests.push(node.rawRequest)); const preloadRequests = requests.filter(req => req.isLinkPreload); const preloadURLsByFrame = new Map(); @@ -157,7 +157,7 @@ class UsesRelPreloadAudit extends Audit { if (node.isMainDocument()) { mainDocumentNode = node; - } else if (node.record && urls.has(node.record.url)) { + } else if (node.rawRequest && urls.has(node.rawRequest.url)) { nodesToPreload.push(node); } }); @@ -176,20 +176,20 @@ class UsesRelPreloadAudit extends Audit { // Once we've modified the dependencies, simulate the new graph. const simulationAfterChanges = simulator.simulate(modifiedGraph); - const originalNodesByRecord = Array.from(simulationBeforeChanges.nodeTimings.keys()) - // @ts-expect-error we don't care if all nodes without a record collect on `undefined` - .reduce((map, node) => map.set(node.record, node), new Map()); + const originalNodesByRequest = Array.from(simulationBeforeChanges.nodeTimings.keys()) + // @ts-expect-error we don't care if all nodes without a request collect on `undefined` + .reduce((map, node) => map.set(node.request, node), new Map()); const results = []; for (const node of nodesToPreload) { - const originalNode = originalNodesByRecord.get(node.record); + const originalNode = originalNodesByRequest.get(node.request); const timingAfter = simulationAfterChanges.nodeTimings.get(node); const timingBefore = simulationBeforeChanges.nodeTimings.get(originalNode); if (!timingBefore || !timingAfter) throw new Error('Missing preload node'); const wastedMs = Math.round(timingBefore.endTime - timingAfter.endTime); if (wastedMs < THRESHOLD_IN_MS) continue; - results.push({url: node.record.url, wastedMs}); + results.push({url: node.rawRequest.url, wastedMs}); } if (!results.length) { diff --git a/core/computed/critical-request-chains.js b/core/computed/critical-request-chains.js index 05635f16a9e7..9fe8b7755a09 100644 --- a/core/computed/critical-request-chains.js +++ b/core/computed/critical-request-chains.js @@ -105,19 +105,19 @@ class CriticalRequestChains { graph.traverse((node, traversalPath) => { seenNodes.add(node); if (node.type !== 'network') return; - if (!CriticalRequestChains.isCritical(node.record, mainResource)) return; + if (!CriticalRequestChains.isCritical(node.rawRequest, mainResource)) return; const networkPath = traversalPath .filter(/** @return {n is LH.Gatherer.Simulation.GraphNetworkNode} */ n => n.type === 'network') .reverse() - .map(node => node.record); + .map(node => node.rawRequest); // Ignore if some ancestor is not a critical request. if (networkPath.some(r => !CriticalRequestChains.isCritical(r, mainResource))) return; // Ignore non-network things (like data urls). - if (NetworkRequest.isNonNetworkRequest(node.record)) return; + if (NetworkRequest.isNonNetworkRequest(node.rawRequest)) return; addChain(networkPath); }, getNextNodes); diff --git a/core/lib/lantern-trace-saver.js b/core/lib/lantern-trace-saver.js index ec3a98952290..82cab33e4b02 100644 --- a/core/lib/lantern-trace-saver.js +++ b/core/lib/lantern-trace-saver.js @@ -33,7 +33,7 @@ function convertNodeTimingsToTrace(nodeTimings) { traceEvents.push(...createFakeTaskEvents(node, timing)); } else { /** @type {LH.Artifacts.NetworkRequest} */ - const record = node.record; + const record = node.rawRequest; // Ignore data URIs as they don't really add much value if (/^data/.test(record.url)) continue; traceEvents.push(...createFakeNetworkEvents(requestId, record, timing)); diff --git a/core/lib/lantern/network-node.js b/core/lib/lantern/network-node.js index adb7760a6edc..a95bb73f98ea 100644 --- a/core/lib/lantern/network-node.js +++ b/core/lib/lantern/network-node.js @@ -68,8 +68,8 @@ class NetworkNode extends BaseNode { /** * @return {Readonly} */ - get record() { - return /** @type {Required} */ (this._request.record); + get rawRequest() { + return /** @type {Required} */ (this._request.rawRequest); } /** @@ -104,7 +104,7 @@ class NetworkNode extends BaseNode { } /** - * Returns whether this network record can be downloaded without a TCP connection. + * Returns whether this network request can be downloaded without a TCP connection. * During simulation we treat data coming in over a network connection separately from on-device data. * @return {boolean} */ diff --git a/core/lib/lantern/page-dependency-graph.js b/core/lib/lantern/page-dependency-graph.js index a7de6562bb95..b0311d4b08c1 100644 --- a/core/lib/lantern/page-dependency-graph.js +++ b/core/lib/lantern/page-dependency-graph.js @@ -32,19 +32,19 @@ const IGNORED_MIME_TYPES_REGEX = /^video/; class PageDependencyGraph { /** - * @param {Lantern.NetworkRequest} record + * @param {Lantern.NetworkRequest} request * @return {Array} */ - static getNetworkInitiators(record) { - if (!record.initiator) return []; - if (record.initiator.url) return [record.initiator.url]; - if (record.initiator.type === 'script') { + static getNetworkInitiators(request) { + if (!request.initiator) return []; + if (request.initiator.url) return [request.initiator.url]; + if (request.initiator.type === 'script') { // Script initiators have the stack of callFrames from all functions that led to this request. // If async stacks are enabled, then the stack will also have the parent functions that asynchronously // led to this request chained in the `parent` property. /** @type {Set} */ const scriptURLs = new Set(); - let stack = record.initiator.stack; + let stack = request.initiator.stack; while (stack) { const callFrames = stack.callFrames || []; for (const frame of callFrames) { @@ -61,10 +61,10 @@ class PageDependencyGraph { } /** - * @param {Array} networkRecords + * @param {Array} networkRequests * @return {NetworkNodeOutput} */ - static getNetworkNodeOutput(networkRecords) { + static getNetworkNodeOutput(networkRequests) { /** @type {Array} */ const nodes = []; /** @type {Map} */ @@ -74,35 +74,35 @@ class PageDependencyGraph { /** @type {Map} */ const frameIdToNodeMap = new Map(); - networkRecords.forEach(record => { - if (IGNORED_MIME_TYPES_REGEX.test(record.mimeType)) return; - if (record.fromWorker) return; + networkRequests.forEach(request => { + if (IGNORED_MIME_TYPES_REGEX.test(request.mimeType)) return; + if (request.fromWorker) return; - // Network record requestIds can be duplicated for an unknown reason - // Suffix all subsequent records with `:duplicate` until it's unique + // Network requestIds can be duplicated for an unknown reason + // Suffix all subsequent requests with `:duplicate` until it's unique // NOTE: This should never happen with modern NetworkRequest library, but old fixtures // might still have this issue. - while (idToNodeMap.has(record.requestId)) { - record.requestId += ':duplicate'; + while (idToNodeMap.has(request.requestId)) { + request.requestId += ':duplicate'; } - const node = new NetworkNode(record); + const node = new NetworkNode(request); nodes.push(node); - const urlList = urlToNodeMap.get(record.url) || []; + const urlList = urlToNodeMap.get(request.url) || []; urlList.push(node); - idToNodeMap.set(record.requestId, node); - urlToNodeMap.set(record.url, urlList); + idToNodeMap.set(request.requestId, node); + urlToNodeMap.set(request.url, urlList); // If the request was for the root document of an iframe, save an entry in our // map so we can link up the task `args.data.frame` dependencies later in graph creation. - if (record.frameId && - record.resourceType === NetworkRequestTypes.Document && - record.documentURL === record.url) { + if (request.frameId && + request.resourceType === NetworkRequestTypes.Document && + request.documentURL === request.url) { // If there's ever any ambiguity, permanently set the value to `false` to avoid loops in the graph. - const value = frameIdToNodeMap.has(record.frameId) ? null : node; - frameIdToNodeMap.set(record.frameId, value); + const value = frameIdToNodeMap.has(request.frameId) ? null : node; + frameIdToNodeMap.set(request.frameId, value); } }); @@ -427,7 +427,7 @@ class PageDependencyGraph { } for (const r of lanternRequests) { - delete r.record; + delete r.rawRequest; if (r.initiatorRequest) { // @ts-expect-error r.initiatorRequest = {id: r.initiatorRequest.requestId}; @@ -508,25 +508,25 @@ class PageDependencyGraph { /** * @param {LH.TraceEvent[]} mainThreadEvents - * @param {Array} networkRecords + * @param {Lantern.NetworkRequest[]} networkRequests * @param {URLArtifact} URL * @return {Node} */ - static createGraph(mainThreadEvents, networkRecords, URL) { + static createGraph(mainThreadEvents, networkRequests, URL) { // This is for debugging trace/devtoolslog network records. - // const debug = PageDependencyGraph._debugNormalizeRequests(networkRecords); - const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRecords); + // const debug = PageDependencyGraph._debugNormalizeRequests(networkRequests); + const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRequests); const cpuNodes = PageDependencyGraph.getCPUNodes(mainThreadEvents); const {requestedUrl, mainDocumentUrl} = URL; if (!requestedUrl) throw new Error('requestedUrl is required to get the root request'); if (!mainDocumentUrl) throw new Error('mainDocumentUrl is required to get the main resource'); - const rootRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl); + const rootRequest = NetworkAnalyzer.findResourceForUrl(networkRequests, requestedUrl); if (!rootRequest) throw new Error('rootRequest not found'); const rootNode = networkNodeOutput.idToNodeMap.get(rootRequest.requestId); if (!rootNode) throw new Error('rootNode not found'); const mainDocumentRequest = - NetworkAnalyzer.findLastDocumentForUrl(networkRecords, mainDocumentUrl); + NetworkAnalyzer.findLastDocumentForUrl(networkRequests, mainDocumentUrl); if (!mainDocumentRequest) throw new Error('mainDocumentRequest not found'); const mainDocumentNode = networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId); if (!mainDocumentNode) throw new Error('mainDocumentNode not found'); @@ -543,20 +543,20 @@ class PageDependencyGraph { } /** - * @param {Lantern.NetworkRequest} record The record to find the initiator of - * @param {Map} recordsByURL + * @param {Lantern.NetworkRequest} request The request to find the initiator of + * @param {Map} requestsByURL * @return {Lantern.NetworkRequest|null} */ - static chooseInitiatorRequest(record, recordsByURL) { - if (record.redirectSource) { - return record.redirectSource; + static chooseInitiatorRequest(request, requestsByURL) { + if (request.redirectSource) { + return request.redirectSource; } - const initiatorURL = PageDependencyGraph.getNetworkInitiators(record)[0]; - let candidates = recordsByURL.get(initiatorURL) || []; + const initiatorURL = PageDependencyGraph.getNetworkInitiators(request)[0]; + let candidates = requestsByURL.get(initiatorURL) || []; // The (valid) initiator must come before the initiated request. candidates = candidates.filter(c => { - return c.responseHeadersEndTime <= record.rendererStartTime && + return c.responseHeadersEndTime <= request.rendererStartTime && c.finished && !c.failed; }); if (candidates.length > 1) { @@ -570,12 +570,12 @@ class PageDependencyGraph { } if (candidates.length > 1) { // Disambiguate based on frame. It's likely that the initiator comes from the same frame. - const sameFrameCandidates = candidates.filter(cand => cand.frameId === record.frameId); + const sameFrameCandidates = candidates.filter(cand => cand.frameId === request.frameId); if (sameFrameCandidates.length) { candidates = sameFrameCandidates; } } - if (candidates.length > 1 && record.initiator.type === 'parser') { + if (candidates.length > 1 && request.initiator.type === 'parser') { // Filter to just Documents when initiator type is parser. const documentCandidates = candidates.filter(cand => cand.resourceType === RESOURCE_TYPES.Document); @@ -728,6 +728,7 @@ class PageDependencyGraph { } return { + rawRequest: request, requestId: request.args.data.requestId, connectionId: request.args.data.connectionId, connectionReused: request.args.data.connectionReused, @@ -754,7 +755,6 @@ class PageDependencyGraph { priority: request.args.data.priority, frameId: request.args.data.frame, fromWorker, - record: request, // Set later. redirects: undefined, redirectSource: undefined, @@ -805,9 +805,9 @@ class PageDependencyGraph { // TraceEngine consolidates all redirects into a single request object, but lantern needs // an entry for each redirected request. for (const request of [...lanternRequests]) { - if (!request.record) continue; + if (!request.rawRequest) continue; - const redirects = request.record.args.data.redirects; + const redirects = request.rawRequest.args.data.redirects; if (!redirects.length) continue; const requestChain = []; diff --git a/core/lib/lantern/simulator/connection-pool.js b/core/lib/lantern/simulator/connection-pool.js index b582863ddecb..fd42af55e0c3 100644 --- a/core/lib/lantern/simulator/connection-pool.js +++ b/core/lib/lantern/simulator/connection-pool.js @@ -27,7 +27,7 @@ export class ConnectionPool { /** @type {Map} */ this._connectionsByOrigin = new Map(); /** @type {Map} */ - this._connectionsByRecord = new Map(); + this._connectionsByRequest = new Map(); this._connectionsInUse = new Set(); this._connectionReusedByRequestId = NetworkAnalyzer.estimateIfConnectionWasReused(records, { forceCoarseEstimates: true, @@ -49,16 +49,16 @@ export class ConnectionPool { const serverResponseTimeByOrigin = this._options.serverResponseTimeByOrigin; const recordsByOrigin = NetworkAnalyzer.groupByOrigin(this._records); - for (const [origin, records] of recordsByOrigin.entries()) { + for (const [origin, requests] of recordsByOrigin.entries()) { const connections = []; const additionalRtt = additionalRttByOrigin.get(origin) || 0; const responseTime = serverResponseTimeByOrigin.get(origin) || DEFAULT_SERVER_RESPONSE_TIME; - for (const record of records) { - if (connectionReused.get(record.requestId)) continue; + for (const request of requests) { + if (connectionReused.get(request.requestId)) continue; - const isTLS = TLS_SCHEMES.includes(record.parsedURL.scheme); - const isH2 = record.protocol === 'h2'; + const isTLS = TLS_SCHEMES.includes(request.parsedURL.scheme); + const isH2 = request.protocol === 'h2'; const connection = new TcpConnection( this._options.rtt + additionalRtt, this._options.throughput, @@ -106,47 +106,47 @@ export class ConnectionPool { } /** - * This method finds an available connection to the origin specified by the network record or null + * This method finds an available connection to the origin specified by the network request or null * if no connection was available. If returned, connection will not be available for other network * records until release is called. * - * @param {Lantern.NetworkRequest} record + * @param {Lantern.NetworkRequest} request * @return {?TcpConnection} */ - acquire(record) { - if (this._connectionsByRecord.has(record)) throw new Error('Record already has a connection'); + acquire(request) { + if (this._connectionsByRequest.has(request)) throw new Error('Record already has a connection'); - const origin = record.parsedURL.securityOrigin; + const origin = request.parsedURL.securityOrigin; const connections = this._connectionsByOrigin.get(origin) || []; const connectionToUse = this._findAvailableConnectionWithLargestCongestionWindow(connections); if (!connectionToUse) return null; this._connectionsInUse.add(connectionToUse); - this._connectionsByRecord.set(record, connectionToUse); + this._connectionsByRequest.set(request, connectionToUse); return connectionToUse; } /** - * Return the connection currently being used to fetch a record. If no connection - * currently being used for this record, an error will be thrown. + * Return the connection currently being used to fetch a request. If no connection + * currently being used for this request, an error will be thrown. * - * @param {Lantern.NetworkRequest} record + * @param {Lantern.NetworkRequest} request * @return {TcpConnection} */ - acquireActiveConnectionFromRecord(record) { - const activeConnection = this._connectionsByRecord.get(record); - if (!activeConnection) throw new Error('Could not find an active connection for record'); + acquireActiveConnectionFromRequest(request) { + const activeConnection = this._connectionsByRequest.get(request); + if (!activeConnection) throw new Error('Could not find an active connection for request'); return activeConnection; } /** - * @param {Lantern.NetworkRequest} record + * @param {Lantern.NetworkRequest} request */ - release(record) { - const connection = this._connectionsByRecord.get(record); - this._connectionsByRecord.delete(record); + release(request) { + const connection = this._connectionsByRequest.get(request); + this._connectionsByRequest.delete(request); this._connectionsInUse.delete(connection); } } diff --git a/core/lib/lantern/simulator/dns-cache.js b/core/lib/lantern/simulator/dns-cache.js index 97b451c34536..2598d7038514 100644 --- a/core/lib/lantern/simulator/dns-cache.js +++ b/core/lib/lantern/simulator/dns-cache.js @@ -58,7 +58,7 @@ class DNSCache { } /** - * Forcefully sets the DNS resolution time for a record. + * Forcefully sets the DNS resolution time for a request. * Useful for testing and alternate execution simulations. * * @param {string} domain diff --git a/core/lib/lantern/simulator/network-analyzer.js b/core/lib/lantern/simulator/network-analyzer.js index dcbf114f4515..d790c3a4cd27 100644 --- a/core/lib/lantern/simulator/network-analyzer.js +++ b/core/lib/lantern/simulator/network-analyzer.js @@ -88,30 +88,30 @@ class NetworkAnalyzer { return summaryByKey; } - /** @typedef {{record: Lantern.NetworkRequest, timing: LH.Crdp.Network.ResourceTiming, connectionReused?: boolean}} RequestInfo */ + /** @typedef {{request: Lantern.NetworkRequest, timing: LH.Crdp.Network.ResourceTiming, connectionReused?: boolean}} RequestInfo */ /** - * @param {Lantern.NetworkRequest[]} records + * @param {Lantern.NetworkRequest[]} requests * @param {(e: RequestInfo) => number | number[] | undefined} iteratee * @return {Map} */ - static _estimateValueByOrigin(records, iteratee) { - const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(records); - const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records); + static _estimateValueByOrigin(requests, iteratee) { + const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(requests); + const groupedByOrigin = NetworkAnalyzer.groupByOrigin(requests); const estimates = new Map(); - for (const [origin, originRecords] of groupedByOrigin.entries()) { + for (const [origin, originRequests] of groupedByOrigin.entries()) { /** @type {number[]} */ let originEstimates = []; - for (const record of originRecords) { - const timing = record.timing; + for (const request of originRequests) { + const timing = request.timing; if (!timing) continue; const value = iteratee({ - record, + request, timing, - connectionReused: connectionWasReused.get(record.requestId), + connectionReused: connectionWasReused.get(request.requestId), }); if (typeof value !== 'undefined') { originEstimates = originEstimates.concat(value); @@ -137,11 +137,11 @@ class NetworkAnalyzer { * @return {number[]|number|undefined} */ static _estimateRTTViaConnectionTiming(info) { - const {timing, connectionReused, record} = info; + const {timing, connectionReused, request} = info; if (connectionReused) return; const {connectStart, sslStart, sslEnd, connectEnd} = timing; - if (connectEnd >= 0 && connectStart >= 0 && record.protocol.startsWith('h3')) { + if (connectEnd >= 0 && connectStart >= 0 && request.protocol.startsWith('h3')) { // These values are equal to sslStart and sslEnd for h3. return connectEnd - connectStart; } else if (sslStart >= 0 && sslEnd >= 0 && sslStart !== connectStart) { @@ -161,17 +161,17 @@ class NetworkAnalyzer { * @return {number|undefined} */ static _estimateRTTViaDownloadTiming(info) { - const {timing, connectionReused, record} = info; + const {timing, connectionReused, request} = info; if (connectionReused) return; // Only look at downloads that went past the initial congestion window - if (record.transferSize <= INITIAL_CWD) return; + if (request.transferSize <= INITIAL_CWD) return; if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) return; // Compute the amount of time downloading everything after the first congestion window took - const totalTime = record.networkEndTime - record.networkRequestTime; + const totalTime = request.networkEndTime - request.networkRequestTime; const downloadTimeAfterFirstByte = totalTime - timing.receiveHeadersEnd; - const numberOfRoundTrips = Math.log2(record.transferSize / INITIAL_CWD); + const numberOfRoundTrips = Math.log2(request.transferSize / INITIAL_CWD); // Ignore requests that required a high number of round trips since bandwidth starts to play // a larger role than latency @@ -190,7 +190,7 @@ class NetworkAnalyzer { * @return {number|undefined} */ static _estimateRTTViaSendStartTiming(info) { - const {timing, connectionReused, record} = info; + const {timing, connectionReused, request} = info; if (connectionReused) return; if (!Number.isFinite(timing.sendStart) || timing.sendStart < 0) return; @@ -198,8 +198,8 @@ class NetworkAnalyzer { // Assume everything before sendStart was just DNS + (SSL)? + TCP handshake // 1 RT for DNS, 1 RT (maybe) for SSL, 1 RT for TCP let roundTrips = 1; - if (!record.protocol.startsWith('h3')) roundTrips += 1; // TCP - if (record.parsedURL.scheme === 'https') roundTrips += 1; + if (!request.protocol.startsWith('h3')) roundTrips += 1; // TCP + if (request.parsedURL.scheme === 'https') roundTrips += 1; return timing.sendStart / roundTrips; } @@ -213,12 +213,12 @@ class NetworkAnalyzer { * @return {number|undefined} */ static _estimateRTTViaHeadersEndTiming(info) { - const {timing, connectionReused, record} = info; + const {timing, connectionReused, request} = info; if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) return; - if (!record.resourceType) return; + if (!request.resourceType) return; const serverResponseTimePercentage = - SERVER_RESPONSE_PERCENTAGE_OF_TTFB[record.resourceType] || + SERVER_RESPONSE_PERCENTAGE_OF_TTFB[request.resourceType] || DEFAULT_SERVER_RESPONSE_PERCENTAGE; const estimatedServerResponseTime = timing.receiveHeadersEnd * serverResponseTimePercentage; @@ -230,8 +230,8 @@ class NetworkAnalyzer { // TTFB = DNS + (SSL)? + TCP handshake + 1 RT for request + server response time if (!connectionReused) { roundTrips += 1; // DNS - if (!record.protocol.startsWith('h3')) roundTrips += 1; // TCP - if (record.parsedURL.scheme === 'https') roundTrips += 1; // SSL + if (!request.protocol.startsWith('h3')) roundTrips += 1; // TCP + if (request.parsedURL.scheme === 'https') roundTrips += 1; // SSL } // subtract out our estimated server response time @@ -246,28 +246,28 @@ class NetworkAnalyzer { * @return {Map} */ static _estimateResponseTimeByOrigin(records, rttByOrigin) { - return NetworkAnalyzer._estimateValueByOrigin(records, ({record, timing}) => { - if (record.serverResponseTime !== undefined) return record.serverResponseTime; + return NetworkAnalyzer._estimateValueByOrigin(records, ({request, timing}) => { + if (request.serverResponseTime !== undefined) return request.serverResponseTime; if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) return; if (!Number.isFinite(timing.sendEnd) || timing.sendEnd < 0) return; const ttfb = timing.receiveHeadersEnd - timing.sendEnd; - const origin = record.parsedURL.securityOrigin; + const origin = request.parsedURL.securityOrigin; const rtt = rttByOrigin.get(origin) || rttByOrigin.get(NetworkAnalyzer.SUMMARY) || 0; return Math.max(ttfb - rtt, 0); }); } /** - * @param {Lantern.NetworkRequest[]} records + * @param {Lantern.NetworkRequest[]} requests * @return {boolean} */ - static canTrustConnectionInformation(records) { + static canTrustConnectionInformation(requests) { const connectionIdWasStarted = new Map(); - for (const record of records) { - const started = connectionIdWasStarted.get(record.connectionId) || !record.connectionReused; - connectionIdWasStarted.set(record.connectionId, started); + for (const request of requests) { + const started = connectionIdWasStarted.get(request.connectionId) || !request.connectionReused; + connectionIdWasStarted.set(request.connectionId, started); } // We probably can't trust the network information if all the connection IDs were the same @@ -289,10 +289,10 @@ class NetworkAnalyzer { // Check if we can trust the connection information coming from the protocol if (!forceCoarseEstimates && NetworkAnalyzer.canTrustConnectionInformation(records)) { - return new Map(records.map(record => [record.requestId, !!record.connectionReused])); + return new Map(records.map(request => [request.requestId, !!request.connectionReused])); } - // Otherwise we're on our own, a record may not have needed a fresh connection if... + // Otherwise we're on our own, a request may not have needed a fresh connection if... // - It was not the first request to the domain // - It was H2 // - It was after the first request to the domain ended @@ -300,13 +300,13 @@ class NetworkAnalyzer { const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records); for (const [_, originRecords] of groupedByOrigin.entries()) { const earliestReusePossible = originRecords - .map(record => record.networkEndTime) + .map(request => request.networkEndTime) .reduce((a, b) => Math.min(a, b), Infinity); - for (const record of originRecords) { + for (const request of originRecords) { connectionWasReused.set( - record.requestId, - record.networkRequestTime >= earliestReusePossible || record.protocol === 'h2' + request.requestId, + request.networkRequestTime >= earliestReusePossible || request.protocol === 'h2' ); } @@ -343,7 +343,7 @@ class NetworkAnalyzer { const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records); const estimatesByOrigin = new Map(); - for (const [origin, originRecords] of groupedByOrigin.entries()) { + for (const [origin, originRequests] of groupedByOrigin.entries()) { /** @type {number[]} */ const originEstimates = []; @@ -352,14 +352,14 @@ class NetworkAnalyzer { */ // eslint-disable-next-line no-inner-declarations function collectEstimates(estimator, multiplier = 1) { - for (const record of originRecords) { - const timing = record.timing; + for (const request of originRequests) { + const timing = request.timing; if (!timing) continue; const estimates = estimator({ - record, + request, timing, - connectionReused: connectionWasReused.get(record.requestId), + connectionReused: connectionWasReused.get(request.requestId), }); if (estimates === undefined) continue; @@ -427,9 +427,9 @@ class NetworkAnalyzer { /** - * Computes the average throughput for the given records in bits/second. + * Computes the average throughput for the given requests in bits/second. * Excludes data URI, failed or otherwise incomplete, and cached requests. - * Returns Infinity if there were no analyzable network records. + * Returns Infinity if there were no analyzable network requests. * * @param {Lantern.NetworkRequest[]} records * @return {number} @@ -438,21 +438,21 @@ class NetworkAnalyzer { let totalBytes = 0; // We will measure throughput by summing the total bytes downloaded by the total time spent - // downloading those bytes. We slice up all the network records into start/end boundaries, so + // downloading those bytes. We slice up all the network requests into start/end boundaries, so // it's easier to deal with the gaps in downloading. - const timeBoundaries = records.reduce((boundaries, record) => { - const scheme = record.parsedURL?.scheme; + const timeBoundaries = records.reduce((boundaries, request) => { + const scheme = request.parsedURL?.scheme; // Requests whose bodies didn't come over the network or didn't completely finish will mess // with the computation, just skip over them. - if (scheme === 'data' || record.failed || !record.finished || - record.statusCode > 300 || !record.transferSize) { + if (scheme === 'data' || request.failed || !request.finished || + request.statusCode > 300 || !request.transferSize) { return boundaries; } // If we've made it this far, all the times we need should be valid (i.e. not undefined/-1). - totalBytes += record.transferSize; - boundaries.push({time: record.responseHeadersEndTime / 1000, isStart: true}); - boundaries.push({time: record.networkEndTime / 1000, isStart: false}); + totalBytes += request.transferSize; + boundaries.push({time: request.responseHeadersEndTime / 1000, isStart: true}); + boundaries.push({time: request.networkEndTime / 1000, isStart: false}); return boundaries; }, /** @type {Array<{time: number, isStart: boolean}>} */([])).sort((a, b) => a.time - b.time); diff --git a/core/lib/lantern/simulator/simulator.js b/core/lib/lantern/simulator/simulator.js index 79a3b594a4ff..2e94b374d9ad 100644 --- a/core/lib/lantern/simulator/simulator.js +++ b/core/lib/lantern/simulator/simulator.js @@ -248,11 +248,11 @@ class Simulator { } /** - * @param {Lantern.NetworkRequest} record + * @param {Lantern.NetworkRequest} request * @return {?TcpConnection} */ - _acquireConnection(record) { - return this._connectionPool.acquire(record); + _acquireConnection(request) { + return this._connectionPool.acquire(request); } /** @@ -342,7 +342,7 @@ class Simulator { * @return {number} */ _estimateNetworkTimeRemaining(networkNode) { - const record = networkNode.request; + const request = networkNode.request; const timingData = this._nodeTimings.getNetworkStarted(networkNode); let timeElapsed = 0; @@ -350,23 +350,23 @@ class Simulator { // Rough access time for seeking to location on disk and reading sequentially. // 8ms per seek + 20ms/MB // @see http://norvig.com/21-days.html#answers - const sizeInMb = (record.resourceSize || 0) / 1024 / 1024; + const sizeInMb = (request.resourceSize || 0) / 1024 / 1024; timeElapsed = 8 + 20 * sizeInMb - timingData.timeElapsed; } else if (networkNode.isNonNetworkProtocol) { // Estimates for the overhead of a data URL in Chromium and the decoding time for base64-encoded data. // 2ms per request + 10ms/MB // @see traces on https://dopiaza.org/tools/datauri/examples/index.php - const sizeInMb = (record.resourceSize || 0) / 1024 / 1024; + const sizeInMb = (request.resourceSize || 0) / 1024 / 1024; timeElapsed = 2 + 10 * sizeInMb - timingData.timeElapsed; } else { - const connection = this._connectionPool.acquireActiveConnectionFromRecord(record); - const dnsResolutionTime = this._dns.getTimeUntilResolution(record, { + const connection = this._connectionPool.acquireActiveConnectionFromRequest(request); + const dnsResolutionTime = this._dns.getTimeUntilResolution(request, { requestedAt: timingData.startTime, shouldUpdateCache: true, }); const timeAlreadyElapsed = timingData.timeElapsed; const calculation = connection.simulateDownloadUntil( - record.transferSize - timingData.bytesDownloaded, + request.transferSize - timingData.bytesDownloaded, {timeAlreadyElapsed, dnsResolutionTime, maximumTimeToElapse: Infinity} ); @@ -410,14 +410,14 @@ class Simulator { if (node.type !== BaseNode.TYPES.NETWORK) throw new Error('Unsupported'); if (!('bytesDownloaded' in timingData)) throw new Error('Invalid timing data'); - const record = node.request; - const connection = this._connectionPool.acquireActiveConnectionFromRecord(record); - const dnsResolutionTime = this._dns.getTimeUntilResolution(record, { + const request = node.request; + const connection = this._connectionPool.acquireActiveConnectionFromRequest(request); + const dnsResolutionTime = this._dns.getTimeUntilResolution(request, { requestedAt: timingData.startTime, shouldUpdateCache: true, }); const calculation = connection.simulateDownloadUntil( - record.transferSize - timingData.bytesDownloaded, + request.transferSize - timingData.bytesDownloaded, { dnsResolutionTime, timeAlreadyElapsed: timingData.timeElapsed, @@ -430,7 +430,7 @@ class Simulator { if (isFinished) { connection.setWarmed(true); - this._connectionPool.release(record); + this._connectionPool.release(request); this._markNodeAsComplete(node, totalElapsedTime, calculation.connectionTiming); } else { timingData.timeElapsed += calculation.timeElapsed; @@ -480,7 +480,7 @@ class Simulator { * * Simulator/connection pool are allowed to deviate from what was * observed in the trace/devtoolsLog and start requests as soon as they are queued (i.e. do not - * wait around for a warm connection to be available if the original record was fetched on a warm + * wait around for a warm connection to be available if the original request was fetched on a warm * connection). * * @param {Node} graph @@ -580,7 +580,7 @@ class Simulator { } /** - * We attempt to start nodes by their observed start time using the record priority as a tie breaker. + * We attempt to start nodes by their observed start time using the request priority as a tie breaker. * When simulating, just because a low priority image started 5ms before a high priority image doesn't mean * it would have happened like that when the network was slower. * @param {Node} node diff --git a/core/lib/lantern/types/lantern.d.ts b/core/lib/lantern/types/lantern.d.ts index 875001b7d027..b52cc58c710b 100644 --- a/core/lib/lantern/types/lantern.d.ts +++ b/core/lib/lantern/types/lantern.d.ts @@ -38,12 +38,13 @@ type LightriderStatistics = { export class NetworkRequest { /** - * The canonical network record. - * Users of Lantern must create NetworkRequests matching this interface, - * but can store the source-of-truth for their network model in this `record` - * property. This is then accessible as a read-only property on NetworkNode. + * Implementation-specifc canoncial data structure that this Lantern NetworkRequest + * was derived from. + * Users of Lantern create a NetworkRequest matching this interface, + * but can store the source-of-truth for their network model in this property. + * This is then accessible as a read-only property on NetworkNode. */ - record?: T; + rawRequest?: T; requestId: string; connectionId: number; diff --git a/core/lib/network-request.js b/core/lib/network-request.js index c9bf74285804..77bf329a04fe 100644 --- a/core/lib/network-request.js +++ b/core/lib/network-request.js @@ -604,10 +604,10 @@ class NetworkRequest { record.fromWorker = record.sessionTargetType === 'worker'; return { + rawRequest: record, ...record, timing, serverResponseTime, - record, }; } diff --git a/core/test/lib/lantern/page-dependency-graph-test.js b/core/test/lib/lantern/page-dependency-graph-test.js index f89347c03c19..9be2461c49c0 100644 --- a/core/test/lib/lantern/page-dependency-graph-test.js +++ b/core/test/lib/lantern/page-dependency-graph-test.js @@ -65,23 +65,23 @@ describe('PageDependencyGraph computed artifact:', () => { const request1 = createRequest(1, 'https://example.com/'); const request2 = createRequest(2, 'https://example.com/page'); const request3 = createRequest(3, 'https://example.com/page'); - const networkRecords = [request1, request2, request3]; + const networkRequests = [request1, request2, request3]; it('should create network nodes', () => { - const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRecords); - for (let i = 0; i < networkRecords.length; i++) { + const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRequests); + for (let i = 0; i < networkRequests.length; i++) { const node = networkNodeOutput.nodes[i]; assert.ok(node, `did not create node at index ${i}`); assert.equal(node.id, i + 1); assert.equal(node.type, 'network'); - assert.equal(node.request, networkRecords[i]); + assert.equal(node.request, networkRequests[i]); } }); it('should ignore worker requests', () => { const workerRequest = createRequest(4, 'https://example.com/worker.js', 0, null, 'Script', true); const recordsWithWorker = [ - ...networkRecords, + ...networkRequests, workerRequest, ]; @@ -92,15 +92,15 @@ describe('PageDependencyGraph computed artifact:', () => { }); it('should index nodes by ID', () => { - const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRecords); + const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRequests); const indexedById = networkNodeOutput.idToNodeMap; - for (const record of networkRecords) { - assert.equal(indexedById.get(record.requestId).request, record); + for (const request of networkRequests) { + assert.equal(indexedById.get(request.requestId).request, request); } }); it('should index nodes by URL', () => { - const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRecords); + const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRequests); const nodes = networkNodeOutput.nodes; const indexedByUrl = networkNodeOutput.urlToNodeMap; assert.deepEqual(indexedByUrl.get('https://example.com/'), [nodes[0]]); @@ -198,11 +198,11 @@ describe('PageDependencyGraph computed artifact:', () => { const request2 = createRequest(2, 'https://example.com/page', 5); const request3 = createRequest(3, 'https://example.com/page2', 5); const request4 = createRequest(4, 'https://example.com/page3', 10, {url: 'https://example.com/page'}); - const networkRecords = [request1, request2, request3, request4]; + const networkRequests = [request1, request2, request3, request4]; addTaskEvents(0, 0, []); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -219,7 +219,7 @@ describe('PageDependencyGraph computed artifact:', () => { const request2 = createRequest(2, 'https://example.com/page', 50); const request3 = createRequest(3, 'https://example.com/page2', 50); const request4 = createRequest(4, 'https://example.com/page3', 300, null, NetworkRequestTypes.XHR); - const networkRecords = [request1, request2, request3, request4]; + const networkRequests = [request1, request2, request3, request4]; addTaskEvents(200, 200, [ {name: 'EvaluateScript', data: {url: 'https://example.com/page'}}, @@ -231,7 +231,7 @@ describe('PageDependencyGraph computed artifact:', () => { {name: 'XHRReadyStateChange', data: {readyState: 4, url: 'https://example.com/page3'}}, ]); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -253,11 +253,11 @@ describe('PageDependencyGraph computed artifact:', () => { const request2 = createRequest(2, 'https://example.com/page', 5); const request3 = createRequest(3, 'https://example.com/page', 5); // duplicate URL const request4 = createRequest(4, 'https://example.com/page3', 10, {url: 'https://example.com/page'}); - const networkRecords = [request1, request2, request3, request4]; + const networkRequests = [request1, request2, request3, request4]; addTaskEvents(0, 0, []); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -275,7 +275,7 @@ describe('PageDependencyGraph computed artifact:', () => { const request3 = createRequest(3, 'https://example.com/page2', 210); const request4 = createRequest(4, 'https://example.com/page3', 590); const request5 = createRequest(5, 'https://example.com/page4', 595, null, NetworkRequestTypes.XHR); - const networkRecords = [request1, request2, request3, request4, request5]; + const networkRequests = [request1, request2, request3, request4, request5]; addTaskEvents(200, 200, [ // CPU 1.2 should depend on Network 1 @@ -296,7 +296,7 @@ describe('PageDependencyGraph computed artifact:', () => { {name: 'ResourceSendRequest', data: {requestId: 5}}, ]); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -314,7 +314,7 @@ describe('PageDependencyGraph computed artifact:', () => { it('should not install timer dependency on itself', () => { const request1 = createRequest(1, 'https://example.com/', 0); - const networkRecords = [request1]; + const networkRequests = [request1]; addTaskEvents(200, 200, [ // CPU 1.2 should depend on Network 1 @@ -324,7 +324,7 @@ describe('PageDependencyGraph computed artifact:', () => { {name: 'TimerFire', data: {timerId: 'timer1'}}, ]); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -341,7 +341,7 @@ describe('PageDependencyGraph computed artifact:', () => { const request2 = createRequest(2, 'https://example.com/page', 200, null, NetworkRequestTypes.XHR); const request3 = createRequest(3, 'https://example.com/page2', 300, null, NetworkRequestTypes.Script); const request4 = createRequest(4, 'https://example.com/page3', 400, null, NetworkRequestTypes.XHR); - const networkRecords = [request0, request1, request2, request3, request4]; + const networkRequests = [request0, request1, request2, request3, request4]; URL = {requestedUrl: 'https://example.com/page0', mainDocumentUrl: 'https://example.com/page0'}; // Long task, should be kept in the output. @@ -358,7 +358,7 @@ describe('PageDependencyGraph computed artifact:', () => { {name: 'XHRReadyStateChange', data: {readyState: 4, url: 'https://example.com/page3'}}, ]); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -390,7 +390,7 @@ describe('PageDependencyGraph computed artifact:', () => { }; const request3 = createRequest(3, 'https://example.com/page2', 300, null, NetworkRequestTypes.XHR); const request4 = createRequest(4, 'https://example.com/page3', 400, null, NetworkRequestTypes.XHR); - const networkRecords = [request0, request1, request2, request3, request4]; + const networkRequests = [request0, request1, request2, request3, request4]; URL = {requestedUrl: 'https://example.com/page0', mainDocumentUrl: 'https://example.com/page0'}; // Short task, evaluates script (2) and sends two XHRs. @@ -404,7 +404,7 @@ describe('PageDependencyGraph computed artifact:', () => { {name: 'XHRReadyStateChange', data: {readyState: 4, url: 'https://example.com/page3'}}, ]); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -424,7 +424,7 @@ describe('PageDependencyGraph computed artifact:', () => { it('should not prune short, first tasks of critical events', () => { const request0 = createRequest(0, 'https://example.com/page0', 0); - const networkRecords = [request0]; + const networkRequests = [request0]; URL = {requestedUrl: 'https://example.com/page0', mainDocumentUrl: 'https://example.com/page0'}; const makeShortEvent = firstEventName => { @@ -444,7 +444,7 @@ describe('PageDependencyGraph computed artifact:', () => { makeShortEvent(eventName); } - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const cpuNodes = []; graph.traverse(node => node.type === 'cpu' && cpuNodes.push(node)); @@ -476,12 +476,12 @@ describe('PageDependencyGraph computed artifact:', () => { // Add in another unrelated + early request to make sure we pick the correct chain const request3 = createRequest(3, 'https://example.com/page2', 0, null, NetworkRequestTypes.Other); request2.redirects = [request1]; - const networkRecords = [request1, request2, request3]; + const networkRequests = [request1, request2, request3]; URL = {requestedUrl: 'https://example.com/', mainDocumentUrl: 'https://example.com/page'}; addTaskEvents(0, 0, []); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -505,11 +505,11 @@ describe('PageDependencyGraph computed artifact:', () => { // Also set the initiatorRequest that Lighthouse's network-recorder.js creates. // This should be ignored and only used as a fallback. request4.initiatorRequest = request1; - const networkRecords = [request1, request2, request3, request4]; + const networkRequests = [request1, request2, request3, request4]; addTaskEvents(0, 0, []); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -530,11 +530,11 @@ describe('PageDependencyGraph computed artifact:', () => { type: 'script', stack: {callFrames: [{url: 'https://example.com/page'}], parent: {parent: {callFrames: [{url: 'https://example.com/page2'}]}}}, }; - const networkRecords = [request1, request2, request3, request4]; + const networkRequests = [request1, request2, request3, request4]; addTaskEvents(0, 0, []); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -558,12 +558,12 @@ describe('PageDependencyGraph computed artifact:', () => { }; // Set the initiatorRequest that it should fallback to. request3.initiatorRequest = request2Fetch; - const networkRecords = [request1, request2Prefetch, request2Fetch, request3]; + const networkRequests = [request1, request2Prefetch, request2Fetch, request3]; URL = {requestedUrl: 'https://a.com/1', mainDocumentUrl: 'https://a.com/1'}; addTaskEvents(0, 0, []); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); @@ -582,12 +582,12 @@ describe('PageDependencyGraph computed artifact:', () => { // jsRequest2 initiated by jsRequest1 const jsRequest1 = createRequest(2, 'https://a.com/js1', 1, {url: 'https://a.com/js2'}); const jsRequest2 = createRequest(3, 'https://a.com/js2', 1, {url: 'https://a.com/js1'}); - const networkRecords = [rootRequest, jsRequest1, jsRequest2]; + const networkRequests = [rootRequest, jsRequest1, jsRequest2]; URL = {requestedUrl: 'https://a.com', mainDocumentUrl: 'https://a.com'}; addTaskEvents(0, 0, []); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); nodes.sort((a, b) => a.id - b.id); @@ -612,12 +612,12 @@ describe('PageDependencyGraph computed artifact:', () => { const jsRequest2 = createRequest(3, 'https://a.com/js2', 1); jsRequest1.initiatorRequest = jsRequest2; jsRequest2.initiatorRequest = jsRequest1; - const networkRecords = [rootRequest, jsRequest1, jsRequest2]; + const networkRequests = [rootRequest, jsRequest1, jsRequest2]; URL = {requestedUrl: 'https://a.com', mainDocumentUrl: 'https://a.com'}; addTaskEvents(0, 0, []); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); nodes.sort((a, b) => a.id - b.id); @@ -632,7 +632,7 @@ describe('PageDependencyGraph computed artifact:', () => { it('should find root if it is not the first node', () => { const request1 = createRequest(1, 'https://example.com/', 0, null, NetworkRequestTypes.Other); const request2 = createRequest(2, 'https://example.com/page', 5, null, NetworkRequestTypes.Document); - const networkRecords = [request1, request2]; + const networkRequests = [request1, request2]; URL = {requestedUrl: 'https://example.com/page', mainDocumentUrl: 'https://example.com/page'}; // Evaluated before root request. @@ -640,7 +640,7 @@ describe('PageDependencyGraph computed artifact:', () => { {name: 'EvaluateScript'}, ]); - const graph = PageDependencyGraph.createGraph(traceEvents, networkRecords, URL); + const graph = PageDependencyGraph.createGraph(traceEvents, networkRequests, URL); const nodes = []; graph.traverse(node => nodes.push(node)); diff --git a/core/test/lib/lantern/simulator/connection-pool-test.js b/core/test/lib/lantern/simulator/connection-pool-test.js index 27f4de888542..84d2e2136dc3 100644 --- a/core/test/lib/lantern/simulator/connection-pool-test.js +++ b/core/test/lib/lantern/simulator/connection-pool-test.js @@ -14,7 +14,7 @@ describe('DependencyGraph/Simulator/ConnectionPool', () => { const throughput = 10000 * 1024; let requestId; - function record(data = {}) { + function request(data = {}) { const url = data.url || 'http://example.com'; const origin = new URL(url).origin; const scheme = url.split(':')[0]; @@ -45,7 +45,7 @@ describe('DependencyGraph/Simulator/ConnectionPool', () => { describe('#constructor', () => { it('should create the pool', () => { - const pool = new ConnectionPool([record()], simulationOptions({rtt, throughput})); + const pool = new ConnectionPool([request()], simulationOptions({rtt, throughput})); // Make sure 6 connections are created for each origin assert.equal(pool._connectionsByOrigin.get('http://example.com').length, 6); // Make sure it populates connectionWasReused @@ -58,14 +58,14 @@ describe('DependencyGraph/Simulator/ConnectionPool', () => { }); it('should set TLS properly', () => { - const recordA = record({url: 'https://example.com'}); + const recordA = request({url: 'https://example.com'}); const pool = new ConnectionPool([recordA], simulationOptions({rtt, throughput})); const connection = pool._connectionsByOrigin.get('https://example.com')[0]; assert.ok(connection._ssl, 'should have set connection TLS'); }); it('should set H2 properly', () => { - const recordA = record({protocol: 'h2'}); + const recordA = request({protocol: 'h2'}); const pool = new ConnectionPool([recordA], simulationOptions({rtt, throughput})); const connection = pool._connectionsByOrigin.get('http://example.com')[0]; assert.ok(connection.isH2(), 'should have set HTTP/2'); @@ -74,7 +74,7 @@ describe('DependencyGraph/Simulator/ConnectionPool', () => { it('should set origin-specific RTT properly', () => { const additionalRttByOrigin = new Map([['http://example.com', 63]]); - const pool = new ConnectionPool([record()], + const pool = new ConnectionPool([request()], simulationOptions({rtt, throughput, additionalRttByOrigin})); const connection = pool._connectionsByOrigin.get('http://example.com')[0]; assert.ok(connection._rtt, rtt + 63); @@ -82,7 +82,7 @@ describe('DependencyGraph/Simulator/ConnectionPool', () => { it('should set origin-specific server latency properly', () => { const serverResponseTimeByOrigin = new Map([['http://example.com', 63]]); - const pool = new ConnectionPool([record()], + const pool = new ConnectionPool([request()], simulationOptions({rtt, throughput, serverResponseTimeByOrigin})); const connection = pool._connectionsByOrigin.get('http://example.com')[0]; assert.ok(connection._serverLatency, 63); @@ -90,40 +90,40 @@ describe('DependencyGraph/Simulator/ConnectionPool', () => { }); describe('.acquire', () => { - it('should remember the connection associated with each record', () => { - const recordA = record(); - const recordB = record(); - const pool = new ConnectionPool([recordA, recordB], simulationOptions({rtt, throughput})); + it('should remember the connection associated with each request', () => { + const requestA = request(); + const requestB = request(); + const pool = new ConnectionPool([requestA, requestB], simulationOptions({rtt, throughput})); - const connectionForA = pool.acquire(recordA); - const connectionForB = pool.acquire(recordB); + const connectionForA = pool.acquire(requestA); + const connectionForB = pool.acquire(requestB); for (let i = 0; i < 10; i++) { - assert.equal(pool.acquireActiveConnectionFromRecord(recordA), connectionForA); - assert.equal(pool.acquireActiveConnectionFromRecord(recordB), connectionForB); + assert.equal(pool.acquireActiveConnectionFromRequest(requestA), connectionForA); + assert.equal(pool.acquireActiveConnectionFromRequest(requestB), connectionForB); } assert.deepStrictEqual(pool.connectionsInUse(), [connectionForA, connectionForB]); }); it('should allocate at least 6 connections', () => { - const pool = new ConnectionPool([record()], simulationOptions({rtt, throughput})); + const pool = new ConnectionPool([request()], simulationOptions({rtt, throughput})); for (let i = 0; i < 6; i++) { - assert.ok(pool.acquire(record()), `did not find connection for ${i}th record`); + assert.ok(pool.acquire(request()), `did not find connection for ${i}th request`); } }); it('should allocate all connections', () => { - const records = new Array(7).fill(undefined, 0, 7).map(() => record()); + const records = new Array(7).fill(undefined, 0, 7).map(() => request()); const pool = new ConnectionPool(records, simulationOptions({rtt, throughput})); - const connections = records.map(record => pool.acquire(record)); - assert.ok(connections[0], 'did not find connection for 1st record'); - assert.ok(connections[5], 'did not find connection for 6th record'); - assert.ok(connections[6], 'did not find connection for 7th record'); + const connections = records.map(request => pool.acquire(request)); + assert.ok(connections[0], 'did not find connection for 1st request'); + assert.ok(connections[5], 'did not find connection for 6th request'); + assert.ok(connections[6], 'did not find connection for 7th request'); }); it('should be oblivious to connection reuse', () => { - const coldRecord = record(); - const warmRecord = record(); + const coldRecord = request(); + const warmRecord = request(); const pool = new ConnectionPool([coldRecord, warmRecord], simulationOptions({rtt, throughput})); pool._connectionReusedByRequestId.set(warmRecord.requestId, true); @@ -137,14 +137,14 @@ describe('DependencyGraph/Simulator/ConnectionPool', () => { } assert.ok(pool.acquire(coldRecord), 'should have acquired connection'); - assert.ok(pool.acquireActiveConnectionFromRecord(warmRecord), + assert.ok(pool.acquireActiveConnectionFromRequest(warmRecord), 'should have acquired connection'); }); it('should acquire in order of warmness', () => { - const recordA = record(); - const recordB = record(); - const recordC = record(); + const recordA = request(); + const recordB = request(); + const recordC = request(); const pool = new ConnectionPool([recordA, recordB, recordC], simulationOptions({rtt, throughput})); pool._connectionReusedByRequestId.set(recordA.requestId, true); @@ -167,27 +167,27 @@ describe('DependencyGraph/Simulator/ConnectionPool', () => { }); describe('.release', () => { - it('noop for record without connection', () => { - const recordA = record(); - const pool = new ConnectionPool([recordA], simulationOptions({rtt, throughput})); - assert.equal(pool.release(recordA), undefined); + it('noop for request without connection', () => { + const requestA = request(); + const pool = new ConnectionPool([requestA], simulationOptions({rtt, throughput})); + assert.equal(pool.release(requestA), undefined); }); it('frees the connection for reissue', () => { - const records = new Array(6).fill(undefined, 0, 7).map(() => record()); - const pool = new ConnectionPool(records, simulationOptions({rtt, throughput})); - records.push(record()); + const requests = new Array(6).fill(undefined, 0, 7).map(() => request()); + const pool = new ConnectionPool(requests, simulationOptions({rtt, throughput})); + requests.push(request()); - records.forEach(record => pool.acquire(record)); + requests.forEach(request => pool.acquire(request)); assert.equal(pool.connectionsInUse().length, 6); - assert.ok(!pool.acquire(records[6]), 'had connection that is in use'); + assert.ok(!pool.acquire(requests[6]), 'had connection that is in use'); - pool.release(records[0]); + pool.release(requests[0]); assert.equal(pool.connectionsInUse().length, 5); - assert.ok(pool.acquire(records[6]), 'could not reissue released connection'); - assert.ok(!pool.acquire(records[0]), 'had connection that is in use'); + assert.ok(pool.acquire(requests[6]), 'could not reissue released connection'); + assert.ok(!pool.acquire(requests[0]), 'had connection that is in use'); }); }); }); diff --git a/core/test/lib/lantern/simulator/dns-cache-test.js b/core/test/lib/lantern/simulator/dns-cache-test.js index cf47322ef4cd..497d9a166621 100644 --- a/core/test/lib/lantern/simulator/dns-cache-test.js +++ b/core/test/lib/lantern/simulator/dns-cache-test.js @@ -61,7 +61,7 @@ describe('DependencyGraph/Simulator/DNSCache', () => { }); describe('.setResolvedAt', () => { - it('should set the DNS resolution time for a record', () => { + it('should set the DNS resolution time for a request', () => { dns.setResolvedAt(request.parsedURL.host, 123); const resolutionTime = dns.getTimeUntilResolution(request); expect(resolutionTime).toEqual(123); diff --git a/core/test/lib/lantern/simulator/network-analyzer-test.js b/core/test/lib/lantern/simulator/network-analyzer-test.js index 8ca0caf72f60..ea360a5edd03 100644 --- a/core/test/lib/lantern/simulator/network-analyzer-test.js +++ b/core/test/lib/lantern/simulator/network-analyzer-test.js @@ -26,7 +26,7 @@ describe('DependencyGraph/Simulator/NetworkAnalyzer', () => { const url = opts.url || 'https://example.com'; if (opts.networkRequestTime) opts.networkRequestTime *= 1000; if (opts.networkEndTime) opts.networkEndTime *= 1000; - const record = Object.assign( + const request = Object.assign( { url, requestId: recordId++, @@ -41,7 +41,7 @@ describe('DependencyGraph/Simulator/NetworkAnalyzer', () => { }, opts ); - return NetworkRequest.asLanternNetworkRequest(record); + return NetworkRequest.asLanternNetworkRequest(request); } beforeEach(() => { @@ -144,56 +144,56 @@ describe('DependencyGraph/Simulator/NetworkAnalyzer', () => { describe('#estimateRTTByOrigin', () => { it('should infer from tcp timing when available', () => { const timing = {connectStart: 0, connectEnd: 99}; - const record = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); - const result = NetworkAnalyzer.estimateRTTByOrigin([record]); + const request = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); + const result = NetworkAnalyzer.estimateRTTByOrigin([request]); const expected = {min: 99, max: 99, avg: 99, median: 99}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); it('should infer only one estimate if tcp and ssl start times are equal', () => { const timing = {connectStart: 0, connectEnd: 99, sslStart: 0, sslEnd: 99}; - const record = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); - const result = NetworkAnalyzer.estimateRTTByOrigin([record]); + const request = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); + const result = NetworkAnalyzer.estimateRTTByOrigin([request]); const expected = {min: 99, max: 99, avg: 99, median: 99}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); it('should infer from tcp and ssl timing when available', () => { const timing = {connectStart: 0, connectEnd: 99, sslStart: 50, sslEnd: 99}; - const record = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); - const result = NetworkAnalyzer.estimateRTTByOrigin([record]); + const request = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); + const result = NetworkAnalyzer.estimateRTTByOrigin([request]); const expected = {min: 49, max: 50, avg: 49.5, median: 49.5}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); it('should infer from connection timing when available for h3 (one estimate)', () => { const timing = {connectStart: 0, connectEnd: 99, sslStart: 1, sslEnd: 99}; - const record = + const request = createRecord({networkRequestTime: 0, networkEndTime: 1, timing, protocol: 'h3'}); - const result = NetworkAnalyzer.estimateRTTByOrigin([record]); + const result = NetworkAnalyzer.estimateRTTByOrigin([request]); const expected = {min: 99, max: 99, avg: 99, median: 99}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); it('should infer from sendStart when available', () => { const timing = {sendStart: 150}; - // this record took 150ms before Chrome could send the request + // this request took 150ms before Chrome could send the request // i.e. DNS (maybe) + queuing (maybe) + TCP handshake took ~100ms // 150ms / 3 round trips ~= 50ms RTT - const record = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); - const result = NetworkAnalyzer.estimateRTTByOrigin([record], {coarseEstimateMultiplier: 1}); + const request = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); + const result = NetworkAnalyzer.estimateRTTByOrigin([request], {coarseEstimateMultiplier: 1}); const expected = {min: 50, max: 50, avg: 50, median: 50}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); it('should infer from download timing when available', () => { const timing = {receiveHeadersEnd: 100}; - // this record took 1000ms after the first byte was received to download the payload + // this request took 1000ms after the first byte was received to download the payload // i.e. it took at least one full additional roundtrip after first byte to download the rest // 1000ms / 1 round trip ~= 1000ms RTT - const record = createRecord({networkRequestTime: 0, networkEndTime: 1.1, + const request = createRecord({networkRequestTime: 0, networkEndTime: 1.1, transferSize: 28 * 1024, timing}); - const result = NetworkAnalyzer.estimateRTTByOrigin([record], { + const result = NetworkAnalyzer.estimateRTTByOrigin([request], { coarseEstimateMultiplier: 1, useHeadersEndEstimates: false, }); @@ -203,13 +203,13 @@ describe('DependencyGraph/Simulator/NetworkAnalyzer', () => { it('should infer from TTFB when available', () => { const timing = {receiveHeadersEnd: 1000}; - const record = createRecord({networkRequestTime: 0, networkEndTime: 1, timing, + const request = createRecord({networkRequestTime: 0, networkEndTime: 1, timing, resourceType: 'Other'}); - const result = NetworkAnalyzer.estimateRTTByOrigin([record], { + const result = NetworkAnalyzer.estimateRTTByOrigin([request], { coarseEstimateMultiplier: 1, }); - // this record's TTFB was 1000ms, it used SSL and was a fresh connection requiring a handshake + // this request's TTFB was 1000ms, it used SSL and was a fresh connection requiring a handshake // which needs ~4 RTs. We don't know its resource type so it'll be assumed that 40% of it was // server response time. // 600 ms / 4 = 150ms @@ -268,16 +268,16 @@ describe('DependencyGraph/Simulator/NetworkAnalyzer', () => { it('should use lrStatistics when needed', () => { global.isLightrider = true; - const record = createRecord({timing: {}, lrStatistics: {TCPMs: 100}}); - const result = NetworkAnalyzer.estimateRTTByOrigin([record]); + const request = createRecord({timing: {}, lrStatistics: {TCPMs: 100}}); + const result = NetworkAnalyzer.estimateRTTByOrigin([request]); const expected = {min: 50, max: 50, avg: 50, median: 50}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); it('should use lrStatistics when needed (h3)', () => { global.isLightrider = true; - const record = createRecord({protocol: 'h3', timing: {}, lrStatistics: {TCPMs: 100}}); - const result = NetworkAnalyzer.estimateRTTByOrigin([record]); + const request = createRecord({protocol: 'h3', timing: {}, lrStatistics: {TCPMs: 100}}); + const result = NetworkAnalyzer.estimateRTTByOrigin([request]); const expected = {min: 100, max: 100, avg: 100, median: 100}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); @@ -286,26 +286,26 @@ describe('DependencyGraph/Simulator/NetworkAnalyzer', () => { describe('#estimateServerResponseTimeByOrigin', () => { it('should estimate server response time using ttfb times', () => { const timing = {sendEnd: 100, receiveHeadersEnd: 200}; - const record = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); + const request = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); const rttByOrigin = new Map([[NetworkAnalyzer.SUMMARY, 0]]); - const result = NetworkAnalyzer.estimateServerResponseTimeByOrigin([record], {rttByOrigin}); + const result = NetworkAnalyzer.estimateServerResponseTimeByOrigin([request], {rttByOrigin}); const expected = {min: 100, max: 100, avg: 100, median: 100}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); it('should subtract out rtt', () => { const timing = {sendEnd: 100, receiveHeadersEnd: 200}; - const record = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); + const request = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); const rttByOrigin = new Map([[NetworkAnalyzer.SUMMARY, 50]]); - const result = NetworkAnalyzer.estimateServerResponseTimeByOrigin([record], {rttByOrigin}); + const result = NetworkAnalyzer.estimateServerResponseTimeByOrigin([request], {rttByOrigin}); const expected = {min: 50, max: 50, avg: 50, median: 50}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); it('should compute rtts when not provided', () => { const timing = {connectStart: 5, connectEnd: 55, sendEnd: 100, receiveHeadersEnd: 200}; - const record = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); - const result = NetworkAnalyzer.estimateServerResponseTimeByOrigin([record]); + const request = createRecord({networkRequestTime: 0, networkEndTime: 1, timing}); + const result = NetworkAnalyzer.estimateServerResponseTimeByOrigin([request]); const expected = {min: 50, max: 50, avg: 50, median: 50}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); @@ -335,8 +335,8 @@ describe('DependencyGraph/Simulator/NetworkAnalyzer', () => { it('should use lrStatistics when needed', () => { global.isLightrider = true; - const record = createRecord({timing: {}, lrStatistics: {TCPMs: 1, requestMs: 100}}); - const result = NetworkAnalyzer.estimateServerResponseTimeByOrigin([record]); + const request = createRecord({timing: {}, lrStatistics: {TCPMs: 1, requestMs: 100}}); + const result = NetworkAnalyzer.estimateServerResponseTimeByOrigin([request]); const expected = {min: 100, max: 100, avg: 100, median: 100}; assert.deepStrictEqual(result.get('https://example.com'), expected); }); diff --git a/core/test/lib/lantern/simulator/simulator-test.js b/core/test/lib/lantern/simulator/simulator-test.js index 650a160c5888..dcb9474d611a 100644 --- a/core/test/lib/lantern/simulator/simulator-test.js +++ b/core/test/lib/lantern/simulator/simulator-test.js @@ -28,7 +28,7 @@ function request(opts) { delete opts.startTime; delete opts.endTime; - const record = Object.assign({ + const request = Object.assign({ requestId: opts.requestId || nextRequestId++, url, transferSize: opts.transferSize || 1000, @@ -38,7 +38,7 @@ function request(opts) { rendererStartTime, networkEndTime, }, opts); - return NetworkRequest.asLanternNetworkRequest(record); + return NetworkRequest.asLanternNetworkRequest(request); } function cpuTask({tid, ts, duration}) { @@ -267,8 +267,8 @@ describe('DependencyGraph/Simulator', () => { ]; for (const imageNode of imageNodes) { - imageNode.record.connectionReused = true; - imageNode.record.connectionId = 1; + imageNode.request.connectionReused = true; + imageNode.request.connectionId = 1; rootNode.addDependent(imageNode); } @@ -297,8 +297,8 @@ describe('DependencyGraph/Simulator', () => { ]; for (const imageNode of imageNodes) { - imageNode.record.connectionReused = true; - imageNode.record.connectionId = 1; + imageNode.request.connectionReused = true; + imageNode.request.connectionId = 1; rootNode.addDependent(imageNode); }