Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: ensure good and average scores start exactly at control points #13559

Merged
merged 3 commits into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions lighthouse-core/audits/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,28 @@ class Audit {
* considering a log-normal distribution governed by two control points (the 10th
* percentile value and the median value) and represents the percentage of sites that are
* greater than `value`.
*
* Score characteristics:
* - within [0, 1]
* - rounded to two digits
* - value must meet or beat a controlPoint value to meet or exceed its percentile score:
* - value > median will give a score < 0.5; value ≤ median will give a score ≥ 0.5.
* - value > p10 will give a score < 0.9; value ≤ p10 will give a score ≥ 0.9.
* - values < p10 will get a slight boost so a score of 1 is achievable by a
* `value` other than those close to 0. Scores of > ~0.99524 end up rounded to 1.
* @param {{median: number, p10: number}} controlPoints
* @param {number} value
* @return {number}
*/
static computeLogNormalScore(controlPoints, value) {
const percentile = statistics.getLogNormalScore(controlPoints, value);
return clampTo2Decimals(percentile);
let percentile = statistics.getLogNormalScore(controlPoints, value);
// Add a boost to scores of 90+, linearly ramping from 0 at 0.9 to half a
// point (0.005) at 1. Expands scores in (0.9, 1] to (0.9, 1.005], so more top
// scores will be a perfect 1 after the two-digit `Math.floor()` rounding below.
if (percentile > 0.9) { // getLogNormalScore ensures `percentile` can't exceed 1.
percentile += 0.05 * (percentile - 0.9);
}
return Math.floor(percentile * 100) / 100;
}

/**
Expand Down
38 changes: 34 additions & 4 deletions lighthouse-core/test/audits/audit-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,40 @@ describe('Audit', () => {

assert.strictEqual(Audit.computeLogNormalScore(params, 0), 1);
assert.strictEqual(Audit.computeLogNormalScore(params, 250), 0.99);
assert.strictEqual(Audit.computeLogNormalScore(params, 1500), 0.23);
assert.strictEqual(Audit.computeLogNormalScore(params, 2500), 0.05);
assert.strictEqual(Audit.computeLogNormalScore(params, 4000), 0.01);
assert.strictEqual(Audit.computeLogNormalScore(params, 4100), 0);
assert.strictEqual(Audit.computeLogNormalScore(params, 1500), 0.22);
assert.strictEqual(Audit.computeLogNormalScore(params, 2500), 0.04);
assert.strictEqual(Audit.computeLogNormalScore(params, 3500), 0.01);
assert.strictEqual(Audit.computeLogNormalScore(params, 3600), 0);
});

it('correctly bins scores relative to control points and allows achievable 100s', () => {
const params = {
median: 800,
p10: 200,
};

// Clamps negative values to a score of 1.
assert.strictEqual(Audit.computeLogNormalScore(params, -100), 1);

// 0 value is always scored with a 1.
assert.strictEqual(Audit.computeLogNormalScore(params, 0), 1);

// A really good value has its score rounded up to 1.
assert.strictEqual(Audit.computeLogNormalScore(params, 25), 1);
assert.strictEqual(Audit.computeLogNormalScore(params, 50), 0.99);

// p10 param gets a 0.9.
assert.strictEqual(Audit.computeLogNormalScore(params, params.p10), 0.9);
// Anything worse than p10 gets < 0.9.
assert.strictEqual(Audit.computeLogNormalScore(params, params.p10 + 1), 0.89);

// Median param gets a 0.5.
assert.strictEqual(Audit.computeLogNormalScore(params, params.median), 0.5);
// Anything worse than the median gets < 0.5.
assert.strictEqual(Audit.computeLogNormalScore(params, params.median + 1), 0.49);

assert.strictEqual(Audit.computeLogNormalScore(params, 8_000), 0.01);
assert.strictEqual(Audit.computeLogNormalScore(params, 10_000), 0);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('Performance: page execution timings audit', () => {

assert.equal(Math.round(output.numericValue), 4081);
assert.equal(output.details.items.length, 7);
assert.equal(output.score, 0.49);
assert.equal(output.score, 0.48);
});

it('should compute the correct values for the redirect trace', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('Performance: first-contentful-paint audit', () => {

const context = getFakeContext({formFactor: 'mobile', throttlingMethod: 'provided'});
const result = await FcpAudit.audit(artifacts, context);
assert.equal(result.score, 0.06);
assert.equal(result.score, 0.05);
assert.equal(result.numericValue, 5668.275);
});
});
4 changes: 2 additions & 2 deletions lighthouse-core/test/results/sample_v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"id": "first-contentful-paint",
"title": "First Contentful Paint",
"description": "First Contentful Paint marks the time at which the first text or image is painted. [Learn more](https://web.dev/first-contentful-paint/).",
"score": 0.02,
"score": 0.01,
"scoreDisplayMode": "numeric",
"numericValue": 6843.95,
"numericUnit": "millisecond",
Expand Down Expand Up @@ -4191,7 +4191,7 @@
"id": "uses-long-cache-ttl",
"title": "Serve static assets with an efficient cache policy",
"description": "A long cache lifetime can speed up repeat visits to your page. [Learn more](https://web.dev/uses-long-cache-ttl/).",
"score": 0.03,
"score": 0.02,
"scoreDisplayMode": "numeric",
"numericValue": 1258057,
"numericUnit": "byte",
Expand Down
2 changes: 1 addition & 1 deletion report/test/generator/report-generator-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ describe('ReportGenerator', () => {
expect(lines.slice(0, 3).join('\n')).toMatchInlineSnapshot(`
"requestedUrl,finalUrl,category,name,title,type,score
\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"Performance\\",\\"performance-score\\",\\"Overall Performance Category Score\\",\\"numeric\\",\\"0.26\\"
\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"Performance\\",\\"first-contentful-paint\\",\\"First Contentful Paint\\",\\"numeric\\",\\"0.02\\"
\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"Performance\\",\\"first-contentful-paint\\",\\"First Contentful Paint\\",\\"numeric\\",\\"0.01\\"
"
`);

Expand Down