From f76e7999e02deda36ad546cec46da53fc0b32534 Mon Sep 17 00:00:00 2001 From: robmc Date: Wed, 29 Mar 2023 21:20:37 -0700 Subject: [PATCH] Update `ByteEfficiencyAudits` to use log-normal distribution scoring (#11883) --- .../byte-efficiency/byte-efficiency-audit.js | 33 ++++++++----------- .../byte-efficiency-audit-test.js | 15 +++++---- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/core/audits/byte-efficiency/byte-efficiency-audit.js b/core/audits/byte-efficiency/byte-efficiency-audit.js index edf308fc5336..61595749b671 100644 --- a/core/audits/byte-efficiency/byte-efficiency-audit.js +++ b/core/audits/byte-efficiency/byte-efficiency-audit.js @@ -5,7 +5,6 @@ */ import {Audit} from '../audit.js'; -import {linearInterpolation} from '../../lib/statistics.js'; import {LanternInteractive} from '../../computed/metrics/lantern-interactive.js'; import * as i18n from '../../lib/i18n/i18n.js'; import {NetworkRecords} from '../../computed/network-records.js'; @@ -17,9 +16,13 @@ const str_ = i18n.createIcuMessageFn(import.meta.url, {}); /** @typedef {import('../../lib/dependency-graph/simulator/simulator').Simulator} Simulator */ /** @typedef {import('../../lib/dependency-graph/base-node.js').Node} Node */ -const WASTED_MS_FOR_AVERAGE = 300; -const WASTED_MS_FOR_POOR = 750; -const WASTED_MS_FOR_SCORE_OF_ZERO = 5000; +// Parameters for log-normal distribution scoring. These values were determined by fitting the +// log-normal cumulative distribution function curve to the former method of linear interpolation +// scoring between the control points {average = 300 ms, poor = 750 ms, zero = 5000 ms} using the +// curve-fit tool at https://mycurvefit.com/ rounded to the nearest integer. See +// https://www.desmos.com/calculator/gcexiyesdi for an interactive visualization of the curve fit. +const WASTED_MS_P10 = 150; +const WASTED_MS_MEDIAN = 935; /** * @typedef {object} ByteEfficiencyProduct @@ -38,26 +41,18 @@ const WASTED_MS_FOR_SCORE_OF_ZERO = 5000; */ class ByteEfficiencyAudit extends Audit { /** - * Creates a score based on the wastedMs value using linear interpolation between control points. - * A negative wastedMs is scored as 1, assuming time is not being wasted with respect to the - * opportunity being measured. + * Creates a score based on the wastedMs value using log-normal distribution scoring. A negative + * wastedMs will be scored as 1, assuming time is not being wasted with respect to the opportunity + * being measured. * * @param {number} wastedMs * @return {number} */ static scoreForWastedMs(wastedMs) { - if (wastedMs <= 0) { - return 1; - } else if (wastedMs < WASTED_MS_FOR_AVERAGE) { - return linearInterpolation(0, 1, WASTED_MS_FOR_AVERAGE, 0.75, wastedMs); - } else if (wastedMs < WASTED_MS_FOR_POOR) { - return linearInterpolation(WASTED_MS_FOR_AVERAGE, 0.75, WASTED_MS_FOR_POOR, 0.5, wastedMs); - } else { - return Math.max( - 0, - linearInterpolation(WASTED_MS_FOR_POOR, 0.5, WASTED_MS_FOR_SCORE_OF_ZERO, 0, wastedMs) - ); - } + return Audit.computeLogNormalScore( + {p10: WASTED_MS_P10, median: WASTED_MS_MEDIAN}, + wastedMs + ); } /** diff --git a/core/test/audits/byte-efficiency/byte-efficiency-audit-test.js b/core/test/audits/byte-efficiency/byte-efficiency-audit-test.js index bd1550ce8bcb..48f7d29c470c 100644 --- a/core/test/audits/byte-efficiency/byte-efficiency-audit-test.js +++ b/core/test/audits/byte-efficiency/byte-efficiency-audit-test.js @@ -414,13 +414,14 @@ describe('Byte efficiency base audit', () => { it('scores wastedMs values', () => { expect(ByteEfficiencyAudit.scoreForWastedMs(-50)).toBe(1); expect(ByteEfficiencyAudit.scoreForWastedMs(0)).toBe(1); - expect(ByteEfficiencyAudit.scoreForWastedMs(240)).toBe(0.8); - expect(ByteEfficiencyAudit.scoreForWastedMs(300)).toBe(0.75); - expect(ByteEfficiencyAudit.scoreForWastedMs(390)).toBe(0.7); - expect(ByteEfficiencyAudit.scoreForWastedMs(750)).toBe(0.5); - expect(ByteEfficiencyAudit.scoreForWastedMs(1_175)).toBe(0.45); - expect(ByteEfficiencyAudit.scoreForWastedMs(5_000)).toBe(0); - expect(ByteEfficiencyAudit.scoreForWastedMs(10_000)).toBe(0); + expect(ByteEfficiencyAudit.scoreForWastedMs(240)).toBe(0.82); + expect(ByteEfficiencyAudit.scoreForWastedMs(300)).toBe(0.78); + expect(ByteEfficiencyAudit.scoreForWastedMs(390)).toBe(0.72); + expect(ByteEfficiencyAudit.scoreForWastedMs(750)).toBe(0.56); + expect(ByteEfficiencyAudit.scoreForWastedMs(1_175)).toBe(0.43); + expect(ByteEfficiencyAudit.scoreForWastedMs(5_000)).toBe(0.12); + expect(ByteEfficiencyAudit.scoreForWastedMs(10_000)).toBe(0.04); + expect(ByteEfficiencyAudit.scoreForWastedMs(30_000)).toBe(0); expect(ByteEfficiencyAudit.scoreForWastedMs(Number.MAX_VALUE)).toBe(0); }); });