Backed out 2 changesets (bug 1632794) for build bustages on ChromeUtils.cpp . CLOSED TREE

Backed out changeset 846b78435f92 (bug 1632794)
Backed out changeset 937d7ef96c5d (bug 1632794)
This commit is contained in:
Narcis Beleuzu 2020-05-06 13:00:15 +03:00
Родитель 87df0b2d72
Коммит cdf603f65b
16 изменённых файлов: 19 добавлений и 1109 удалений

Просмотреть файл

@ -101,8 +101,6 @@ static const RedirEntry kRedirMap[] = {
nsIAboutModule::ALLOW_SCRIPT},
{"plugins", "chrome://global/content/plugins.html",
nsIAboutModule::URI_MUST_LOAD_IN_CHILD},
{"processes", "chrome://global/content/aboutProcesses.html",
nsIAboutModule::ALLOW_SCRIPT},
// about:serviceworkers always wants to load in the parent process because
// when dom.serviceWorkers.parent_intercept is set to true (the new default)
// then the only place nsIServiceWorkerManager has any data is in the

Просмотреть файл

@ -36,8 +36,6 @@ if defined('MOZ_CRASHREPORTER'):
about_pages.append('crashes')
if buildconfig.substs['MOZ_WIDGET_TOOLKIT'] != 'android':
about_pages.append('profiles')
if defined('NIGHTLY_BUILD'):
about_pages.append('processes')
Headers = ['/docshell/build/nsDocShellModule.h']

Просмотреть файл

