commit a3a5cac5a06b9d69d45b9f4d888ab7e1b5667550
parent d88fce9a0c41a2f964864311edb4818d0a9b3cac
Author: James Teow <jteow@mozilla.com>
Date: Tue, 28 Oct 2025 14:23:51 +0000
Bug 1986066 - Add a performance test for calculate_frecency - r=perftest-reviewers,mozperftest-reviewers,places-reviewers,sparky,Standard8
calculate_frecency determines frecency values for moz_places rows
in Places. We should add performance tests to understand the impact
of changes to the function, especially as we continue to evolve
the algorithm.
Differential Revision: https://phabricator.services.mozilla.com/D267276
Diffstat:
7 files changed, 256 insertions(+), 0 deletions(-)
diff --git a/python/mozperftest/perfdocs/config.yml b/python/mozperftest/perfdocs/config.yml
@@ -95,3 +95,8 @@ suites:
"browser_addManyNodes.js": ""
"browser_reflowPseudoelements.js": ""
"browser_removeManySpellingErrors.js": ""
+
+ toolkit/components/places/tests/browser/performance:
+ description: "Performance tests for Toolkit: Places"
+ tests:
+ "Calculate Frecency Speed": ""
diff --git a/taskcluster/kinds/perftest/linux.yml b/taskcluster/kinds/perftest/linux.yml
@@ -780,3 +780,22 @@ perftest-accessibility:
--flavor mochitest
--output $MOZ_FETCHES_DIR/../artifacts
accessible/tests/browser/performance/browser_removeManySpellingErrors.js
+
+perftest-places:
+ description: Run Places related performance tests
+ treeherder:
+ symbol: perftest(places)
+ tier: 2
+ attributes:
+ batch: false
+ cron: false
+ run-on-projects: [mozilla-central]
+ run:
+ command: >-
+ mkdir -p $MOZ_FETCHES_DIR/../artifacts &&
+ cd $MOZ_FETCHES_DIR &&
+ python3 python/mozperftest/mozperftest/runner.py
+ --mochitest-binary ${MOZ_FETCHES_DIR}/firefox/firefox-bin
+ --flavor mochitest
+ --output $MOZ_FETCHES_DIR/../artifacts
+ toolkit/components/places/tests/browser/performance/browser_calculate_frecency_speed.js
diff --git a/taskcluster/kinds/perftest/macosx.yml b/taskcluster/kinds/perftest/macosx.yml
@@ -732,3 +732,22 @@ perftest-accessibility:
--flavor mochitest
--output $MOZ_FETCHES_DIR/../artifacts
accessible/tests/browser/performance/browser_removeManySpellingErrors.js
+
+perftest-places:
+ description: Run Places related performance tests
+ treeherder:
+ symbol: perftest(places)
+ tier: 2
+ attributes:
+ batch: false
+ cron: false
+ run-on-projects: [mozilla-central]
+ run:
+ command: >-
+ mkdir -p $MOZ_FETCHES_DIR/../artifacts &&
+ cd $MOZ_FETCHES_DIR &&
+ python3 python/mozperftest/mozperftest/runner.py
+ --mochitest-binary ${MOZ_FETCHES_DIR}/target.dmg
+ --flavor mochitest
+ --output $MOZ_FETCHES_DIR/../artifacts
+ toolkit/components/places/tests/browser/performance/browser_calculate_frecency_speed.js
diff --git a/testing/perfdocs/generated/mozperftest.rst b/testing/perfdocs/generated/mozperftest.rst
@@ -719,6 +719,30 @@ browser_ml_summarizer_perf.js
**Template test for latency for Summarizer model**
+toolkit/components/places/tests/browser/performance
+---------------------------------------------------
+Performance tests for Toolkit: Places
+
+browser_calculate_frecency_speed.js
+===================================
+
+:owner: Places
+:name: Calculate Frecency Speed
+:Default options:
+
+::
+
+ --extra-args headless
+ --manifest perftest.toml
+ --manifest-flavor browser-chrome
+ --perfherder
+ --perfherder-metrics name:PlacesCalculateFrecencyHighFrequency,unit:ms,shouldAlert:False, name:PlacesCalculateFrecencyLowFrequency,unit:ms,shouldAlert:False, name:PlacesCalculateFrecencyChunked,unit:ms,shouldAlert:False
+ --try-platform linux, mac
+ --verbose
+
+**Audits the speed of running calculate_frecency.**
+
+
toolkit/components/url-classifier/tests/performance
---------------------------------------------------
Performance tests for the URL Classifier
diff --git a/toolkit/components/places/tests/browser/performance/browser_calculate_frecency_speed.js b/toolkit/components/places/tests/browser/performance/browser_calculate_frecency_speed.js
@@ -0,0 +1,184 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ AddonTestUtils: "resource://testing-common/AddonTestUtils.sys.mjs",
+ PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs",
+ PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
+});
+
+const DEFAULT_CHUNK_SIZE = 50;
+
+// XXX: We can consolidate this once bug 1930955 lands
+// eslint-disable-next-line no-unused-vars
+const perfMetadata = {
+ owner: "Places",
+ name: "Calculate Frecency Speed",
+ description: "Audits the speed of running calculate_frecency.",
+ options: {
+ default: {
+ extra_args: ["headless"],
+ manifest: "perftest.toml",
+ manifest_flavor: "browser-chrome",
+ perfherder: true,
+ perfherder_metrics: [
+ // Timing metrics.
+ {
+ name: "PlacesCalculateFrecencyHighFrequency",
+ unit: "ms",
+ shouldAlert: false,
+ },
+ {
+ name: "PlacesCalculateFrecencyLowFrequency",
+ unit: "ms",
+ shouldAlert: false,
+ },
+ {
+ name: "PlacesCalculateFrecencyChunked",
+ unit: "ms",
+ shouldAlert: false,
+ },
+ ],
+ try_platform: ["linux", "mac"],
+ verbose: true,
+ },
+ },
+};
+
+function createTimer(metricName) {
+ let accumulatedTime = 0;
+ let iterations = 0;
+ let now = 0;
+ return {
+ start() {
+ now = ChromeUtils.now();
+ },
+ stop() {
+ accumulatedTime += ChromeUtils.now() - now;
+ iterations++;
+ },
+ reportMetrics() {
+ const metrics = {};
+ metrics[metricName] = accumulatedTime / iterations;
+ info(`perfMetrics | ${JSON.stringify(metrics)}`);
+ },
+ };
+}
+
+add_task(async function measure_frecency_speed() {
+ let testData = [
+ // High frequency, recent visits.
+ {
+ timerName: "PlacesCalculateFrecencyHighFrequency",
+ urls: [
+ {
+ url: "https://www.mozilla.org/",
+ visits: [
+ {
+ // 1 hour ago
+ date: new Date(Date.now() - 1000 * 60 * 60),
+ transition: PlacesUtils.history.TRANSITIONS.TYPED,
+ },
+ {
+ // 1 day ago
+ date: new Date(Date.now() - 1000 * 60 * 60 * 24),
+ transition: PlacesUtils.history.TRANSITIONS.TYPED,
+ },
+ {
+ // 7 days ago
+ date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 7),
+ transition: PlacesUtils.history.TRANSITIONS.TYPED,
+ },
+ {
+ // 14 days ago
+ date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 14),
+ transition: PlacesUtils.history.TRANSITIONS.TYPED,
+ },
+ {
+ // 30 days ago
+ date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 30),
+ transition: PlacesUtils.history.TRANSITIONS.TYPED,
+ },
+ ],
+ },
+ ],
+ },
+ // Low frequency, old visit.
+ {
+ timerName: "PlacesCalculateFrecencyLowFrequency",
+ urls: [
+ {
+ url: "https://old.mozilla.org/",
+ visits: [
+ {
+ // 365 days ago
+ date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 365),
+ transition: PlacesUtils.history.TRANSITIONS.LINK,
+ },
+ ],
+ },
+ ],
+ },
+ // Many different URLs.
+ {
+ timerName: "PlacesCalculateFrecencyChunked",
+ urls: [
+ ...Array.from({ length: DEFAULT_CHUNK_SIZE }, (_, i) => ({
+ url: `https://www.example${i}.com/`,
+ visits: [
+ {
+ date: new Date(),
+ },
+ ],
+ })),
+ ],
+ },
+ ];
+
+ for (let item of testData) {
+ await PlacesUtils.bookmarks.eraseEverything();
+ await PlacesUtils.history.clear();
+
+ let db = await PlacesUtils.promiseDBConnection();
+ let initialIds = await db.executeCached(`
+ SELECT id FROM moz_places
+ ORDER BY id
+ `);
+ Assert.equal(initialIds.length, 0, "Places should be empty.");
+
+ for (let urlData of item.urls) {
+ for (let visit of urlData.visits) {
+ await PlacesTestUtils.addVisits({
+ uri: urlData.url,
+ visitDate: visit.date,
+ transition: visit.transition,
+ });
+ }
+ }
+ let placeIds = await db.executeCached(`
+ SELECT id FROM moz_places
+ ORDER BY id
+ `);
+ Assert.equal(
+ placeIds.length,
+ item.urls.length,
+ "Places should match the number of URLs in the test."
+ );
+
+ let frecencyTimer = createTimer(item.timerName);
+ await PlacesUtils.withConnectionWrapper("Calculate Frecency", async db => {
+ frecencyTimer.start();
+ await db.executeCached(
+ `
+ UPDATE moz_places
+ SET frecency = CALCULATE_FRECENCY(id)
+ `
+ );
+ frecencyTimer.stop();
+ });
+
+ frecencyTimer.reportMetrics();
+ }
+});
diff --git a/toolkit/components/places/tests/browser/performance/perftest.toml b/toolkit/components/places/tests/browser/performance/perftest.toml
@@ -0,0 +1,4 @@
+[DEFAULT]
+
+["browser_calculate_frecency_speed.js"]
+disabled = "Disabled as we want to run this only as perftest, not regular CI"
diff --git a/toolkit/components/places/tests/moz.build b/toolkit/components/places/tests/moz.build
@@ -25,6 +25,7 @@ XPCSHELL_TESTS_MANIFESTS += [
BROWSER_CHROME_MANIFESTS += [
"browser/browser.toml",
+ "browser/performance/perftest.toml",
"browser/previews/browser.toml",
]