Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
/* Any copyright is dedicated to the Public Domain.
"use strict";
ChromeUtils.defineESModuleGetters(this, {
PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
});
const DEFAULT_CHUNK_SIZE = 50;
// 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: [
{
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: [
{
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) => ({
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();
}
});