@ -741,12 +741,9 @@ static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
switch (aType) {
PROCTYPE_TO_WEBIDL_CASE(Web, Web);
PROCTYPE_TO_WEBIDL_CASE(WebIsolated, WebIsolated);
PROCTYPE_TO_WEBIDL_CASE(File, File);
PROCTYPE_TO_WEBIDL_CASE(Extension, Extension);
PROCTYPE_TO_WEBIDL_CASE(PrivilegedAbout, Privilegedabout);
PROCTYPE_TO_WEBIDL_CASE(PrivilegedMozilla, Privilegedmozilla);
PROCTYPE_TO_WEBIDL_CASE(WebCOOPCOEP, WithCoopCoep);
PROCTYPE_TO_WEBIDL_CASE(WebLargeAllocation, WebLargeAllocation);
PROCTYPE_TO_WEBIDL_CASE(Browser, Browser);
PROCTYPE_TO_WEBIDL_CASE(Plugin, Plugin);
@ -792,7 +789,7 @@ already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
global->EventTargetFor(TaskCategory::Performance);
// Getting the parent proc info
mozilla::GetProcInfo(parentPid, 0, mozilla::ProcType::Browser, NS_LITERAL_STRING(""))
mozilla::GetProcInfo(parentPid, 0, mozilla::ProcType::Browser)
->Then(
target, __func__,
[target, domPromise, parentPid](ProcInfo aParentInfo) {
@ -806,7 +803,7 @@ already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
if (!aGeckoProcess->GetChildProcessHandle()) {
return;
}
nsAutoString origin;
base::ProcessId childPid =
base::GetProcId(aGeckoProcess->GetChildProcessHandle());
int32_t childId = 0;
@ -826,51 +823,22 @@ already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
if (!contentParent) {
return;
}
// Converting the remoteType into a ProcType.
// Ideally, the remoteType should be strongly typed
// upstream, this would make the conversion less brittle.
nsAutoString remoteType(contentParent->GetRemoteType());
if (StringBeginsWith(
remoteType,
NS_LITERAL_STRING(FISSION_WEB_REMOTE_TYPE))) {
// WARNING: Do not change the order, as
// `DEFAULT_REMOTE_TYPE` is a prefix of
// `FISSION_WEB_REMOTE_TYPE`.
type = mozilla::ProcType::WebIsolated;
} else if (StringBeginsWith(
remoteType,
NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE))) {
// Converting the Content Type into a ProcType
nsAutoString processType;
processType.Assign(contentParent->GetRemoteType());
if (IsWebRemoteType(processType)) {
type = mozilla::ProcType::Web;
} else if (remoteType.EqualsLiteral(FILE_REMOTE_TYPE)) {
} else if (processType.EqualsLiteral(FILE_REMOTE_TYPE)) {
type = mozilla::ProcType::File;
} else if (remoteType.EqualsLiteral(
} else if (processType.EqualsLiteral(
EXTENSION_REMOTE_TYPE)) {
type = mozilla::ProcType::Extension;
} else if (remoteType.EqualsLiteral(
} else if (processType.EqualsLiteral(
PRIVILEGEDABOUT_REMOTE_TYPE)) {
type = mozilla::ProcType::PrivilegedAbout;
} else if (remoteType.EqualsLiteral(
PRIVILEGEDMOZILLA_REMOTE_TYPE)) {
type = mozilla::ProcType::PrivilegedMozilla;
} else if (StringBeginsWith(
remoteType,
NS_LITERAL_STRING(
WITH_COOP_COEP_REMOTE_TYPE_PREFIX))) {
type = mozilla::ProcType::WebCOOPCOEP;
} else if (remoteType.EqualsLiteral(
} else if (processType.EqualsLiteral(
LARGE_ALLOCATION_REMOTE_TYPE)) {
type = mozilla::ProcType::WebLargeAllocation;
} else {
MOZ_CRASH("Unknown remoteType");
}
// By convention, everything after '=' is the origin.
nsAString::const_iterator cursor;
nsAString::const_iterator end;
remoteType.BeginReading(cursor);
remoteType.EndReading(end);
if (FindCharInReadable(u'=', cursor, end)) {
origin = Substring(++cursor, end);
}
childId = contentParent->ChildID();
break;
@ -911,10 +879,10 @@ already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
promises.AppendElement(
#ifdef XP_MACOSX
mozilla::GetProcInfo(childPid, childId, type, origin,
mozilla::GetProcInfo(childPid, childId, type,
aGeckoProcess->GetChildTask())
#else
mozilla::GetProcInfo(childPid, childId, type, origin)
mozilla::GetProcInfo(childPid, childId, type)
#endif
);
});
@ -960,7 +928,6 @@ already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
// Basic info.
childProcInfo->mChildID = info.childId;
childProcInfo->mType = ProcTypeToWebIDL(info.type);
childProcInfo->mOrigin = info.origin;
childProcInfo->mPid = info.pid;
childProcInfo->mFilename.Assign(info.filename);
childProcInfo->mVirtualMemorySize = info.virtualMemorySize;

Просмотреть файл

@ -498,13 +498,10 @@ partial namespace ChromeUtils {
*/
enum WebIDLProcType {
"web",
"webIsolated",
"file",
"extension",
"privilegedabout",
"privilegedmozilla",
"webLargeAllocation",
"withCoopCoep",
"browser",
"plugin",
"ipdlUnitTest",
@ -544,7 +541,6 @@ dictionary ChildProcInfoDictionary {
sequence<ThreadInfoDictionary> threads = [];
// Firefox info
unsigned long long ChildID = 0;
DOMString origin = "";
WebIDLProcType type = "web";
};

Просмотреть файл

@ -1,157 +0,0 @@
/* 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/. */
@import url("chrome://global/skin/in-content/common.css");
html {
background-color: var(--in-content-page-background);
}
body {
overflow-x: hidden;
}
#process-table {
-moz-user-select: none;
font-size: 1em;
border-spacing: 0;
background-color: var(--in-content-box-background);
margin: 0;
position: absolute;
top: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
min-width: 40em;
}
/* Avoid scrolling the header */
#process-tbody {
display: block;
margin-top: 2em;
}
#process-thead {
position: fixed;
z-index: 1;
height: 2em;
border-bottom: 1px solid var(--in-content-border-color);
min-width: 40em;
background-color: var(--in-content-box-background);
}
tr {
display: table;
table-layout: fixed;
width: 100%;
}
td:nth-child(1) {
width: 6%;
}
/* At least one column needs to have a flexible width,
so no width specified for td:nth-child(2) */
td:nth-child(3) {
width: 10%;
}
td:nth-child(4) {
width: 10%;
}
td:nth-child(5) {
width: 10%;
}
td:nth-child(6) {
width: 10%;
}
td:nth-child(7) {
width: 2%;
}
#process-thead > tr {
height: inherit;
}
#process-thead > tr > td {
border: none;
background-color: var(--in-content-button-background);
}
#process-thead > tr > td:not(:first-child) {
border-inline-start-width: 1px;
border-inline-start-style: solid;
border-image: linear-gradient(transparent 0%, transparent 20%, var(--in-content-box-border-color) 20%, var(--in-content-box-border-color) 80%, transparent 80%, transparent 100%) 1 1;
border-bottom: 1px solid var(--in-content-border-color);
}
td {
padding: 5px 10px;
min-height: 2em;
color: var(--in-content-text-color);
max-width: 70vw;
overflow: hidden;
white-space: nowrap;
}
#process-tbody > tr > td:first-child {
text-overflow: ellipsis;
}
.twisty {
margin-inline: -10px 0px;
padding-inline: 18px;
position: relative;
}
/* Putting the background image in a positioned pseudo element lets us
* use CSS transforms on the background image, which we need for rtl. */
.twisty::before {
content: url("chrome://global/skin/icons/twisty-collapsed.svg");
position: absolute;
display: block;
line-height: 50%;
top: 4px; /* Half the image's height */
left: 0;
width: 100%;
text-align: center;
-moz-context-properties: fill;
fill: currentColor;
}
.twisty:dir(rtl)::before {
transform: scaleX(-1);
}
.twisty.open::before {
content: url("chrome://global/skin/icons/twisty-expanded.svg");
}
#process-tbody > tr > td.indent {
padding-inline: 36px 0;
}
#process-tbody > tr[selected] > td {
background-color: var(--in-content-item-selected);
color: var(--in-content-selected-text);
}
#process-tbody > tr:hover {
background-color: var(--in-content-item-hover);
}
.clickable {
background-repeat: no-repeat;
background-position: right 4px center;
}
.clickable:dir(rtl) {
background-position-x: left 4px;
}
.asc {
background-image: url(chrome://global/skin/icons/arrow-up-12.svg);
-moz-context-properties: fill;
fill: currentColor;
}
.desc {
background-image: url(chrome://global/skin/icons/arrow-dropdown-12.svg);
-moz-context-properties: fill;
fill: currentColor;
}
#process-thead > tr > td.clickable:hover {
background-color: var(--in-content-button-background-hover);
}
#process-thead > tr > td.clickable:active {
background-color: var(--in-content-button-background-active);
}
#process-tbody > tr.process {
font-weight: bold;
}
#process-tbody > tr.thread {
font-size-adjust: 0.5;
}

Просмотреть файл

@ -1,18 +0,0 @@
# 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/.
# Page title
about-processes-title = Process Manager
## Column headers
about-processes-column-id = Id
about-processes-column-type = Type
about-processes-column-name = Name
about-processes-column-memory-resident = Memory (Resident)
about-processes-column-memory-virtual = Memory (Virtual)
about-processes-column-cpu-user = CPU (User)
about-processes-column-cpu-kernel = CPU (Kernel)
about-processes-column-cpu-threads = CPU (Threads)
about-processes-column-threads = Threads

Просмотреть файл

@ -1,31 +0,0 @@
<!-- 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/. -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src chrome:;img-src data:; object-src 'none'">
<title data-l10n-id="about-processes-title"></title>
<link rel="icon" id="favicon" href="chrome://global/skin/icons/performance.svg">
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
<link rel="localization" href="preview/aboutProcesses.ftl">
<script src="chrome://global/content/aboutProcesses.js"></script>
<link rel="stylesheet" href="chrome://global/content/aboutProcesses.css">
</head>
<body>
<table id="process-table">
<thead id="process-thead">
<tr>
<td class="clickable" id="column-pid" data-l10n-id="about-processes-column-id"></td>
<td class="clickable" id="column-name" data-l10n-id="about-processes-column-name"></td>
<td class="clickable" id="column-memory-resident" data-l10n-id="about-processes-column-memory-resident"></td> <!-- Memory usage. -->
<td class="clickable" id="column-memory-virtual" data-l10n-id="about-processes-column-memory-virtual"></td> <!-- Memory usage. -->
<td class="clickable" id="column-cpu-user" data-l10n-id="about-processes-column-cpu-user"></td> <!-- CPU user. -->
<td class="clickable" id="column-cpu-kernel" data-l10n-id="about-processes-column-cpu-kernel"></td> <!-- CPU kernel. -->
<td class="clickable" id="column-cpu-threads" data-l10n-id="about-processes-column-threads"></td>
</tr>
</thead>
<tbody id="process-tbody"></tbody>
</table>
</body>
</html>

Просмотреть файл

