From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/performance/browser_preferences_usage.js | 282 +++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 browser/base/content/test/performance/browser_preferences_usage.js (limited to 'browser/base/content/test/performance/browser_preferences_usage.js') diff --git a/browser/base/content/test/performance/browser_preferences_usage.js b/browser/base/content/test/performance/browser_preferences_usage.js new file mode 100644 index 0000000000..d62cb2316b --- /dev/null +++ b/browser/base/content/test/performance/browser_preferences_usage.js @@ -0,0 +1,282 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +if (SpecialPowers.useRemoteSubframes) { + requestLongerTimeout(2); +} + +const DEFAULT_PROCESS_COUNT = Services.prefs + .getDefaultBranch(null) + .getIntPref("dom.ipc.processCount"); + +/** + * A test that checks whether any preference getter from the given list + * of stats was called more often than the max parameter. + * + * @param {Array} stats - an array of [prefName, accessCount] tuples + * @param {Number} max - the maximum number of times any of the prefs should + * have been called. + * @param {Object} knownProblematicPrefs (optional) - an object that defines + * prefs that should be exempt from checking the + * maximum access. It looks like the following: + * + * pref_name: { + * min: [Number] the minimum amount of times this should have + * been called (to avoid keeping around dead items) + * max: [Number] the maximum amount of times this should have + * been called (to avoid this creeping up further) + * } + */ +function checkPrefGetters(stats, max, knownProblematicPrefs = {}) { + let getterStats = Object.entries(stats).sort( + ([, val1], [, val2]) => val2 - val1 + ); + + // Clone the list to be able to delete entries to check if we + // forgot any later on. + knownProblematicPrefs = Object.assign({}, knownProblematicPrefs); + + for (let [pref, count] of getterStats) { + let prefLimits = knownProblematicPrefs[pref]; + if (!prefLimits) { + Assert.lessOrEqual( + count, + max, + `${pref} should not be accessed more than ${max} times.` + ); + } else { + // Still record how much this pref was accessed even if we don't do any real assertions. + if (!prefLimits.min && !prefLimits.max) { + info( + `${pref} should not be accessed more than ${max} times and was accessed ${count} times.` + ); + } + + if (prefLimits.min) { + Assert.lessOrEqual( + prefLimits.min, + count, + `${pref} should be accessed at least ${prefLimits.min} times.` + ); + } + if (prefLimits.max) { + Assert.lessOrEqual( + count, + prefLimits.max, + `${pref} should be accessed at most ${prefLimits.max} times.` + ); + } + delete knownProblematicPrefs[pref]; + } + } + + // This pref will be accessed by mozJSComponentLoader when loading modules, + // which fails TV runs since they run the test multiple times without restarting. + // We just ignore this pref, since it's for testing only anyway. + if (knownProblematicPrefs["browser.startup.record"]) { + delete knownProblematicPrefs["browser.startup.record"]; + } + + let unusedPrefs = Object.keys(knownProblematicPrefs); + is( + unusedPrefs.length, + 0, + `Should have accessed all known problematic prefs. Remaining: ${unusedPrefs}` + ); +} + +/** + * A helper function to read preference access data + * using the Services.prefs.readStats() function. + */ +function getPreferenceStats() { + let stats = {}; + Services.prefs.readStats((key, value) => (stats[key] = value)); + return stats; +} + +add_task(async function debug_only() { + ok(AppConstants.DEBUG, "You need to run this test on a debug build."); +}); + +// Just checks how many prefs were accessed during startup. +add_task(async function startup() { + let max = 40; + + let knownProblematicPrefs = { + "browser.startup.record": { + // This pref is accessed in Nighly and debug builds only. + min: 200, + max: 400, + }, + "network.loadinfo.skip_type_assertion": { + // This is accessed in debug only. + }, + "chrome.override_package.global": { + min: 0, + max: 50, + }, + }; + + let startupRecorder = + Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject; + await startupRecorder.done; + + ok(startupRecorder.data.prefStats, "startupRecorder has prefStats"); + + checkPrefGetters(startupRecorder.data.prefStats, max, knownProblematicPrefs); +}); + +// This opens 10 tabs and checks pref getters. +add_task(async function open_10_tabs() { + // This is somewhat arbitrary. When we had a default of 4 content processes + // the value was 15. We need to scale it as we increase the number of + // content processes so we approximate with 4 * process_count. + const max = 4 * DEFAULT_PROCESS_COUNT; + + let knownProblematicPrefs = { + "browser.startup.record": { + max: 20, + }, + "browser.tabs.remote.logSwitchTiming": { + max: 35, + }, + "network.loadinfo.skip_type_assertion": { + // This is accessed in debug only. + }, + }; + + Services.prefs.resetStats(); + + let tabs = []; + while (tabs.length < 10) { + tabs.push( + await BrowserTestUtils.openNewForegroundTab( + gBrowser, + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com", + true, + true + ) + ); + } + + for (let tab of tabs) { + await BrowserTestUtils.removeTab(tab); + } + + checkPrefGetters(getPreferenceStats(), max, knownProblematicPrefs); +}); + +// This navigates to 50 sites and checks pref getters. +add_task(async function navigate_around() { + await SpecialPowers.pushPrefEnv({ + set: [ + // Disable bfcache so that we can measure more accurately the number of + // pref accesses in the child processes. + // If bfcache is enabled on Fission + // dom.ipc.keepProcessesAlive.webIsolated.perOrigin and + // security.sandbox.content.force-namespace are accessed only a couple of + // times. + ["browser.sessionhistory.max_total_viewers", 0], + ], + }); + + let max = 40; + + let knownProblematicPrefs = { + "network.loadinfo.skip_type_assertion": { + // This is accessed in debug only. + }, + }; + + if (Services.prefs.getBoolPref("browser.translations.enable")) { + // The translations pref logs the translation decision on each DOMContentLoaded, + // and only shows the log by the preferences set in the console.createInstance. + // See Bug 1835693. This means that it is invoked on each page load. + knownProblematicPrefs["browser.translations.logLevel"] = { + min: 50, + max: 50, + }; + } + + if (SpecialPowers.useRemoteSubframes) { + // We access this when considering starting a new content process. + // Because there is no complete list of content process types, + // caching this is not trivial. Opening 50 different content + // processes and throwing them away immediately is a bit artificial; + // we're more likely to keep some around so this shouldn't be quite + // this bad in practice. Fixing this is + // https://bugzilla.mozilla.org/show_bug.cgi?id=1600266 + knownProblematicPrefs["dom.ipc.processCount.webIsolated"] = { + min: 50, + max: 51, + }; + // This pref is only accessed in automation to speed up tests. + knownProblematicPrefs["dom.ipc.keepProcessesAlive.webIsolated.perOrigin"] = + { + min: 100, + max: 102, + }; + if (AppConstants.platform == "linux") { + // The following sandbox pref is covered by + // https://bugzilla.mozilla.org/show_bug.cgi?id=1600189 + knownProblematicPrefs["security.sandbox.content.force-namespace"] = { + min: 45, + max: 55, + }; + } else if (AppConstants.platform == "win") { + // The following 2 graphics prefs are covered by + // https://bugzilla.mozilla.org/show_bug.cgi?id=1639497 + knownProblematicPrefs["gfx.canvas.azure.backends"] = { + min: 90, + max: 110, + }; + knownProblematicPrefs["gfx.content.azure.backends"] = { + min: 90, + max: 110, + }; + // The following 2 sandbox prefs are covered by + // https://bugzilla.mozilla.org/show_bug.cgi?id=1639494 + knownProblematicPrefs["security.sandbox.content.read_path_whitelist"] = { + min: 47, + max: 55, + }; + knownProblematicPrefs["security.sandbox.logging.enabled"] = { + min: 47, + max: 55, + }; + } + } + + Services.prefs.resetStats(); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com", + true, + true + ); + + let urls = [ + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com/", + "https://example.com/", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.org/", + "https://example.org/", + ]; + + for (let i = 0; i < 50; i++) { + let url = urls[i % urls.length]; + info(`Navigating to ${url}...`); + BrowserTestUtils.loadURIString(tab.linkedBrowser, url); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, url); + info(`Loaded ${url}.`); + } + + await BrowserTestUtils.removeTab(tab); + + checkPrefGetters(getPreferenceStats(), max, knownProblematicPrefs); +}); -- cgit v1.2.3