-
Notifications
You must be signed in to change notification settings - Fork 9.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core(lantern): move LanternMetric in lib/lantern (#15857)
- Loading branch information
1 parent
7d80178
commit e72a9c9
Showing
7 changed files
with
159 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import {BaseNode} from '../../lib/lantern/base-node.js'; | ||
import {NetworkRequest} from '../../lib/network-request.js'; | ||
|
||
/** @typedef {import('./base-node.js').Node} Node */ | ||
/** @typedef {import('./network-node.js').NetworkNode} NetworkNode */ | ||
/** @typedef {import('./simulator/simulator.js').Simulator} Simulator */ | ||
/** @typedef {import('../../../types/internal/lantern.js').Lantern.Simulation.MetricComputationDataInput} MetricComputationDataInput */ | ||
|
||
/** | ||
* @typedef Extras | ||
* @property {boolean} optimistic | ||
* @property {LH.Artifacts.LanternMetric=} fcpResult | ||
* @property {LH.Artifacts.LanternMetric=} fmpResult | ||
* @property {LH.Artifacts.LanternMetric=} interactiveResult | ||
* @property {{speedIndex: number}=} speedline | ||
*/ | ||
|
||
class Metric { | ||
/** | ||
* @param {Node} dependencyGraph | ||
* @param {function(NetworkNode):boolean=} treatNodeAsRenderBlocking | ||
* @return {Set<string>} | ||
*/ | ||
static getScriptUrls(dependencyGraph, treatNodeAsRenderBlocking) { | ||
/** @type {Set<string>} */ | ||
const scriptUrls = new Set(); | ||
|
||
dependencyGraph.traverse(node => { | ||
if (node.type !== BaseNode.TYPES.NETWORK) return; | ||
if (node.record.resourceType !== NetworkRequest.TYPES.Script) return; | ||
if (treatNodeAsRenderBlocking?.(node)) { | ||
scriptUrls.add(node.record.url); | ||
} | ||
}); | ||
|
||
return scriptUrls; | ||
} | ||
|
||
/** | ||
* @return {LH.Gatherer.Simulation.MetricCoefficients} | ||
*/ | ||
static get COEFFICIENTS() { | ||
throw new Error('COEFFICIENTS unimplemented!'); | ||
} | ||
|
||
/** | ||
* Returns the coefficients, scaled by the throttling settings if needed by the metric. | ||
* Some lantern metrics (speed-index) use components in their estimate that are not | ||
* from the simulator. In this case, we need to adjust the coefficients as the target throttling | ||
* settings change. | ||
* | ||
* @param {number} rttMs | ||
* @return {LH.Gatherer.Simulation.MetricCoefficients} | ||
*/ | ||
static getScaledCoefficients(rttMs) { // eslint-disable-line no-unused-vars | ||
return this.COEFFICIENTS; | ||
} | ||
|
||
/** | ||
* @param {Node} dependencyGraph | ||
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation | ||
* @return {Node} | ||
*/ | ||
static getOptimisticGraph(dependencyGraph, processedNavigation) { // eslint-disable-line no-unused-vars | ||
throw new Error('Optimistic graph unimplemented!'); | ||
} | ||
|
||
/** | ||
* @param {Node} dependencyGraph | ||
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation | ||
* @return {Node} | ||
*/ | ||
static getPessimisticGraph(dependencyGraph, processedNavigation) { // eslint-disable-line no-unused-vars | ||
throw new Error('Pessmistic graph unimplemented!'); | ||
} | ||
|
||
/** | ||
* @param {LH.Gatherer.Simulation.Result} simulationResult | ||
* @param {Extras} extras | ||
* @return {LH.Gatherer.Simulation.Result} | ||
*/ | ||
static getEstimateFromSimulation(simulationResult, extras) { // eslint-disable-line no-unused-vars | ||
return simulationResult; | ||
} | ||
|
||
/** | ||
* @param {MetricComputationDataInput} data | ||
* @param {Omit<Extras, 'optimistic'>=} extras | ||
* @return {Promise<LH.Artifacts.LanternMetric>} | ||
*/ | ||
static async compute(data, extras) { | ||
const {simulator, graph, processedNavigation} = data; | ||
|
||
const metricName = this.name.replace('Lantern', ''); | ||
const optimisticGraph = this.getOptimisticGraph(graph, processedNavigation); | ||
const pessimisticGraph = this.getPessimisticGraph(graph, processedNavigation); | ||
|
||
/** @type {{flexibleOrdering?: boolean, label?: string}} */ | ||
let simulateOptions = {label: `optimistic${metricName}`}; | ||
const optimisticSimulation = simulator.simulate(optimisticGraph, simulateOptions); | ||
|
||
simulateOptions = {label: `optimisticFlex${metricName}`, flexibleOrdering: true}; | ||
const optimisticFlexSimulation = simulator.simulate(optimisticGraph, simulateOptions); | ||
|
||
simulateOptions = {label: `pessimistic${metricName}`}; | ||
const pessimisticSimulation = simulator.simulate(pessimisticGraph, simulateOptions); | ||
|
||
const optimisticEstimate = this.getEstimateFromSimulation( | ||
optimisticSimulation.timeInMs < optimisticFlexSimulation.timeInMs ? | ||
optimisticSimulation : optimisticFlexSimulation, {...extras, optimistic: true} | ||
); | ||
|
||
const pessimisticEstimate = this.getEstimateFromSimulation( | ||
pessimisticSimulation, | ||
{...extras, optimistic: false} | ||
); | ||
|
||
const coefficients = this.getScaledCoefficients(simulator.rtt); | ||
// Estimates under 1s don't really follow the normal curve fit, minimize the impact of the intercept | ||
const interceptMultiplier = coefficients.intercept > 0 ? | ||
Math.min(1, optimisticEstimate.timeInMs / 1000) : 1; | ||
const timing = | ||
coefficients.intercept * interceptMultiplier + | ||
coefficients.optimistic * optimisticEstimate.timeInMs + | ||
coefficients.pessimistic * pessimisticEstimate.timeInMs; | ||
|
||
return { | ||
timing, | ||
optimisticEstimate, | ||
pessimisticEstimate, | ||
optimisticGraph, | ||
pessimisticGraph, | ||
}; | ||
} | ||
} | ||
|
||
export {Metric}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters