зеркало из https://github.com/mozilla/gecko-dev.git
143 строки
4.8 KiB
JavaScript
143 строки
4.8 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/. */
|
|
|
|
/**
|
|
* 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";
|
|
|
|
var { 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");
|
|
|
|
/**
|
|
* 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 in the parent.
|
|
*
|
|
* In the parent, this is always an empty monitor.
|
|
*/
|
|
var gMonitor = PerformanceStats.getMonitor([]);
|
|
|
|
/**
|
|
* `true` if this is a content process, `false` otherwise.
|
|
*/
|
|
var 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.probeNames
|
|
.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", 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 = await gMonitor.promiseSnapshot({probeNames});
|
|
Services.cpmm.sendAsyncMessage("performance-stats-service-collect", {
|
|
id,
|
|
data
|
|
});
|
|
});
|