@ -1,790 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-*/
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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";
// Time in ms before we start changing the sort order again after receiving a
// mousemove event.
const TIME_BEFORE_SORTING_AGAIN = 5000;
// How often we should add a sample to our buffer.
const BUFFER_SAMPLING_RATE_MS = 1000;
// The age of the oldest sample to keep.
const BUFFER_DURATION_MS = 10000;
// How often we should update
const UPDATE_INTERVAL_MS = 2000;
const MS_PER_NS = 1000000;
const NS_PER_S = 1000000000;
const ONE_GIGA = 1024 * 1024 * 1024;
const ONE_MEGA = 1024 * 1024;
const ONE_KILO = 1024;
/**
* Returns a Promise that's resolved after the next turn of the event loop.
*
* Just returning a resolved Promise would mean that any `then` callbacks
* would be called right after the end of the current turn, so `setTimeout`
* is used to delay Promise resolution until the next turn.
*
* In mochi tests, it's possible for this to be called after the
* about:performance window has been torn down, which causes `setTimeout` to
* throw an NS_ERROR_NOT_INITIALIZED exception. In that case, returning
* `undefined` is fine.
*/
function wait(ms = 0) {
try {
let resolve;
let p = new Promise(resolve_ => {
resolve = resolve_;
});
setTimeout(resolve, ms);
return p;
} catch (e) {
dump(
"WARNING: wait aborted because of an invalid Window state in aboutPerformance.js.\n"
);
return undefined;
}
}
/**
* Utilities for dealing with state
*/
var State = {
/**
* Indexed by the number of minutes since the snapshot was taken.
*
* @type {Array<ApplicationSnapshot>}
*/
_buffer: [],
/**
* The latest snapshot.
*
* @type ApplicationSnapshot
*/
_latest: null,
async _promiseSnapshot() {
let main = await ChromeUtils.requestProcInfo();
let processes = new Map();
processes.set(main.pid, main);
for (let child of main.children) {
processes.set(child.pid, child);
}
return { processes, date: Cu.now() };
},
/**
* Update the internal state.
*
* @return {Promise}
*/
async update() {
// If the buffer is empty, add one value for bootstraping purposes.
if (!this._buffer.length) {
this._latest = await this._promiseSnapshot();
this._buffer.push(this._latest);
await wait(BUFFER_SAMPLING_RATE_MS * 1.1);
}
let now = Cu.now();
// If we haven't sampled in a while, add a sample to the buffer.
let latestInBuffer = this._buffer[this._buffer.length - 1];
let deltaT = now - latestInBuffer.date;
if (deltaT > BUFFER_SAMPLING_RATE_MS) {
this._latest = await this._promiseSnapshot();
this._buffer.push(this._latest);
}
// If we have too many samples, remove the oldest sample.
let oldestInBuffer = this._buffer[0];
if (oldestInBuffer.date + BUFFER_DURATION_MS < this._latest.date) {
this._buffer.shift();
}
},
_getThreadDelta(cur, prev, deltaT) {
let name = cur.name || "???";
let result = {
tid: cur.tid,
name,
// Total amount of CPU used, in ns (user).
totalCpuUser: cur.cpuUser,
slopeCpuUser: null,
// Total amount of CPU used, in ns (kernel).
totalCpuKernel: cur.cpuKernel,
slopeCpuKernel: null,
};
if (!prev) {
return result;
}
if (prev.tid != cur.tid) {
throw new Error("Assertion failed: A thread cannot change tid.");
}
result.slopeCpuUser = (cur.cpuUser - prev.cpuUser) / deltaT;
result.slopeCpuKernel = (cur.cpuKernel - prev.cpuKernel) / deltaT;
return result;
},
/**
* Compute the delta between two process snapshots.
*
* @param {ProcessSnapshot} cur
* @param {ProcessSnapshot?} prev
* @param {Number?} deltaT A number of nanoseconds elapsed between `cur` and `prev`.
*/
_getProcessDelta(cur, prev, deltaT) {
let result = {
pid: cur.pid,
filename: cur.filename,
totalVirtualMemorySize: cur.virtualMemorySize,
deltaVirtualMemorySize: null,
totalResidentSize: cur.residentSetSize,
deltaResidentSize: null,
totalCpuUser: cur.cpuUser,
slopeCpuUser: null,
totalCpuKernel: cur.cpuKernel,
slopeCpuKernel: null,
type: cur.type,
origin: cur.origin || "",
threads: null,
};
if (!prev) {
result.threads = cur.threads.map(data =>
this._getThreadDelta(data, null, null)
);
return result;
}
if (prev.pid != cur.pid) {
throw new Error("Assertion failed: A process cannot change pid.");
}
if (prev.type != cur.type) {
throw new Error("Assertion failed: A process cannot change type.");
}
let prevThreads = new Map();
for (let thread of prev.threads) {
prevThreads.set(thread.tid, thread);
}
let threads = cur.threads.map(curThread => {
let prevThread = prevThreads.get(curThread.tid);
if (!prevThread) {
return this._getThreadDelta(curThread);
}
return this._getThreadDelta(curThread, prevThread, deltaT);
});
result.deltaVirtualMemorySize =
cur.virtualMemorySize - prev.virtualMemorySize;
result.deltaResidentSize = cur.residentSetSize - prev.residentSetSize;
result.slopeCpuUser = (cur.cpuUser - prev.cpuUser) / deltaT;
result.slopeCpuKernel = (cur.cpuKernel - prev.cpuKernel) / deltaT;
result.threads = threads;
return result;
},
getCounters() {
// We rebuild the maps during each iteration to make sure that
// we do not maintain references to processes that have been
// shutdown.
let previous = this._buffer[Math.max(this._buffer.length - 2, 0)];
let current = this._latest;
let counters = [];
for (let cur of current.processes.values()) {
// Look for the oldest point of comparison
let oldest = null;
let delta;
for (let index = 0; index <= this._buffer.length - 2; ++index) {
oldest = this._buffer[index].processes.get(cur.pid);
if (oldest) {
// Found it!
break;
}
}
if (oldest) {
// Existing process. Let's display slopes info.
delta = this._getProcessDelta(
cur,
oldest,
(current.date - previous.date) * MS_PER_NS
);
} else {
// New process. Let's display basic info.
delta = this._getProcessDelta(cur, null, null);
}
counters.push(delta);
}
return counters;
},
};
var View = {
_fragment: document.createDocumentFragment(),
async commit() {
let tbody = document.getElementById("process-tbody");
// Force translation to happen before we insert the new content in the DOM
// to avoid flicker when resizing.
await document.l10n.translateFragment(this._fragment);
while (tbody.firstChild) {
tbody.firstChild.remove();
}
tbody.appendChild(this._fragment);
this._fragment = document.createDocumentFragment();
},
insertAfterRow(row) {
row.parentNode.insertBefore(this._fragment, row.nextSibling);
this._fragment = document.createDocumentFragment();
},
/**
* Append a row showing a single process (without its threads).
*
* @param {ProcessDelta} data The data to display.
* @param {bool} isOpen `true` if we're also displaying the threads of this process, `false` otherwise.
* @return {DOMElement} The row displaying the process.
*/
appendProcessRow(data, isOpen) {
let row = document.createElement("tr");
row.classList.add("process");
// Column: pid / twisty image
{
let elt = this._addCell(row, {
content: data.pid,
classes: ["pid", "root"],
});
if (data.threads.length) {
let img = document.createElement("span");
img.classList.add("twisty", "process");
if (isOpen) {
img.classList.add("open");
}
elt.insertBefore(img, elt.firstChild);
}
}
// Column: type
{
let content = data.origin ? `${data.origin} (${data.type})` : data.type;
this._addCell(row, {
content,
classes: ["type"],
});
}
// Column: Resident size
{
let { formatedDelta, formatedValue } = this._formatMemoryAndDelta(
data.totalResidentSize,
data.deltaResidentSize
);
let content = formatedDelta
? `${formatedValue}${formatedDelta}`
: formatedValue;
this._addCell(row, {
content,
classes: ["totalResidentSize"],
});
}
// Column: VM size
{
let { formatedDelta, formatedValue } = this._formatMemoryAndDelta(
data.totalVirtualMemorySize,
data.deltaVirtualMemorySize
);
let content = formatedDelta
? `${formatedValue}${formatedDelta}`
: formatedValue;
this._addCell(row, {
content,
classes: ["totalVirtualMemorySize"],
});
}
// Column: CPU: User
{
let slope = this._formatPercentage(data.slopeCpuUser);
let content = `${slope} (${(
data.totalCpuUser / MS_PER_NS
).toLocaleString(undefined, { maximumFractionDigits: 0 })}ms)`;
this._addCell(row, {
content,
classes: ["cpuUser"],
});
}
// Column: CPU: Kernel
{
let slope = this._formatPercentage(data.slopeCpuKernel);
let content = `${slope} (${(
data.totalCpuKernel / MS_PER_NS
).toLocaleString(undefined, { maximumFractionDigits: 0 })}ms)`;
this._addCell(row, {
content,
classes: ["cpuKernel"],
});
}
// Column: Number of threads
this._addCell(row, {
content: data.threads.length,
classes: ["numberOfThreads"],
});
this._fragment.appendChild(row);
return row;
},
/**
* Append a row showing a single thread.
*
* @param {ThreadDelta} data The data to display.
* @return {DOMElement} The row displaying the thread.
*/
appendThreadRow(data) {
let row = document.createElement("tr");
row.classList.add("thread");
// Column: id
this._addCell(row, {
content: data.tid,
classes: ["tid", "indent"],
});
// Column: filename
this._addCell(row, {
content: data.name,
classes: ["name"],
});
// Column: Resident size (empty)
this._addCell(row, {
content: "",
classes: ["totalResidentSize"],
});
// Column: VM size (empty)
this._addCell(row, {
content: "",
classes: ["totalVirtualMemorySize"],
});
// Column: CPU: User
{
let slope = this._formatPercentage(data.slopeCpuUser);
let text = `${slope} (${(
data.totalCpuUser / MS_PER_NS
).toLocaleString(undefined, { maximumFractionDigits: 0 })} ms)`;
this._addCell(row, {
content: text,
classes: ["cpuUser"],
});
}
// Column: CPU: Kernel
{
let slope = this._formatPercentage(data.slopeCpuKernel);
let text = `${slope} (${(
data.totalCpuKernel / MS_PER_NS
).toLocaleString(undefined, { maximumFractionDigits: 0 })} ms)`;
this._addCell(row, {
content: text,
classes: ["cpuKernel"],
});
}
// Column: Number of threads (empty)
this._addCell(row, {
content: "",
classes: ["numberOfThreads"],
});
this._fragment.appendChild(row);
return row;
},
_addCell(row, { content, classes }) {
let elt = document.createElement("td");
this._setTextAndTooltip(elt, content);
elt.classList.add(...classes);
row.appendChild(elt);
return elt;
},
/**
* Utility method to format an optional percentage.
*
* As a special case, we also handle `null`, which represents the case in which we do
* not have sufficient information to compute a percentage.
*
* @param {Number?} value The value to format. Must be either `null` or a non-negative number.
* A value of 1 means 100%. A value larger than 1 is possible as processes can use several
* cores.
* @return {String}
*/
_formatPercentage(value) {
if (value == null) {
return "?";
}
if (value < 0 || typeof value != "number") {
throw new Error(`Invalid percentage value ${value}`);
}
if (value == 0) {
// Let's make sure that we do not confuse idle and "close to 0%",
// otherwise this results in weird displays.
return "idle";
}
// Now work with actual percentages.
let percentage = value * 100;
if (percentage < 0.01) {
// Tiny percentage, let's display something more useful than "0".
return "~0%";
}
if (percentage < 1) {
// Still a small percentage, but it should fit within 2 digits.
return `${percentage.toLocaleString(undefined, {
maximumFractionDigits: 2,
})}%`;
}
// For other percentages, just return a round number.
return `${Math.round(percentage)}%`;
},
/**
* Format a value representing an amount of memory.
*
* As a special case, we also handle `null`, which represents the case in which we do
* not have sufficient information to compute an amount of memory.
*
* @param {Number?} value The value to format. Must be either `null` or a non-negative number.
* @return { {unit: "GB" | "MB" | "KB" | B" | "?"}, amount: Number } The formated amount and its
* unit, which may be used for e.g. additional CSS formating.
*/
_formatMemory(value) {
if (value == null) {
return { unit: "?", amount: 0 };
}
if (value < 0 || typeof value != "number") {
throw new Error(`Invalid memory value ${value}`);
}
if (value >= ONE_GIGA) {
return {
unit: "GB",
amount: Math.ceil((value / ONE_GIGA) * 100) / 100,
};
}
if (value >= ONE_MEGA) {
return {
unit: "MB",
amount: Math.ceil((value / ONE_MEGA) * 100) / 100,
};
}
if (value >= ONE_KILO) {
return {
unit: "KB",
amount: Math.ceil((value / ONE_KILO) * 100) / 100,
};
}
return {
unit: "B",
amount: Math.round(value),
};
},
/**
* Format a value representing an amount of memory and a delta.
*
* @param {Number?} value The value to format. Must be either `null` or a non-negative number.
* @param {Number?} value The delta to format. Must be either `null` or a non-negative number.
* @return {
* {unitValue: "GB" | "MB" | "KB" | B" | "?"},
* formatedValue: string,
* {unitDelta: "GB" | "MB" | "KB" | B" | "?"},
* formatedDelta: string
* }
*/
_formatMemoryAndDelta(value, delta) {
let formatedDelta;
let unitDelta;
if (delta == null) {
formatedDelta == "";
unitDelta = null;
} else if (delta == 0) {
formatedDelta = null;
unitDelta = null;
} else if (delta >= 0) {
let { unit, amount } = this._formatMemory(delta);
formatedDelta = ` (+${amount}${unit})`;
unitDelta = unit;
} else {
let { unit, amount } = this._formatMemory(-delta);
formatedDelta = ` (-${amount}${unit})`;
unitDelta = unit;
}
let { unit: unitValue, amount } = this._formatMemory(value);
return {
unitValue,
unitDelta,
formatedDelta,
formatedValue: `${amount}${unitValue}`,
};
},
_setTextAndTooltip(elt, text, tooltip = text) {
elt.textContent = text;
elt.setAttribute("title", tooltip);
},
};
var Control = {
_openItems: new Set(),
_sortColumn: null,
_sortAscendent: true,
_removeSubtree(row) {
while (row.nextSibling && row.nextSibling.classList.contains("thread")) {
row.nextSibling.remove();
}
},
init() {
let tbody = document.getElementById("process-tbody");
tbody.addEventListener("click", event => {
this._updateLastMouseEvent();
// Handle showing or hiding subitems of a row.
let target = event.target;
if (target.classList.contains("twisty")) {
let row = target.parentNode.parentNode;
let id = row.process.pid;
if (target.classList.toggle("open")) {
this._openItems.add(id);
this._showChildren(row);
View.insertAfterRow(row);
} else {
this._openItems.delete(id);
this._removeSubtree(row);
}
return;
}
// Handle selection changes
let row = target.parentNode;
if (this.selectedRow) {
this.selectedRow.removeAttribute("selected");
}
if (row.windowId) {
row.setAttribute("selected", "true");
this.selectedRow = row;
} else if (this.selectedRow) {
this.selectedRow = null;
}
});
tbody.addEventListener("mousemove", () => {
this._updateLastMouseEvent();
});
window.addEventListener("visibilitychange", event => {
if (!document.hidden) {
this._updateDisplay(true);
}
});
document
.getElementById("process-thead")
.addEventListener("click", async event => {
if (!event.target.classList.contains("clickable")) {
return;
}
if (this._sortColumn) {
const td = document.getElementById(this._sortColumn);
td.classList.remove("asc");
td.classList.remove("desc");
}
const columnId = event.target.id;
if (columnId == this._sortColumn) {
// Reverse sorting order.
this._sortAscendent = !this._sortAscendent;
} else {
this._sortColumn = columnId;
this._sortAscendent = true;
}
if (this._sortAscendent) {
event.target.classList.remove("desc");
event.target.classList.add("asc");
} else {
event.target.classList.remove("asc");
event.target.classList.add("desc");
}
await this._updateDisplay(true);
});
},
_lastMouseEvent: 0,
_updateLastMouseEvent() {
this._lastMouseEvent = Date.now();
},
async update() {
await State.update();
if (document.hidden) {
return;
}
await wait(0);
await this._updateDisplay();
},
// The force parameter can force a full update even when the mouse has been
// moved recently.
async _updateDisplay(force = false) {
if (
!force &&
Date.now() - this._lastMouseEvent < TIME_BEFORE_SORTING_AGAIN
) {
return;
}
let counters = State.getCounters();
// Reset the selectedRow field and the _openItems set each time we redraw
// to avoid keeping forever references to dead processes.
let openItems = this._openItems;
this._openItems = new Set();
counters = this._sortProcesses(counters);
for (let process of counters) {
let isOpen = openItems.has(process.pid);
let row = View.appendProcessRow(process, isOpen);
row.process = process;
if (isOpen) {
this._openItems.add(process.pid);
this._showChildren(row);
}
}
await View.commit();
},
_showChildren(row) {
let process = row.process;
this._sortThreads(process.threads);
for (let thread of process.threads) {
View.appendThreadRow(thread);
}
},
_sortThreads(threads) {
return threads.sort((a, b) => {
let order;
switch (this._sortColumn) {
case "column-name":
order = a.name.localeCompare(b.name);
break;
case "column-cpu-user":
order = b.slopeCpuUser - a.slopeCpuUser;
if (order == 0) {
order = b.totalCpuUser - a.totalCpuUser;
}
break;
case "column-cpu-kernel":
order = b.slopeCpuKernel - a.slopeCpuKernel;
if (order == 0) {
order = b.totalCpuKernel - a.totalCpuKernel;
}
break;
case "column-cpu-threads":
case "column-memory-resident":
case "column-memory-virtual":
case "column-type":
case "column-pid":
case null:
order = b.tid - a.tid;
break;
default:
throw new Error("Unsupported order: " + this._sortColumn);
}
if (!this._sortAscendent) {
order = -order;
}
return order;
});
},
_sortProcesses(counters) {
return counters.sort((a, b) => {
let order;
switch (this._sortColumn) {
case "column-pid":
order = b.pid - a.pid;
break;
case "column-type":
order = String(a.origin).localeCompare(b.origin);
if (order == 0) {
order = String(a.type).localeCompare(b.type);
}
break;
case "column-name":
order = String(a.name).localeCompare(b.name);
break;
case "column-cpu-user":
order = b.slopeCpuUser - a.slopeCpuUser;
if (order == 0) {
order = b.totalCpuUser - a.totalCpuUser;
}
break;
case "column-cpu-kernel":
order = b.slopeCpuKernel - a.slopeCpuKernel;
if (order == 0) {
order = b.totalCpuKernel - a.totalCpuKernel;
}
break;
case "column-cpu-threads":
order = b.threads.length - a.threads.length;
break;
case "column-memory-resident":
order = b.totalResidentSize - a.totalResidentSize;
break;
case "column-memory-virtual":
order = b.totalVirtualMemorySize - a.totalVirtualMemorySize;
break;
case null:
// Default order: browser goes first.
if (a.type == "browser") {
order = -1;
} else if (b.type == "browser") {
order = 1;
}
// Other processes by increasing pid, arbitrarily.
order = b.pid - a.pid;
break;
default:
throw new Error("Unsupported order: " + this._sortColumn);
}
if (!this._sortAscendent) {
order = -order;
}
return order;
});
},
};
window.onload = async function() {
Control.init();
await Control.update();
window.setInterval(() => Control.update(), UPDATE_INTERVAL_MS);
};

