Skip to content
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
37 changes: 37 additions & 0 deletions src/lib/navbench/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import {
annotationsFor,
displayName,
OVERALL_TEST,
proseList,
scenariosIn,
signatureTest,
sitesIn,
testKey,
videoScenario
} from './config';
Expand Down Expand Up @@ -80,3 +83,37 @@ describe('annotationsFor', () => {
expect(annotationsFor(OVERALL_TEST, 'osxm4', [windowsOnly])).toEqual([]);
});
});

describe('the explainer lists', () => {
const tests = [
OVERALL_TEST,
'wikipedia-nav-subnav-score',
'amazon-nav-load-score',
'amazon-nav-subnav-score',
'google-docs-nav-warm-score'
];

it('names each site once, alphabetically, without the overall', () => {
expect(sitesIn(tests)).toEqual(['Amazon', 'Google Docs', 'Wikipedia']);
});

it('names each scenario once, in a fixed order', () => {
expect(scenariosIn(tests)).toEqual(['page load', 'sub-navigation', 'warm-load']);
expect(scenariosIn(['amazon-nav-subnav-score', 'amazon-nav-load-score'])).toEqual([
'page load',
'sub-navigation'
]);
});

it('is empty before any tests have loaded', () => {
expect(sitesIn([OVERALL_TEST])).toEqual([]);
expect(scenariosIn([OVERALL_TEST])).toEqual([]);
});

it('joins items without a serial comma', () => {
expect(proseList([])).toBe('');
expect(proseList(['A'])).toBe('A');
expect(proseList(['A', 'B'])).toBe('A and B');
expect(proseList(['A', 'B', 'C'])).toBe('A, B and C');
});
});
74 changes: 65 additions & 9 deletions src/lib/navbench/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ export const NAVBENCH_FRAMEWORK = FRAMEWORK.browsertime;

export const NAVBENCH_REPOSITORY = 'autoland' as const;

/** The desktop platforms the benchmark runs on, from the shared platform table. */
const NAVBENCH_PLATFORM_KEYS = ['linux', 'osxm4', 'windows', 'windows-hwref'];
/**
* The platforms the benchmark runs on, from the shared platform table. Android
* runs the mobile variant (nav-bench-m) in Fenix, which reports under the same
* suite name.
*/
const NAVBENCH_PLATFORM_KEYS = ['linux', 'osxm4', 'windows', 'windows-hwref', 'android-a55'];

