зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 653179afb65f (bug 1175098) for frequent WinXP browser_compartments.js failures.
CLOSED TREE --HG-- extra : amend_source : 281a11895a3ee742061158d49672d42a52146bad
This commit is contained in:
Родитель
59e6297180
Коммит
0c009c0080
|
@ -86,10 +86,7 @@ let AutoUpdate = {
|
|||
};
|
||||
|
||||
let State = {
|
||||
_monitor: PerformanceStats.getMonitor([
|
||||
"jank", "cpow", "ticks",
|
||||
"jank-content", "cpow-content", "ticks-content",
|
||||
]),
|
||||
_monitor: PerformanceStats.getMonitor(["jank", "cpow", "ticks"]),
|
||||
|
||||
/**
|
||||
* @type{PerformanceData}
|
||||
|
@ -247,7 +244,7 @@ let updateLiveData = Task.async(function*() {
|
|||
let headerElt = document.createElement("tr");
|
||||
dataElt.appendChild(headerElt);
|
||||
headerElt.classList.add("header");
|
||||
for (let column of [...MEASURES, {key: "name", name: ""}, {key: "process", name: ""}]) {
|
||||
for (let column of [...MEASURES, {key: "name", name: ""}]) {
|
||||
let el = document.createElement("td");
|
||||
el.classList.add(column.key);
|
||||
el.textContent = column.label;
|
||||
|
@ -283,37 +280,20 @@ let updateLiveData = Task.async(function*() {
|
|||
el.textContent = value;
|
||||
}
|
||||
|
||||
{
|
||||
// Name
|
||||
let el = document.createElement("td");
|
||||
let id = item.id;
|
||||
el.classList.add("contents");
|
||||
el.classList.add("name");
|
||||
row.appendChild(el);
|
||||
if (item.addonId) {
|
||||
let _el = el;
|
||||
let _item = item;
|
||||
AddonManager.getAddonByID(item.addonId, a => {
|
||||
_el.textContent = a ? a.name : _item.name
|
||||
});
|
||||
} else {
|
||||
el.textContent = item.title || item.name;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Process information.
|
||||
let el = document.createElement("td");
|
||||
el.classList.add("contents");
|
||||
el.classList.add("process");
|
||||
row.appendChild(el);
|
||||
if (item.isChildProcess) {
|
||||
el.textContent = "(child)";
|
||||
row.classList.add("child");
|
||||
} else {
|
||||
el.textContent = "(parent)";
|
||||
row.classList.add("parent");
|
||||
}
|
||||
// Name
|
||||
let el = document.createElement("td");
|
||||
let id = item.id;
|
||||
el.classList.add("contents");
|
||||
el.classList.add("name");
|
||||
row.appendChild(el);
|
||||
if (item.addonId) {
|
||||
let _el = el;
|
||||
let _item = item;
|
||||
AddonManager.getAddonByID(item.addonId, a => {
|
||||
_el.textContent = a ? a.name : _item.name
|
||||
});
|
||||
} else {
|
||||
el.textContent = item.title || item.name;
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
|
|
|
@ -6,3 +6,4 @@ support-files =
|
|||
browser_compartments_script.js
|
||||
|
||||
[browser_aboutperformance.js]
|
||||
skip-if = e10s # Feature not implemented yet – bug 1140310
|
||||
|
|
|
@ -1,144 +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/. */
|
||||
|
||||
/**
|
||||
* A proxy implementing communication between the PerformanceStats.jsm modules
|
||||
* of the parent and children processes.
|
||||
*
|
||||
* This script is loaded in all processes but is essentially a NOOP in the
|
||||
* parent process.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PerformanceStats",
|
||||
"resource://gre/modules/PerformanceStats.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
/**
|
||||
* A global performance monitor used by this process.
|
||||
*
|
||||
* For the sake of simplicity, rather than attempting to map each PerformanceMonitor
|
||||
* of the parent to a PerformanceMonitor in each child process, we maintain a single
|
||||
* PerformanceMonitor in each child process. Probes activation/deactivation for this
|
||||
* monitor is controlled by the activation/deactivation of probes marked as "-content"
|
||||
* in the parent.
|
||||
*
|
||||
* In the parent, this is always an empty monitor.
|
||||
*/
|
||||
let gMonitor = PerformanceStats.getMonitor([]);
|
||||
|
||||
/**
|
||||
* `true` if this is a content process, `false` otherwise.
|
||||
*/
|
||||
let isContent = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
|
||||
|
||||
/**
|
||||
* Handle message `performance-stats-service-acquire`: ensure that the global
|
||||
* monitor has a given probe. This message must be sent by the parent process
|
||||
* whenever a probe is activated application-wide.
|
||||
*
|
||||
* Note that we may miss acquire messages if they are sent before this process is
|
||||
* launched. For this reason, `performance-stats-service-collect` automatically
|
||||
* re-acquires probes if it realizes that they are missing.
|
||||
*
|
||||
* This operation is a NOOP on the parent process.
|
||||
*
|
||||
* @param {{payload: Array<string>}} msg.data The message received. `payload`
|
||||
* must be an array of probe names.
|
||||
*/
|
||||
Services.cpmm.addMessageListener("performance-stats-service-acquire", function(msg) {
|
||||
if (!isContent) {
|
||||
return;
|
||||
}
|
||||
let name = msg.data.payload;
|
||||
ensureAcquired(name);
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle message `performance-stats-service-release`: release a given probe
|
||||
* from the global monitor. This message must be sent by the parent process
|
||||
* whenever a probe is deactivated application-wide.
|
||||
*
|
||||
* Note that we may miss release messages if they are sent before this process is
|
||||
* launched. This is ok, as probes are inactive by default: if we miss the release
|
||||
* message, we have already missed the acquire message, and the effect of both
|
||||
* messages together is to reset to the default state.
|
||||
*
|
||||
* This operation is a NOOP on the parent process.
|
||||
*
|
||||
* @param {{payload: Array<string>}} msg.data The message received. `payload`
|
||||
* must be an array of probe names.
|
||||
*/
|
||||
Services.cpmm.addMessageListener("performance-stats-service-release", function(msg) {
|
||||
if (!isContent) {
|
||||
return;
|
||||
}
|
||||
// Keep only the probes that do not appear in the payload
|
||||
let probes = gMonitor.getProbeNames
|
||||
.filter(x => msg.data.payload.indexOf(x) == -1);
|
||||
gMonitor = PerformanceStats.getMonitor(probes);
|
||||
});
|
||||
|
||||
/**
|
||||
* Ensure that this process has all the probes it needs.
|
||||
*
|
||||
* @param {Array<string>} probeNames The name of all probes needed by the
|
||||
* process.
|
||||
*/
|
||||
function ensureAcquired(probeNames) {
|
||||
let alreadyAcquired = gMonitor.probeNames;
|
||||
|
||||
// Algorithm is O(n^2) because we expect that n ≤ 3.
|
||||
let shouldAcquire = [];
|
||||
for (let probeName of probeNames) {
|
||||
if (alreadyAcquired.indexOf(probeName) == -1) {
|
||||
shouldAcquire.push(probeName)
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldAcquire.length == 0) {
|
||||
return;
|
||||
}
|
||||
gMonitor = PerformanceStats.getMonitor([...alreadyAcquired, ...shouldAcquire]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle message `performance-stats-service-collected`: collect the data
|
||||
* obtained by the monitor. This message must be sent by the parent process
|
||||
* whenever we grab a performance snapshot of the application.
|
||||
*
|
||||
* This operation provides `null` on the parent process.
|
||||
*
|
||||
* @param {{data: {payload: Array<string>}}} msg The message received. `payload`
|
||||
* must be an array of probe names.
|
||||
*/
|
||||
Services.cpmm.addMessageListener("performance-stats-service-collect", Task.async(function*(msg) {
|
||||
let {id, payload: {probeNames}} = msg.data;
|
||||
if (!isContent) {
|
||||
// This message was sent by the parent process to itself.
|
||||
// As per protocol, respond `null`.
|
||||
Services.cpmm.sendAsyncMessage("performance-stats-service-collect", {
|
||||
id,
|
||||
data: null
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// We may have missed acquire messages if the process was loaded too late.
|
||||
// Catch up now.
|
||||
ensureAcquired(probeNames);
|
||||
|
||||
// Collect and return data.
|
||||
let data = yield gMonitor.promiseSnapshot({probeNames});
|
||||
Services.cpmm.sendAsyncMessage("performance-stats-service-collect", {
|
||||
id,
|
||||
data
|
||||
});
|
||||
}));
|
|
@ -23,14 +23,6 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
|
||||
"resource://gre/modules/PromiseUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "clearTimeout",
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
|
||||
// The nsIPerformanceStatsService provides lower-level
|
||||
// access to SpiderMonkey and the probes.
|
||||
|
@ -45,17 +37,14 @@ XPCOMUtils.defineLazyServiceGetter(this, "finalizer",
|
|||
Ci.nsIFinalizationWitnessService
|
||||
);
|
||||
|
||||
|
||||
// The topic used to notify that a PerformanceMonitor has been garbage-collected
|
||||
// and that we can release/close the probes it holds.
|
||||
const FINALIZATION_TOPIC = "performancemonitor-finalize";
|
||||
|
||||
const PROPERTIES_META_IMMUTABLE = ["addonId", "isSystem", "isChildProcess", "groupId"];
|
||||
const PROPERTIES_META = [...PROPERTIES_META_IMMUTABLE, "windowId", "title", "name"];
|
||||
const PROPERTIES_META_IMMUTABLE = ["name", "addonId", "isSystem", "groupId"];
|
||||
const PROPERTIES_META = [...PROPERTIES_META_IMMUTABLE, "windowId", "title"];
|
||||
|
||||
// How long we wait for children processes to respond.
|
||||
const MAX_WAIT_FOR_CHILD_PROCESS_MS = 5000;
|
||||
|
||||
let isContent = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
|
||||
/**
|
||||
* Access to a low-level performance probe.
|
||||
*
|
||||
|
@ -136,14 +125,14 @@ Probe.prototype = {
|
|||
* @return {object} An object representing `a - b`. If `b` is
|
||||
* `null`, this is `a`.
|
||||
*/
|
||||
subtract: function(a, b) {
|
||||
substract: function(a, b) {
|
||||
if (a == null) {
|
||||
throw new TypeError();
|
||||
}
|
||||
if (b == null) {
|
||||
return a;
|
||||
}
|
||||
return this._impl.subtract(a, b);
|
||||
return this._impl.substract(a, b);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -215,7 +204,7 @@ let Probes = {
|
|||
}
|
||||
return true;
|
||||
},
|
||||
subtract: function(a, b) {
|
||||
substract: function(a, b) {
|
||||
// invariant: `a` and `b` are both non-null
|
||||
let result = {
|
||||
totalUserTime: a.totalUserTime - b.totalUserTime,
|
||||
|
@ -254,7 +243,7 @@ let Probes = {
|
|||
isEqual: function(a, b) {
|
||||
return a.totalCPOWTime == b.totalCPOWTime;
|
||||
},
|
||||
subtract: function(a, b) {
|
||||
substract: function(a, b) {
|
||||
return {
|
||||
totalCPOWTime: a.totalCPOWTime - b.totalCPOWTime
|
||||
};
|
||||
|
@ -283,78 +272,12 @@ let Probes = {
|
|||
isEqual: function(a, b) {
|
||||
return a.ticks == b.ticks;
|
||||
},
|
||||
subtract: function(a, b) {
|
||||
substract: function(a, b) {
|
||||
return {
|
||||
ticks: a.ticks - b.ticks
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
"jank-content": new Probe("jank-content", {
|
||||
_isActive: false,
|
||||
set isActive(x) {
|
||||
this._isActive = x;
|
||||
if (x) {
|
||||
Process.broadcast("acquire", ["jank"]);
|
||||
} else {
|
||||
Process.broadcast("release", ["jank"]);
|
||||
}
|
||||
},
|
||||
get isActive() {
|
||||
return this._isActive;
|
||||
},
|
||||
extract: function(xpcom) {
|
||||
return {};
|
||||
},
|
||||
isEqual: function(a, b) {
|
||||
return true;
|
||||
},
|
||||
subtract: function(a, b) {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
|
||||
"cpow-content": new Probe("cpow-content", {
|
||||
_isActive: false,
|
||||
set isActive(x) {
|
||||
this._isActive = x;
|
||||
if (x) {
|
||||
Process.broadcast("acquire", ["cpow"]);
|
||||
} else {
|
||||
Process.broadcast("release", ["cpow"]);
|
||||
}
|
||||
},
|
||||
get isActive() {
|
||||
return this._isActive;
|
||||
},
|
||||
extract: function(xpcom) {
|
||||
return {};
|
||||
},
|
||||
isEqual: function(a, b) {
|
||||
return true;
|
||||
},
|
||||
subtract: function(a, b) {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
|
||||
"ticks-content": new Probe("ticks-content", {
|
||||
set isActive(x) {
|
||||
// Ignore: This probe is always active.
|
||||
},
|
||||
get isActive() {
|
||||
return true;
|
||||
},
|
||||
extract: function(xpcom) {
|
||||
return {};
|
||||
},
|
||||
isEqual: function(a, b) {
|
||||
return true;
|
||||
},
|
||||
subtract: function(a, b) {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
|
@ -382,13 +305,6 @@ function PerformanceMonitor(probes) {
|
|||
PerformanceMonitor._monitors.set(this._id, probes);
|
||||
}
|
||||
PerformanceMonitor.prototype = {
|
||||
/**
|
||||
* The names of probes activated in this monitor.
|
||||
*/
|
||||
get probeNames() {
|
||||
return [for (probe of this._probes) probe.name];
|
||||
},
|
||||
|
||||
/**
|
||||
* Return asynchronously a snapshot with the data
|
||||
* for each probe monitored by this PerformanceMonitor.
|
||||
|
@ -401,7 +317,7 @@ PerformanceMonitor.prototype = {
|
|||
* will return a `Snapshot` in which all values are 0. For most uses,
|
||||
* the appropriate scenario is to perform a first call to `promiseSnapshot()`
|
||||
* to obtain a baseline, and then watch evolution of the values by calling
|
||||
* `promiseSnapshot()` and `subtract()`.
|
||||
* `promiseSnapshot()` and `substract()`.
|
||||
*
|
||||
* On the other hand, numeric values are also monotonic across several instances
|
||||
* of a PerformanceMonitor with the same probes.
|
||||
|
@ -414,45 +330,18 @@ PerformanceMonitor.prototype = {
|
|||
*
|
||||
* // all values of `snapshot2` are greater or equal to values of `snapshot1`.
|
||||
*
|
||||
* @param {object} options If provided, an object that may contain the following
|
||||
* fields:
|
||||
* {Array<string>} probeNames The subset of probes to use for this snapshot.
|
||||
* These probes must be a subset of the probes active in the monitor.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolve {Snapshot}
|
||||
*/
|
||||
promiseSnapshot: function(options = null) {
|
||||
promiseSnapshot: function() {
|
||||
if (!this._finalizer) {
|
||||
throw new Error("dispose() has already been called, this PerformanceMonitor is not usable anymore");
|
||||
}
|
||||
let probes;
|
||||
if (options && options.probeNames || undefined) {
|
||||
if (!Array.isArray(options.probeNames)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
// Make sure that we only request probes that we have
|
||||
for (let probeName of options.probeNames) {
|
||||
let probe = this._probes.find(probe => probe.name == probeName);
|
||||
if (!probe) {
|
||||
throw new TypeError(`I need probe ${probeName} but I only have ${this.probeNames}`);
|
||||
}
|
||||
if (!probes) {
|
||||
probes = [];
|
||||
}
|
||||
probes.push(probe);
|
||||
}
|
||||
} else {
|
||||
probes = this._probes;
|
||||
}
|
||||
return Task.spawn(function*() {
|
||||
let collected = yield Process.broadcastAndCollect("collect", {probeNames: [for (probe of probes) probe.name]});
|
||||
return new Snapshot({
|
||||
xpcom: performanceStatsService.getSnapshot(),
|
||||
childProcesses: collected,
|
||||
probes
|
||||
});
|
||||
});
|
||||
// Current implementation is actually synchronous.
|
||||
return Promise.resolve().then(() => new Snapshot({
|
||||
xpcom: performanceStatsService.getSnapshot(),
|
||||
probes: this._probes
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -492,7 +381,7 @@ PerformanceMonitor.make = function(probeNames) {
|
|||
let probes = [];
|
||||
for (let probeName of probeNames) {
|
||||
if (!(probeName in Probes)) {
|
||||
throw new TypeError("Probe not implemented: " + probeName);
|
||||
throw new TypeError("Probe not implemented: " + k);
|
||||
}
|
||||
probes.push(Probes[probeName]);
|
||||
}
|
||||
|
@ -578,24 +467,12 @@ this.PerformanceStats = {
|
|||
* @field {object|undefined} cpow See the documentation of probe "cpow".
|
||||
* `undefined` if this probe is not active.
|
||||
*/
|
||||
function PerformanceData({xpcom, json, probes}) {
|
||||
if (xpcom && json) {
|
||||
throw new TypeError("Cannot import both xpcom and json data");
|
||||
}
|
||||
let source = xpcom || json;
|
||||
function PerformanceData({xpcom, probes}) {
|
||||
for (let k of PROPERTIES_META) {
|
||||
this[k] = source[k];
|
||||
this[k] = xpcom[k];
|
||||
}
|
||||
if (xpcom) {
|
||||
for (let probe of probes) {
|
||||
this[probe.name] = probe.extract(xpcom);
|
||||
}
|
||||
this.isChildProcess = false;
|
||||
} else {
|
||||
for (let probe of probes) {
|
||||
this[probe.name] = json[probe.name];
|
||||
}
|
||||
this.isChildProcess = true;
|
||||
for (let probe of probes) {
|
||||
this[probe.name] = probe.extract(xpcom);
|
||||
}
|
||||
}
|
||||
PerformanceData.prototype = {
|
||||
|
@ -642,161 +519,20 @@ function PerformanceDiff(current, old = null) {
|
|||
for (let probeName of Object.keys(Probes)) {
|
||||
let other = old ? old[probeName] : null;
|
||||
if (probeName in current) {
|
||||
this[probeName] = Probes[probeName].subtract(current[probeName], other);
|
||||
this[probeName] = Probes[probeName].substract(current[probeName], other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A snapshot of the performance usage of the application.
|
||||
*
|
||||
* @param {nsIPerformanceSnapshot} xpcom The data acquired from this process.
|
||||
* @param {Array<Object>} childProcesses The data acquired from children processes.
|
||||
* @param {Array<Probe>} probes The active probes.
|
||||
* A snapshot of the performance usage of the process.
|
||||
*/
|
||||
function Snapshot({xpcom, childProcesses, probes}) {
|
||||
function Snapshot({xpcom, probes}) {
|
||||
this.componentsData = [];
|
||||
|
||||
// Parent process
|
||||
if (xpcom) {
|
||||
let enumeration = xpcom.getComponentsData().enumerate();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
let xpcom = enumeration.getNext().QueryInterface(Ci.nsIPerformanceStats);
|
||||
this.componentsData.push(new PerformanceData({xpcom, probes}));
|
||||
}
|
||||
let enumeration = xpcom.getComponentsData().enumerate();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
let stat = enumeration.getNext().QueryInterface(Ci.nsIPerformanceStats);
|
||||
this.componentsData.push(new PerformanceData({xpcom: stat, probes}));
|
||||
}
|
||||
|
||||
// Content processes
|
||||
if (childProcesses) {
|
||||
for (let {componentsData} of childProcesses) {
|
||||
// We are only interested in `componentsData` for the time being.
|
||||
for (let json of componentsData) {
|
||||
this.componentsData.push(new PerformanceData({json, probes}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.processData = new PerformanceData({xpcom: xpcom.getProcessData(), probes});
|
||||
}
|
||||
|
||||
/**
|
||||
* Communication with other processes
|
||||
*/
|
||||
let Process = {
|
||||
// `true` once communications have been initialized
|
||||
_initialized: false,
|
||||
|
||||
// the message manager
|
||||
_loader: null,
|
||||
|
||||
// a counter used to match responses to requests
|
||||
_idcounter: 0,
|
||||
|
||||
/**
|
||||
* If we are in a child process, return `null`.
|
||||
* Otherwise, return the global parent process message manager
|
||||
* and load the script to connect to children processes.
|
||||
*/
|
||||
get loader() {
|
||||
if (this._initialized) {
|
||||
return this._loader;
|
||||
}
|
||||
this._initialized = true;
|
||||
this._loader = Services.ppmm;
|
||||
if (!this._loader) {
|
||||
// We are in a child process.
|
||||
return null;
|
||||
}
|
||||
this._loader.loadProcessScript("resource://gre/modules/PerformanceStats-content.js",
|
||||
true/*including future processes*/);
|
||||
return this._loader;
|
||||
},
|
||||
|
||||
/**
|
||||
* Broadcast a message to all children processes.
|
||||
*
|
||||
* NOOP if we are in a child process.
|
||||
*/
|
||||
broadcast: function(topic, payload) {
|
||||
if (!this.loader) {
|
||||
return;
|
||||
}
|
||||
this.loader.broadcastAsyncMessage("performance-stats-service-" + topic, {payload});
|
||||
},
|
||||
|
||||
/**
|
||||
* Brodcast a message to all children processes and wait for answer.
|
||||
*
|
||||
* NOOP if we are in a child process, or if we have no children processes,
|
||||
* in which case we return `undefined`.
|
||||
*
|
||||
* @return {undefined} If we have no children processes, in particular
|
||||
* if we are in a child process.
|
||||
* @return {Promise<Array<Object>>} If we have children processes, an
|
||||
* array of objects with a structure similar to PerformanceData. Note
|
||||
* that the array may be empty if no child process responded.
|
||||
*/
|
||||
broadcastAndCollect: Task.async(function*(topic, payload) {
|
||||
if (!this.loader || this.loader.childCount == 1) {
|
||||
return undefined;
|
||||
}
|
||||
const TOPIC = "performance-stats-service-" + topic;
|
||||
let id = this._idcounter++;
|
||||
|
||||
// The number of responses we are expecting. Note that we may
|
||||
// not receive all responses if a process is too long to respond.
|
||||
let expecting = this.loader.childCount;
|
||||
|
||||
// The responses we have collected, in arbitrary order.
|
||||
let collected = [];
|
||||
let deferred = PromiseUtils.defer();
|
||||
|
||||
// The content script may be loaded more than once (bug 1184115).
|
||||
// To avoid double-responses, we keep track of who has already responded.
|
||||
// Note that we could it on the other end, at the expense of implementing
|
||||
// an additional .jsm just for that purpose.
|
||||
let responders = new Set();
|
||||
let observer = function({data, target}) {
|
||||
if (data.id != id) {
|
||||
// Collision between two collections,
|
||||
// ignore the other one.
|
||||
return;
|
||||
}
|
||||
if (responders.has(target)) {
|
||||
return;
|
||||
}
|
||||
responders.add(target);
|
||||
if (data.data) {
|
||||
collected.push(data.data)
|
||||
}
|
||||
if (--expecting > 0) {
|
||||
// We are still waiting for at least one response.
|
||||
return;
|
||||
}
|
||||
deferred.resolve();
|
||||
};
|
||||
this.loader.addMessageListener(TOPIC, observer);
|
||||
this.loader.broadcastAsyncMessage(
|
||||
TOPIC,
|
||||
{id, payload}
|
||||
);
|
||||
|
||||
// Processes can die/freeze/be busy loading a page..., so don't expect
|
||||
// that they will always respond.
|
||||
let timeout = setTimeout(() => {
|
||||
if (expecting == 0) {
|
||||
return;
|
||||
}
|
||||
deferred.resolve();
|
||||
}, MAX_WAIT_FOR_CHILD_PROCESS_MS);
|
||||
|
||||
deferred.promise.then(() => {
|
||||
clearTimeout(timeout);
|
||||
});
|
||||
|
||||
yield deferred.promise;
|
||||
this.loader.removeMessageListener(TOPIC, observer);
|
||||
|
||||
return collected;
|
||||
})
|
||||
};
|
||||
|
|
|
@ -13,7 +13,6 @@ XPIDL_MODULE = 'toolkit_perfmonitoring'
|
|||
|
||||
EXTRA_JS_MODULES += [
|
||||
'AddonWatcher.jsm',
|
||||
'PerformanceStats-content.js',
|
||||
'PerformanceStats.jsm',
|
||||
]
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ nsPerformanceSnapshot::GetGroupId(JSContext* cx,
|
|||
|
||||
groupId.AssignLiteral("process: ");
|
||||
groupId.AppendInt(mProcessId);
|
||||
groupId.AppendLiteral(", thread: ");
|
||||
groupId.AssignLiteral(", thread: ");
|
||||
groupId.AppendInt(runtimeId);
|
||||
groupId.AppendLiteral(", group: ");
|
||||
groupId.AppendInt(uid);
|
||||
|
|
|
@ -86,7 +86,7 @@ let SilentAssert = {
|
|||
}
|
||||
};
|
||||
|
||||
let isShuttingDown = false;
|
||||
|
||||
function monotinicity_tester(source, testName) {
|
||||
// In the background, check invariants:
|
||||
// - numeric data can only ever increase;
|
||||
|
@ -130,10 +130,6 @@ function monotinicity_tester(source, testName) {
|
|||
};
|
||||
let iteration = 0;
|
||||
let frameCheck = Task.async(function*() {
|
||||
if (isShuttingDown) {
|
||||
window.clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
let name = `${testName}: ${iteration++}`;
|
||||
let snapshot = yield source();
|
||||
if (!snapshot) {
|
||||
|
@ -163,10 +159,7 @@ function monotinicity_tester(source, testName) {
|
|||
}
|
||||
|
||||
let key = item.groupId;
|
||||
if (map.has(key)) {
|
||||
let old = map.get(key);
|
||||
Assert.ok(false, `Component ${key} has already been seen. Latest: ${item.title||item.addonId||item.name}, previous: ${old.title||old.addonId||old.name}`);
|
||||
}
|
||||
SilentAssert.ok(!map.has(key), "The component hasn't been seen yet.");
|
||||
map.set(key, item);
|
||||
}
|
||||
for (let [key, item] of map) {
|
||||
|
@ -243,19 +236,13 @@ add_task(function* test() {
|
|||
info("Searching by title, we didn't find the main frame");
|
||||
continue;
|
||||
}
|
||||
info("Found the main frame");
|
||||
|
||||
if (skipTotalUserTime) {
|
||||
info("Not looking for total user time on this platform, we're done");
|
||||
} else if (parent.jank.totalUserTime > 1000) {
|
||||
info("Enough CPU time detected, we're done");
|
||||
if (skipTotalUserTime || parent.jank.totalUserTime > 1000) {
|
||||
break;
|
||||
} else {
|
||||
info(`Not enough CPU time detected: ${parent.jank.totalUserTime}`);
|
||||
info(`Details: ${JSON.stringify(parent, null, "\t")}`);
|
||||
info(`Not enough CPU time detected: ${parent.jank.totalUserTime}`)
|
||||
}
|
||||
}
|
||||
isShuttingDown = true;
|
||||
|
||||
// Cleanup
|
||||
gBrowser.removeTab(newTab);
|
||||
|
|
Загрузка…
Ссылка в новой задаче