Просмотреть файл

@ -1,9 +0,0 @@
# 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/.
toolkit.jar:
content/global/aboutProcesses.html (content/aboutProcesses.html)
content/global/aboutProcesses.js (content/aboutProcesses.js)
content/global/aboutProcesses.css (content/aboutProcesses.css)
preview/aboutProcesses.ftl (content/aboutProcesses.ftl)

Просмотреть файл

@ -1,10 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
with Files('**'):
BUG_COMPONENT = ('Toolkit', 'Performance Monitoring')
JAR_MANIFESTS += ['jar.mn']

Просмотреть файл

@ -126,7 +126,3 @@ if CONFIG['MOZ_BUILD_APP'] == 'browser':
# This is only packaged for browser since corrupt JAR and XPI files tend to be a desktop-OS problem.
if CONFIG['MOZ_BUILD_APP'] == 'browser':
DIRS += ['corroborator']
# about:processes is experimental
if CONFIG['NIGHTLY_BUILD']:
DIRS += ['aboutprocesses']

Просмотреть файл

@ -22,13 +22,10 @@ class GeckoChildProcessHost;
enum class ProcType {
// These must match the ones in ContentParent.h, and E10SUtils.jsm
Web,
WebIsolated,
File,
Extension,
PrivilegedAbout,
PrivilegedMozilla,
WebLargeAllocation,
WebCOOPCOEP,
// the rest matches GeckoProcessTypes.h
Browser, // Default is named Browser here
Plugin,
@ -65,8 +62,6 @@ struct ProcInfo {
dom::ContentParentId childId;
// Process type
ProcType type;
// Origin, if any
nsString origin;
// Process filename (without the path name).
nsString filename;
// VMS in bytes.
@ -91,13 +86,11 @@ typedef MozPromise<ProcInfo, nsresult, true> ProcInfoPromise;
*/
#ifdef XP_MACOSX
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
const ProcType& processType,
const nsAString& origin,
const ProcType& type,
mach_port_t aChildTask = MACH_PORT_NULL);
#else
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
const ProcType& processType,
const nsAString& origin);
const ProcType& type);
#endif
} // namespace mozilla

