Tab unloading should not unload "fresh" tabs i.e. tabs that were accessed very recently, even though one of them was the least recently used tab. To achieve it, this patch introduces the minimum inactive duration and we prevent tabs that were accessed in the last period of that duration from being unloaded. This patch sets the default value to 10 minutes based on the historgram `TAB_UNLOAD_TO_RELOAD` where the median was 60sec and the 75th percentile was 1040sec. This value can be overriden by the parameter of the TabUnloader's APIs so that about:unloads and the tests can unload those fresh tabs. Differential Revision: https://phabricator.services.mozilla.com/D125824
435 lines
11 KiB
JavaScript
435 lines
11 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
|
*/
|
|
"use strict";
|
|
|
|
const { TabUnloader } = ChromeUtils.import(
|
|
"resource:///modules/TabUnloader.jsm"
|
|
);
|
|
|
|
let TestTabUnloaderMethods = {
|
|
isNonDiscardable(tab, weight) {
|
|
return /\bselected\b/.test(tab.keywords) ? weight : 0;
|
|
},
|
|
|
|
isParentProcess(tab, weight) {
|
|
return /\bparent\b/.test(tab.keywords) ? weight : 0;
|
|
},
|
|
|
|
isPinned(tab, weight) {
|
|
return /\bpinned\b/.test(tab.keywords) ? weight : 0;
|
|
},
|
|
|
|
isLoading(tab, weight) {
|
|
return /\bloading\b/.test(tab.keywords) ? weight : 0;
|
|
},
|
|
|
|
usingPictureInPicture(tab, weight) {
|
|
return /\bpictureinpicture\b/.test(tab.keywords) ? weight : 0;
|
|
},
|
|
|
|
playingMedia(tab, weight) {
|
|
return /\bmedia\b/.test(tab.keywords) ? weight : 0;
|
|
},
|
|
|
|
usingWebRTC(tab, weight) {
|
|
return /\bwebrtc\b/.test(tab.keywords) ? weight : 0;
|
|
},
|
|
|
|
getMinTabCount() {
|
|
// Use a low number for testing.
|
|
return 3;
|
|
},
|
|
|
|
getNow() {
|
|
return 100;
|
|
},
|
|
|
|
*iterateProcesses(tab) {
|
|
for (let process of tab.process.split(",")) {
|
|
yield Number(process);
|
|
}
|
|
},
|
|
|
|
async calculateMemoryUsage(processMap, tabs) {
|
|
let memory = tabs[0].memory;
|
|
for (let pid of processMap.keys()) {
|
|
processMap.get(pid).memory = memory ? memory[pid - 1] : 1;
|
|
}
|
|
},
|
|
};
|
|
|
|
let unloadTests = [
|
|
// Each item in the array represents one test. The test is a subarray
|
|
// containing an element per tab. This is a string of keywords that
|
|
// identify which criteria apply. The first part of the string may contain
|
|
// a number that represents the last visit time, where higher numbers
|
|
// are later. The last element in the subarray is special and identifies
|
|
// the expected order of the tabs sorted by weight. The first tab in
|
|
// this list is the one that is expected to selected to be discarded.
|
|
{ tabs: ["1 selected", "2", "3"], result: "1,2,0" },
|
|
{ tabs: ["1", "2 selected", "3"], result: "0,2,1" },
|
|
{ tabs: ["1 selected", "2", "3"], process: ["1", "2", "3"], result: "1,2,0" },
|
|
{
|
|
tabs: ["1 selected", "2 selected", "3 selected"],
|
|
process: ["1", "2", "3"],
|
|
result: "0,1,2",
|
|
},
|
|
{
|
|
tabs: ["1 selected", "2", "3"],
|
|
process: ["1,2,3", "2", "3"],
|
|
result: "1,2,0",
|
|
},
|
|
{
|
|
tabs: ["9", "8", "6", "5 selected", "2", "3", "4", "1"],
|
|
result: "7,4,5,6,2,1,0,3",
|
|
},
|
|
{
|
|
tabs: ["9", "8 pinned", "6", "5 selected", "2", "3 pinned", "4", "1"],
|
|
result: "7,4,6,2,0,5,1,3",
|
|
},
|
|
{
|
|
tabs: [
|
|
"9",
|
|
"8 pinned",
|
|
"6",
|
|
"5 selected pinned",
|
|
"2",
|
|
"3 pinned",
|
|
"4",
|
|
"1",
|
|
],
|
|
result: "7,4,6,2,0,5,1,3",
|
|
},
|
|
{
|
|
tabs: [
|
|
"9",
|
|
"8 pinned",
|
|
"6",
|
|
"5 selected pinned",
|
|
"2",
|
|
"3 selected pinned",
|
|
"4",
|
|
"1",
|
|
],
|
|
result: "7,4,6,2,0,1,5,3",
|
|
},
|
|
{
|
|
tabs: ["1", "2 selected", "3", "4 media", "5", "6"],
|
|
result: "0,2,4,5,1,3",
|
|
},
|
|
{
|
|
tabs: ["1 media", "2 selected media", "3", "4 media", "5", "6"],
|
|
result: "2,4,5,0,3,1",
|
|
},
|
|
{
|
|
tabs: ["1 media", "2 media pinned", "3", "4 media", "5 pinned", "6"],
|
|
result: "2,5,4,0,3,1",
|
|
},
|
|
{
|
|
tabs: [
|
|
"1 media",
|
|
"2 media pinned",
|
|
"3",
|
|
"4 media",
|
|
"5 media pinned",
|
|
"6 selected",
|
|
],
|
|
result: "2,0,3,5,1,4",
|
|
},
|
|
{
|
|
// Since TestTabUnloaderMethods.getNow() returns 100 and the test
|
|
// passes minInactiveDuration = 0 to TabUnloader.getSortedTabs(),
|
|
// tab 200 and 300 are excluded from the result.
|
|
tabs: ["300", "10", "50", "100", "200"],
|
|
result: "1,2,3",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6"],
|
|
process: ["1", "2", "1", "1", "1", "1"],
|
|
result: "1,0,2,3,4,5",
|
|
},
|
|
{
|
|
tabs: ["1", "2 selected", "3", "4", "5", "6"],
|
|
process: ["1", "2", "1", "1", "1", "1"],
|
|
result: "0,2,3,4,5,1",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6"],
|
|
process: ["1", "2", "2", "1", "1", "1"],
|
|
result: "0,1,2,3,4,5",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6"],
|
|
process: ["1", "2", "3", "1", "1", "1"],
|
|
result: "1,0,2,3,4,5",
|
|
},
|
|
{
|
|
tabs: ["1", "2 media", "3", "4", "5", "6"],
|
|
process: ["1", "2", "3", "1", "1", "1"],
|
|
result: "2,0,3,4,5,1",
|
|
},
|
|
{
|
|
tabs: ["1", "2 media", "3", "4", "5", "6"],
|
|
process: ["1", "2", "3", "1", "1,2,3", "1"],
|
|
result: "0,2,3,4,5,1",
|
|
},
|
|
{
|
|
tabs: ["1", "2 media", "3", "4", "5", "6"],
|
|
process: ["1", "2", "3", "1", "1,4,5", "1"],
|
|
result: "2,0,3,4,5,1",
|
|
},
|
|
{
|
|
tabs: ["1", "2 media", "3 media", "4", "5 media", "6"],
|
|
process: ["1", "2", "3", "1", "1,4,5", "1"],
|
|
result: "0,3,5,1,2,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2 media", "3 media", "4", "5 media", "6"],
|
|
process: ["1", "1", "3", "1", "1,4,5", "1"],
|
|
result: "0,3,5,1,2,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2 media", "3 media", "4", "5 media", "6"],
|
|
process: ["1", "2", "3", "4", "1,4,5", "5"],
|
|
result: "0,3,5,1,2,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2 media", "3 media", "4", "5 media", "6"],
|
|
process: ["1", "1", "3", "4", "1,4,5", "5"],
|
|
result: "0,3,5,1,2,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6"],
|
|
process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1"],
|
|
result: "0,1,2,3,4,5",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
|
process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1", "1", "1"],
|
|
result: "4,0,3,1,2,5,6,7",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 selected", "6"],
|
|
process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1"],
|
|
result: "0,1,2,3,5,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 media", "6"],
|
|
process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1"],
|
|
result: "0,1,2,3,5,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
|
|
process: ["1", "1", "1", "2", "1,3,4,5,6,7,8", "1", "1", "1"],
|
|
result: "0,3,1,2,5,6,7,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
|
|
process: ["1", "1,3,4,5,6,7,8", "1", "1", "1", "1", "1", "1"],
|
|
result: "1,0,2,3,5,6,7,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
|
|
process: ["1", "1", "1,3,4,5,6,7,8", "1", "1", "1", "1", "1"],
|
|
result: "2,0,1,3,5,6,7,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
|
|
process: ["1", "1", "1,1,1,1,1,1,1", "1", "1", "1", "1,1,1,1,1", "1"],
|
|
result: "0,1,2,3,5,6,7,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
|
|
process: ["1", "1", "1,2,3,4,5", "1", "1", "1", "1,2,3,4,5", "1"],
|
|
result: "0,1,2,3,5,6,7,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
|
|
process: ["1", "1", "1,6", "1", "1", "1", "1,2,3,4,5", "1"],
|
|
result: "0,2,1,3,5,6,7,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
|
|
process: ["1", "1", "1,6", "1,7", "1,8", "1,9", "1,2,3,4,5", "1"],
|
|
result: "2,3,0,5,1,6,7,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5 media", "6", "7", "8"],
|
|
process: ["1,10,11", "1", "1,2", "1,7", "1,8", "1,9", "1,2,3,4,5", "1"],
|
|
result: "0,3,1,5,2,6,7,4",
|
|
},
|
|
{
|
|
tabs: [
|
|
"1 media",
|
|
"2 media",
|
|
"3 media",
|
|
"4 media",
|
|
"5 media",
|
|
"6",
|
|
"7",
|
|
"8",
|
|
],
|
|
process: ["1,10,11", "1", "1,2", "1,7", "1,8", "1,9", "1,2,3,4,5", "1"],
|
|
result: "6,5,7,0,1,2,3,4",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3"],
|
|
process: ["1", "2", "3"],
|
|
memory: ["100", "200", "300"],
|
|
result: "0,1,2",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
|
|
process: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
|
|
memory: [
|
|
"100",
|
|
"200",
|
|
"300",
|
|
"400",
|
|
"500",
|
|
"600",
|
|
"700",
|
|
"800",
|
|
"900",
|
|
"1000",
|
|
],
|
|
result: "0,1,2,3,4,5,6,7,8,9",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
|
|
process: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
|
|
memory: [
|
|
"100",
|
|
"900",
|
|
"300",
|
|
"500",
|
|
"400",
|
|
"700",
|
|
"600",
|
|
"1000",
|
|
"200",
|
|
"200",
|
|
],
|
|
result: "1,0,2,3,5,4,6,7,8,9",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
|
|
process: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
|
|
memory: [
|
|
"1000",
|
|
"900",
|
|
"300",
|
|
"500",
|
|
"400",
|
|
"1000",
|
|
"600",
|
|
"1000",
|
|
"200",
|
|
"200",
|
|
],
|
|
result: "0,1,2,3,5,4,6,7,8,9",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6"],
|
|
process: ["1", "2,7", "3", "4", "5", "6"],
|
|
memory: ["100", "200", "300", "400", "500", "600", "700"],
|
|
result: "1,0,2,3,4,5",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
|
process: ["1,6", "2,7", "3,8", "4,1,2", "5", "6", "7", "8"],
|
|
memory: ["100", "200", "300", "400", "500", "600", "700", "800"],
|
|
result: "2,3,0,1,4,5,6,7",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
|
process: ["1", "1", "1", "2", "1", "1", "1", "1"],
|
|
memory: ["700", "1000"],
|
|
result: "0,3,1,2,4,5,6,7",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
|
process: ["1", "1", "1", "1", "2,1", "2,1", "3", "3"],
|
|
memory: ["1000", "2000", "3000"],
|
|
result: "0,1,2,4,3,5,6,7",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
|
process: ["2", "2", "2", "2", "2,1", "2,1", "3", "3"],
|
|
memory: ["1000", "600", "1000"],
|
|
result: "0,1,2,4,3,5,6,7",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
|
process: ["1", "1", "1", "2", "2,1,1,1", "2,1", "3", "3"],
|
|
memory: ["1000", "1800", "1000"],
|
|
result: "0,1,3,2,4,5,6,7",
|
|
},
|
|
{
|
|
tabs: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
|
process: ["1", "1", "1", "2", "2,1,1,1", "2,1", "3", "3"],
|
|
memory: ["4000", "1800", "1000"],
|
|
result: "0,1,2,4,3,5,6,7",
|
|
},
|
|
{
|
|
// The tab "1" contains 4 frames, but its uniqueCount is 1 because
|
|
// all of those frames are backed by the process "1". As a result,
|
|
// TabUnloader puts the tab "1" first based on the last access time.
|
|
tabs: ["1", "2", "3", "4", "5"],
|
|
process: ["1,1,1,1", "2", "3", "3", "3"],
|
|
memory: ["100", "100", "100"],
|
|
result: "0,1,2,3,4",
|
|
},
|
|
{
|
|
// The uniqueCount of the tab "1", "2", and "3" is 1, 2, and 3,
|
|
// respectively. As a result the first three tabs are sorted as 2,1,0.
|
|
tabs: ["1", "2", "3", "4", "5", "6"],
|
|
process: ["1,7,1,7,1,1,7,1", "7,3,7,2", "4,5,7,4,6,7", "7", "7", "7"],
|
|
memory: ["100", "100", "100", "100", "100", "100", "100"],
|
|
result: "2,1,0,3,4,5",
|
|
},
|
|
];
|
|
|
|
let globalBrowser = {
|
|
discardBrowser() {
|
|
return true;
|
|
},
|
|
};
|
|
|
|
add_task(async function doTests() {
|
|
for (let test of unloadTests) {
|
|
function* iterateTabs() {
|
|
let tabs = test.tabs;
|
|
for (let t = 0; t < tabs.length; t++) {
|
|
let tab = {
|
|
tab: {
|
|
originalIndex: t,
|
|
lastAccessed: Number(/^[0-9]+/.exec(tabs[t])[0]),
|
|
keywords: tabs[t],
|
|
process: "process" in test ? test.process[t] : "1",
|
|
},
|
|
memory: test.memory,
|
|
gBrowser: globalBrowser,
|
|
};
|
|
yield tab;
|
|
}
|
|
}
|
|
TestTabUnloaderMethods.iterateTabs = iterateTabs;
|
|
|
|
let expectedOrder = "";
|
|
const sortedTabs = await TabUnloader.getSortedTabs(
|
|
0,
|
|
TestTabUnloaderMethods
|
|
);
|
|
for (let tab of sortedTabs) {
|
|
if (expectedOrder) {
|
|
expectedOrder += ",";
|
|
}
|
|
expectedOrder += tab.tab.originalIndex;
|
|
}
|
|
|
|
Assert.equal(expectedOrder, test.result);
|
|
}
|
|
});
|