fune/browser/components/tabunloader/content/aboutUnloads.js
Toshihito Kikuchi 16a8fe4d37 Bug 1729911 - Define minInactiveDurationInMS not to unload fresh tabs. r=NeilDeakin
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
2021-10-20 23:22:57 +00:00

127 lines
3.6 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { TabUnloader } = ChromeUtils.import(
"resource:///modules/TabUnloader.jsm"
);
async function refreshData() {
const sortedTabs = await TabUnloader.getSortedTabs(null);
const tabTable = document.querySelector(".tab-table > tbody");
const getHost = uri => {
try {
return uri?.host;
} catch (e) {
return uri?.spec;
}
};
const updateTimestamp = () => {
document.l10n.setAttributes(
document.getElementById("label-last-updated"),
"about-unloads-last-updated",
{ date: Date.now() }
);
};
// Reset the table
// Don't delete the first row showing the "no unloadable tab" message
while (tabTable.rows.length > 1) {
tabTable.deleteRow(1);
}
if (!sortedTabs.length) {
document.getElementById("button-unload").disabled = true;
document.getElementById("no-unloadable-tab-message").hidden = false;
updateTimestamp();
return;
}
document.getElementById(
"button-unload"
).disabled = !TabUnloader.isDiscardable(sortedTabs[0]);
document.getElementById("no-unloadable-tab-message").hidden = true;
const fragmentRows = new DocumentFragment();
const templateRow = document.querySelector("template[name=tab-table-row]");
let ordinal = 0;
for (const tabInfo of sortedTabs) {
if (!("tab" in tabInfo)) {
continue;
}
const fragment = templateRow.content.cloneNode(true);
const row = fragment.querySelector("tr");
row.children[0].textContent = TabUnloader.isDiscardable(tabInfo)
? ++ordinal
: "-";
row.children[1].textContent = getHost(
tabInfo.tab?.linkedBrowser?.currentURI
);
if ("lastAccessed" in tabInfo.tab) {
document.l10n.setAttributes(
row.children[2],
"about-unloads-last-accessed",
{ date: tabInfo.tab.lastAccessed }
);
}
row.children[3].textContent = tabInfo.weight;
row.children[4].textContent = tabInfo.sortWeight;
if ("memory" in tabInfo) {
document.l10n.setAttributes(
row.children[5],
"about-unloads-memory-in-mb",
{ mem: tabInfo.memory / 1024 / 1024 }
);
}
if (tabInfo.processes) {
for (const [pid, procEntry] of tabInfo.processes) {
if (pid < 0) {
// Tab is hosted by the main process
continue;
}
const procLabel = document.createElement("span");
const procInfo = procEntry.entryToProcessMap;
if (procEntry.isTopLevel) {
procLabel.classList.add("top-level-process");
}
if (procInfo.tabSet.size > 1) {
procLabel.classList.add("shared-process");
}
procLabel.textContent = pid;
document.l10n.setAttributes(
procLabel,
"about-unloads-memory-in-mb-tooltip",
{ mem: procInfo.memory / 1024 / 1024 }
);
row.children[6].appendChild(procLabel);
row.children[6].appendChild(document.createTextNode(" "));
}
}
fragmentRows.appendChild(fragment);
}
tabTable.appendChild(fragmentRows);
updateTimestamp();
}
async function onLoad() {
document
.getElementById("button-unload")
.addEventListener("click", async () => {
await TabUnloader.unloadLeastRecentlyUsedTab(null);
await refreshData();
});
await refreshData();
}
try {
document.addEventListener("DOMContentLoaded", onLoad, { once: true });
} catch (ex) {
Cu.reportError(ex);
}