Просмотреть файл

@ -20,7 +20,7 @@
namespace mozilla {
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, const ProcType& type,
const nsAString& origin, mach_port_t aChildTask) {
mach_port_t aChildTask) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);
@ -32,15 +32,11 @@ RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, const
return promise;
}
// Ensure that the string is still alive when `ResolveGetProcInfo` is called.
nsString originCopy(origin);
auto ResolveGetProcinfo = [holder = std::move(holder), pid, type,
originCopy = std::move(originCopy), childId, aChildTask]() {
auto ResolveGetProcinfo = [holder = std::move(holder), pid, type, childId, aChildTask]() {
ProcInfo info;
info.pid = pid;
info.childId = childId;
info.type = type;
info.origin = originCopy;
struct proc_bsdinfo proc;
if ((unsigned long)proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &proc, PROC_PIDTBSDINFO_SIZE) <
PROC_PIDTBSDINFO_SIZE) {

Просмотреть файл

@ -208,8 +208,7 @@ class ThreadInfoReader final : public StatReader {
};
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
const ProcType& type,
const nsAString& origin) {
const ProcType& type) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);
nsresult rv = NS_OK;
@ -221,11 +220,8 @@ RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
return promise;
}
// Ensure that the string is still alive when the runnable is called.
nsString originCopy(origin);
RefPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [holder = std::move(holder), pid, type,
originCopy = std::move(originCopy), childId]() {
__func__, [holder = std::move(holder), pid, type, childId]() {
// opening the stat file and reading its content
StatReader reader(pid);
ProcInfo info;
@ -237,7 +233,6 @@ RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
// Extra info
info.childId = childId;
info.type = type;
info.origin = originCopy;
// Let's look at the threads
nsCString taskPath;

Просмотреть файл

@ -8,7 +8,6 @@ const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const MAC = AppConstants.platform == "macosx";
const isFissionEnabled = Services.prefs.getBoolPref("fission.autostart");
add_task(async function test_proc_info() {
waitForExplicitFinish();
@ -43,13 +42,6 @@ add_task(async function test_proc_info() {
"unknown",
"Child proc type should be known"
);
if (childProc.type == "webIsolated") {
Assert.notEqual(
childProc.origin || "",
"",
"Child process should have an origin"
);
}
for (var y = 0; y < childProc.threads.length; y++) {
cpuThreads += childProc.threads[y].cpuUser;

Просмотреть файл

@ -73,7 +73,6 @@ void AppendThreads(ProcInfo* info) {
}
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
const nsString& origin,
const ProcType& type) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);
@ -87,12 +86,8 @@ RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
return promise;
}
// Ensure that the string is still alive when `ResolveGetProcInfo` is called.
nsString originCopy(origin);
RefPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__,
[holder = std::move(holder), originCopy = std::move(originCopy), pid,
type, childId]() -> void {
__func__, [holder = std::move(holder), pid, type, childId]() -> void {
nsAutoHandle handle(OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
@ -123,7 +118,6 @@ RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
info.pid = pid;
info.childId = childId;
info.type = type;
info.origin = originCopy;
info.filename.Assign(filename);
info.cpuKernel = ToNanoSeconds(kernelTime);
info.cpuUser = ToNanoSeconds(userTime);