export const NAVBENCH_PLATFORMS: readonly PlatformConfig[] = PLATFORMS.filter((platform) =>
NAVBENCH_PLATFORM_KEYS.includes(platform.key)
Expand Down Expand Up @@ -52,21 +56,73 @@ const SITE_LABELS: Record<string, string> = {

const capitalize = (word: string) => word.charAt(0).toUpperCase() + word.slice(1);

/**
* A test's site and scenario: `google-docs` and `warm` from
* `google-docs-nav-warm-score`.
*
* Split at `-nav-` rather than at the first hyphen, so a hyphenated site name
* stays together.
*/
function parseTest(test: string): { site: string; scenario?: string } {
const name = test.replace(/-score$/, '');
const split = name.indexOf('-nav-');
return split === -1
? { site: name }
: { site: name.slice(0, split), scenario: name.slice(split + '-nav-'.length) };
}

const siteLabel = (site: string) => SITE_LABELS[site] ?? site.split('-').map(capitalize).join(' ');

/**
* `BBC nav subnav` from `bbc-nav-subnav-score`.
*
* Every test in this suite is a score, so the suffix carries no information in
* a table whose header already says so. Split at `-nav-` rather than at the
* first hyphen, so `google-docs-nav-warm-score` is Google Docs and not Google.
* a table whose header already says so.
*/
export function displayName(test: string): string {
if (test === OVERALL_TEST) return 'Overall Score';

const name = test.replace(/-score$/, '');
const split = name.indexOf('-nav-');
const site = split === -1 ? name : name.slice(0, split);
const label = SITE_LABELS[site] ?? site.split('-').map(capitalize).join(' ');
return split === -1 ? label : `${label} nav ${name.slice(split + '-nav-'.length)}`;
const { site, scenario } = parseTest(test);
return scenario === undefined ? siteLabel(site) : `${siteLabel(site)} nav ${scenario}`;
}

/** The sites among these tests, labelled and alphabetical. */
export function sitesIn(tests: readonly string[]): string[] {
const sites = new Set(
tests.filter((test) => test !== OVERALL_TEST).map((test) => siteLabel(parseTest(test).site))
);
return [...sites].sort((a, b) => a.localeCompare(b));
}

const SCENARIO_LABELS: Record<string, string> = {
load: 'page load',
subnav: 'sub-navigation',
warm: 'warm-load'
};

/** The scenarios among these tests, in prose, in the order above. */
export function scenariosIn(tests: readonly string[]): string[] {
const scenarios = new Set(
tests.flatMap((test) => {
const { scenario } = parseTest(test);
return test === OVERALL_TEST || scenario === undefined ? [] : [scenario];
})
);
const known = Object.keys(SCENARIO_LABELS);
return [...scenarios]
.sort((a, b) => {
const rank = (scenario: string) =>
known.includes(scenario) ? known.indexOf(scenario) : known.length;
return rank(a) - rank(b) || a.localeCompare(b);
})
.map((scenario) => SCENARIO_LABELS[scenario] ?? scenario);
}

/** `a, b and c`, matching the explainer's house style (no serial comma). */
export function proseList(items: readonly string[]): string {
return items.length <= 1
? (items[0] ?? '')
: `${items.slice(0, -1).join(', ')} and ${items[items.length - 1]}`;
}

/**
Expand Down
11 changes: 9 additions & 2 deletions src/lib/navbench/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ import {
/** Days of history behind the comparison table, independent of the chart range. */
export const TABLE_WINDOW_DAYS = 30;

/** Every nav-bench signature on a platform, both Firefox and Nightly-as-Release. */
/**
* Every nav-bench signature on a platform, both Firefox and Nightly-as-Release.
* On Android the application is Fenix rather than Firefox.
*/
export async function loadNavBenchSignatures(
platformKey: string,
signal?: AbortSignal
Expand All @@ -47,7 +50,11 @@ export async function loadNavBenchSignatures(

const navBench = perPlatform
.flat()
.filter((sig) => sig.suite === NAVBENCH_SUITE && sig.application === 'firefox');
.filter(
(sig) =>
sig.suite === NAVBENCH_SUITE &&
(sig.application === 'firefox' || sig.application === 'fenix')
);

return selectCanonicalSignatures(navBench);
}
Expand Down
27 changes: 20 additions & 7 deletions src/routes/navbench/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
NAVBENCH_FRAMEWORK,
NAVBENCH_PLATFORMS,
NAVBENCH_REPOSITORY,
OVERALL_TEST
OVERALL_TEST,
platformByKey,
proseList,
scenariosIn,
sitesIn
} from '$lib/navbench/config';
import {
loadNavBenchMeasurements,
Expand Down Expand Up @@ -56,6 +60,14 @@

const tests = $derived(testsIn(signatures.value ?? []));

// The explainer describes what runs on this platform: Android runs fewer
// sites and scenarios than desktop. Empty until the signatures load.
const browserName = $derived(
platformByKey(os).group === 'mobile' ? 'Firefox for Android' : 'Firefox'
);
const sites = $derived(proseList(sitesIn(tests)));
const scenarios = $derived(proseList(scenariosIn(tests)));

const chartData = resource(async (signal) => {
const all = signatures.value;
if (!all) return [];
Expand Down Expand Up @@ -204,12 +216,13 @@

<div class="page">
<div class="explainer">
<strong>Navigation Benchmark</strong> tests Firefox navigation performance across real websites:
Amazon, BBC, DuckDuckGo, Facebook, Google, Google Docs, Reddit, Wikipedia and Yahoo. Sites are
tested across a mix of page load, sub-navigation and warm-load scenarios, scored using
SpeedIndex. Per-site and overall scores are geometric means; higher is better. Click a point to
play the screen recordings that run made. Dashed markers on the charts flag benchmark changes;
hover for details, or click the label to open the bug.
<strong>Navigation Benchmark</strong> tests {browserName} navigation performance across real websites{#if sites}:
{sites}{/if}.{' '}{#if scenarios}
Sites are tested across a mix of {scenarios} scenarios, scored using SpeedIndex.{:else}
Sites are scored using SpeedIndex.{/if}
Per-site and overall scores are geometric means; higher is better. Click a point to play the screen
recordings that run made. Dashed markers on the charts flag benchmark changes; hover for details,
or click the label to open the bug.
<p class="links">
<a
href="https://firefox-source-docs.mozilla.org/testing/perfdocs/raptor.html#nav-bench"
Expand Down
Loading