Bug 1793629 - Implement attention indicator for the unified extensions button, r...
[gecko.git] / browser / base / content / test / performance / browser_preferences_usage.js
blob8fa0ddd858e159169ee7a8695b7b18558590bb09
1 /* Any copyright is dedicated to the Public Domain.
2    http://creativecommons.org/publicdomain/zero/1.0/ */
4 if (SpecialPowers.useRemoteSubframes) {
5   requestLongerTimeout(2);
8 const DEFAULT_PROCESS_COUNT = Services.prefs
9   .getDefaultBranch(null)
10   .getIntPref("dom.ipc.processCount");
12 /**
13  * A test that checks whether any preference getter from the given list
14  * of stats was called more often than the max parameter.
15  *
16  * @param {Array}  stats - an array of [prefName, accessCount] tuples
17  * @param {Number} max - the maximum number of times any of the prefs should
18  *                 have been called.
19  * @param {Object} knownProblematicPrefs (optional) - an object that defines
20  *                 prefs that should be exempt from checking the
21  *                 maximum access. It looks like the following:
22  *
23  *                 pref_name: {
24  *                   min: [Number] the minimum amount of times this should have
25  *                                 been called (to avoid keeping around dead items)
26  *                   max: [Number] the maximum amount of times this should have
27  *                                 been called (to avoid this creeping up further)
28  *                 }
29  */
30 function checkPrefGetters(stats, max, knownProblematicPrefs = {}) {
31   let getterStats = Object.entries(stats).sort(
32     ([, val1], [, val2]) => val2 - val1
33   );
35   // Clone the list to be able to delete entries to check if we
36   // forgot any later on.
37   knownProblematicPrefs = Object.assign({}, knownProblematicPrefs);
39   for (let [pref, count] of getterStats) {
40     let prefLimits = knownProblematicPrefs[pref];
41     if (!prefLimits) {
42       Assert.lessOrEqual(
43         count,
44         max,
45         `${pref} should not be accessed more than ${max} times.`
46       );
47     } else {
48       // Still record how much this pref was accessed even if we don't do any real assertions.
49       if (!prefLimits.min && !prefLimits.max) {
50         info(
51           `${pref} should not be accessed more than ${max} times and was accessed ${count} times.`
52         );
53       }
55       if (prefLimits.min) {
56         Assert.lessOrEqual(
57           prefLimits.min,
58           count,
59           `${pref} should be accessed at least ${prefLimits.min} times.`
60         );
61       }
62       if (prefLimits.max) {
63         Assert.lessOrEqual(
64           count,
65           prefLimits.max,
66           `${pref} should be accessed at most ${prefLimits.max} times.`
67         );
68       }
69       delete knownProblematicPrefs[pref];
70     }
71   }
73   // This pref will be accessed by mozJSComponentLoader when loading modules,
74   // which fails TV runs since they run the test multiple times without restarting.
75   // We just ignore this pref, since it's for testing only anyway.
76   if (knownProblematicPrefs["browser.startup.record"]) {
77     delete knownProblematicPrefs["browser.startup.record"];
78   }
80   let unusedPrefs = Object.keys(knownProblematicPrefs);
81   is(
82     unusedPrefs.length,
83     0,
84     `Should have accessed all known problematic prefs. Remaining: ${unusedPrefs}`
85   );
88 /**
89  * A helper function to read preference access data
90  * using the Services.prefs.readStats() function.
91  */
92 function getPreferenceStats() {
93   let stats = {};
94   Services.prefs.readStats((key, value) => (stats[key] = value));
95   return stats;
98 add_task(async function debug_only() {
99   ok(AppConstants.DEBUG, "You need to run this test on a debug build.");
102 // Just checks how many prefs were accessed during startup.
103 add_task(async function startup() {
104   let max = 40;
106   let knownProblematicPrefs = {
107     "browser.startup.record": {
108       // This pref is accessed in Nighly and debug builds only.
109       min: 200,
110       max: 400,
111     },
112     "network.loadinfo.skip_type_assertion": {
113       // This is accessed in debug only.
114     },
115     "chrome.override_package.global": {
116       min: 0,
117       max: 50,
118     },
119   };
121   let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService()
122     .wrappedJSObject;
123   await startupRecorder.done;
125   ok(startupRecorder.data.prefStats, "startupRecorder has prefStats");
127   checkPrefGetters(startupRecorder.data.prefStats, max, knownProblematicPrefs);
130 // This opens 10 tabs and checks pref getters.
131 add_task(async function open_10_tabs() {
132   // This is somewhat arbitrary. When we had a default of 4 content processes
133   // the value was 15. We need to scale it as we increase the number of
134   // content processes so we approximate with 4 * process_count.
135   const max = 4 * DEFAULT_PROCESS_COUNT;
137   let knownProblematicPrefs = {
138     "browser.startup.record": {
139       max: 20,
140     },
141     "browser.tabs.remote.logSwitchTiming": {
142       max: 35,
143     },
144     "network.loadinfo.skip_type_assertion": {
145       // This is accessed in debug only.
146     },
147   };
149   Services.prefs.resetStats();
151   let tabs = [];
152   while (tabs.length < 10) {
153     tabs.push(
154       await BrowserTestUtils.openNewForegroundTab(
155         gBrowser,
156         "http://example.com",
157         true,
158         true
159       )
160     );
161   }
163   for (let tab of tabs) {
164     await BrowserTestUtils.removeTab(tab);
165   }
167   checkPrefGetters(getPreferenceStats(), max, knownProblematicPrefs);
170 // This navigates to 50 sites and checks pref getters.
171 add_task(async function navigate_around() {
172   await SpecialPowers.pushPrefEnv({
173     set: [
174       // Disable bfcache so that we can measure more accurately the number of
175       // pref accesses in the child processes.
176       // If bfcache is enabled on Fission
177       // dom.ipc.keepProcessesAlive.webIsolated.perOrigin and
178       // security.sandbox.content.force-namespace are accessed only a couple of
179       // times.
180       ["browser.sessionhistory.max_total_viewers", 0],
181     ],
182   });
184   let max = 40;
186   let knownProblematicPrefs = {
187     "network.loadinfo.skip_type_assertion": {
188       // This is accessed in debug only.
189     },
190   };
192   if (AppConstants.NIGHTLY_BUILD) {
193     knownProblematicPrefs["toolkit.telemetry.cachedClientID"] = {
194       // Bug 1712391: Only an issue in tests where pref is not populated early on
195       // in startup. Code path is only accessed in Nightly builds.
196     };
197   }
199   if (SpecialPowers.useRemoteSubframes) {
200     // We access this when considering starting a new content process.
201     // Because there is no complete list of content process types,
202     // caching this is not trivial. Opening 50 different content
203     // processes and throwing them away immediately is a bit artificial;
204     // we're more likely to keep some around so this shouldn't be quite
205     // this bad in practice. Fixing this is
206     // https://bugzilla.mozilla.org/show_bug.cgi?id=1600266
207     knownProblematicPrefs["dom.ipc.processCount.webIsolated"] = {
208       min: 50,
209       max: 51,
210     };
211     // This pref is only accessed in automation to speed up tests.
212     knownProblematicPrefs[
213       "dom.ipc.keepProcessesAlive.webIsolated.perOrigin"
214     ] = {
215       min: 50,
216       max: 51,
217     };
218     if (AppConstants.platform == "linux") {
219       // The following sandbox pref is covered by
220       // https://bugzilla.mozilla.org/show_bug.cgi?id=1600189
221       knownProblematicPrefs["security.sandbox.content.force-namespace"] = {
222         min: 45,
223         max: 55,
224       };
225       // This was previously being read in the content process, but
226       // bug 1725573 moved it into the parent process.  We also block
227       // the main thread on requests to the X server, which is likely
228       // more problematic than the pref read.  These issues are covered
229       // by https://bugzilla.mozilla.org/show_bug.cgi?id=1729080
230       knownProblematicPrefs["gfx.color_management.display_profile"] = {
231         min: 45,
232         max: 50,
233       };
234     } else if (AppConstants.platform == "win") {
235       // The following 2 graphics prefs are covered by
236       // https://bugzilla.mozilla.org/show_bug.cgi?id=1639497
237       knownProblematicPrefs["gfx.canvas.azure.backends"] = {
238         min: 90,
239         max: 110,
240       };
241       knownProblematicPrefs["gfx.content.azure.backends"] = {
242         min: 90,
243         max: 110,
244       };
245       // The following 2 sandbox prefs are covered by
246       // https://bugzilla.mozilla.org/show_bug.cgi?id=1639494
247       knownProblematicPrefs["security.sandbox.content.read_path_whitelist"] = {
248         min: 49,
249         max: 55,
250       };
251       knownProblematicPrefs["security.sandbox.logging.enabled"] = {
252         min: 49,
253         max: 55,
254       };
255     }
256   }
258   Services.prefs.resetStats();
260   let tab = await BrowserTestUtils.openNewForegroundTab(
261     gBrowser,
262     "http://example.com",
263     true,
264     true
265   );
267   let urls = [
268     "http://example.com/",
269     "https://example.com/",
270     "http://example.org/",
271     "https://example.org/",
272   ];
274   for (let i = 0; i < 50; i++) {
275     let url = urls[i % urls.length];
276     info(`Navigating to ${url}...`);
277     BrowserTestUtils.loadURI(tab.linkedBrowser, url);
278     await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, url);
279     info(`Loaded ${url}.`);
280   }
282   await BrowserTestUtils.removeTab(tab);
284   checkPrefGetters(getPreferenceStats(), max, knownProblematicPrefs);