--- a/js/ipc/CPOWTimer.cpp
+++ b/js/ipc/CPOWTimer.cpp
@@ -14,14 +14,16 @@ CPOWTimer::~CPOWTimer()
/* This is a best effort to find the compartment responsible for this CPOW call */
nsIGlobalObject *global = mozilla::dom::GetIncumbentGlobal();
if (!global)
return;
JSObject *obj = global->GetGlobalJSObject();
if (!obj)
return;
JSCompartment *compartment = js::GetObjectCompartment(obj);
- xpc::CompartmentPrivate *compartmentPrivate = xpc::CompartmentPrivate::Get(compartment);
- if (!compartmentPrivate)
+ if (!compartment)
return;
- PRIntervalTime time = PR_IntervalNow() - startInterval;
- compartmentPrivate->CPOWTime += time;
+ js::PerformanceData *performance = js::GetPerformanceData(compartment);
+ if (!performance)
+ return;
+ uint64_t time = PR_IntervalToMilliseconds(PR_IntervalNow() - startInterval);
+ performance->cpowTime += time;
}
--- a/js/ipc/moz.build
+++ b/js/ipc/moz.build
@@ -30,12 +30,13 @@ EXPORTS.mozilla.jsipc = [
'CpowHolder.h',
'CrossProcessObjectWrappers.h',
]
LOCAL_INCLUDES += [
'/dom/base',
'/js/ipc',
'/js/public',
+ '/js/src',
'/js/xpconnect/src',
'/js/xpconnect/wrappers',
]
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -163,23 +163,24 @@ JS_GetEmptyString(JSRuntime *rt)
{
MOZ_ASSERT(rt->hasContexts());
return rt->emptyString;
}
JS_PUBLIC_API(bool)
JS_GetCompartmentStats(JSRuntime *rt, CompartmentStatsVector &stats)
{
- for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
+ for (CompartmentsIter c(rt); !c.done(); c.next()) {
if (!stats.growBy(1))
return false;
CompartmentTimeStats *stat = &stats.back();
- stat->time = c.get()->totalTime;
stat->compartment = c.get();
+ stat->performance = stat->compartment->performance;
+ stat->isSystem = stat->compartment->isSystem;
stat->addonId = c.get()->addonId;
if (rt->compartmentNameCallback) {
(*rt->compartmentNameCallback)(rt, stat->compartment,
stat->compartmentName,
MOZ_ARRAY_LENGTH(stat->compartmentName));
} else {
strcpy(stat->compartmentName, "<unknown>");
}
@@ -5801,8 +5802,16 @@ JS::CaptureCurrentStack(JSContext *cx, J
return true;
}
JS_PUBLIC_API(Zone *)
JS::GetObjectZone(JSObject *obj)
{
return obj->zone();
}
+
+JS_PUBLIC_API(PerformanceData*)
+js::GetPerformanceData(JSCompartment *cx)
+{
+ if (!cx)
+ return nullptr;
+ return &cx->performance;
+}
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1024,18 +1024,18 @@ JS_GetEmptyStringValue(JSContext *cx);
extern JS_PUBLIC_API(JSString *)
JS_GetEmptyString(JSRuntime *rt);
struct CompartmentTimeStats {
char compartmentName[1024];
JSAddonId *addonId;
JSCompartment *compartment;
- uint64_t time; // microseconds
- uint64_t cpowTime; // microseconds
+ bool isSystem;
+ js::PerformanceData performance;
};
typedef js::Vector<CompartmentTimeStats, 0, js::SystemAllocPolicy> CompartmentStatsVector;
extern JS_PUBLIC_API(bool)
JS_GetCompartmentStats(JSRuntime *rt, CompartmentStatsVector &stats);
extern JS_PUBLIC_API(bool)
@@ -5122,11 +5122,17 @@ ResetStopwatches(JSRuntime*);
/**
* Turn on/off stopwatch-based CPU monitoring.
*/
extern JS_PUBLIC_API(void)
SetStopwatchActive(JSRuntime*, bool);
extern JS_PUBLIC_API(bool)
IsStopwatchActive(JSRuntime*);
+/**
+ * Access the performance information stored in a compartment.
+ */
+extern JS_PUBLIC_API(PerformanceData*)
+GetPerformanceData(JSCompartment*);
+
} /* namespace js */
#endif /* jsapi_h */
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -165,47 +165,17 @@ struct JSCompartment
friend struct JSContext;
friend class js::ExclusiveContext;
js::ReadBarrieredGlobalObject global_;
unsigned enterCompartmentDepth;
int64_t startInterval;
public:
- struct Performance {
- // Jank indicator.
- //
- // missedFrames[i] == number of times
- // execution of this compartment caused us to
- // miss at least 2^i successive frames - we
- // assume that a frame lasts 16ms.
- uint64_t missedFrames[8]; // FIXME: Magic number
-
- // Total amount of time spent executing code in
- // this compartment, in milliseconds, since process
- // launch.
- uint64_t totalUserTime;
- uint64_t totalSystemTime;
- uint64_t ownUserTime;
- uint64_t ownSystemTime;
-
- // Total number of time code was executed in this
- // compartment, in milliseconds, since process launch.
- uint64_t visits;
-
- Performance()
- : missedFrames{0, 0, 0, 0, 0, 0, 0, 0}
- , totalUserTime(0)
- , totalSystemTime(0)
- , ownUserTime(0)
- , ownSystemTime(0)
- , visits(0)
- {}
- };
- Performance performance;
+ js::PerformanceData performance;
void enter() {
enterCompartmentDepth++;
}
void leave() {
enterCompartmentDepth--;
}
bool hasBeenEntered() { return !!enterCompartmentDepth; }
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -474,12 +474,67 @@ struct PerThreadDataFriendFields
// Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp|
return reinterpret_cast<const PerThreadDataFriendFields *>(
reinterpret_cast<const char*>(rt) + RuntimeMainThreadOffset);
}
template <typename T> friend class JS::Rooted;
};
+// Container for performance data
+struct PerformanceData {
+ // Jank indicator.
+ //
+ // missedFrames[i] == number of times
+ // execution of this compartment caused us to
+ // miss at least 2^i successive frames - we
+ // assume that a frame lasts 16ms.
+ uint64_t missedFrames[8];
+
+ // Total amount of time spent executing code in
+ // this compartment, in milliseconds, since process
+ // launch.
+ uint64_t totalUserTime;
+ uint64_t totalSystemTime;
+ uint64_t ownUserTime;
+ uint64_t ownSystemTime;
+ uint64_t cpowTime;
+
+ // Total number of time code was executed in this
+ // compartment, since process launch.
+ uint64_t visits;
+
+ PerformanceData()
+ : missedFrames{0, 0, 0, 0, 0, 0, 0, 0}
+ , totalUserTime(0)
+ , totalSystemTime(0)
+ , ownUserTime(0)
+ , ownSystemTime(0)
+ , cpowTime(0)
+ , visits(0)
+ {}
+ PerformanceData(const PerformanceData& from)
+ : missedFrames{0, 0, 0, 0, 0, 0, 0, 0}
+ , totalUserTime(from.totalUserTime)
+ , totalSystemTime(from.totalSystemTime)
+ , ownUserTime(from.ownUserTime)
+ , ownSystemTime(from.ownSystemTime)
+ , cpowTime(from.cpowTime)
+ , visits(from.visits)
+ {
+ memcpy(missedFrames, from.missedFrames, sizeof(missedFrames));
+ }
+ PerformanceData& operator=(const PerformanceData& from)
+ {
+ memcpy(missedFrames, from.missedFrames, sizeof(missedFrames));
+ totalUserTime = from.totalUserTime;
+ totalSystemTime = from.totalSystemTime;
+ ownUserTime = from.ownUserTime;
+ ownSystemTime = from.ownSystemTime;
+ cpowTime = from.cpowTime;
+ visits = from.visits;
+ return *this;
+ }
+};
} /* namespace js */
#endif /* jspubtd_h */
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -373,9 +373,10 @@ typedef size_t jsbitmap;
#if !defined(JS_SILENCE_UNUSED_VALUE_IN_EXPR)
# define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
JS_BEGIN_MACRO \
expr; \
JS_END_MACRO
#endif
+
#endif /* jsutil_h */
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -430,24 +430,25 @@ struct AutoStopwatch MOZ_FINAL
* Previous owner is restored upon destruction.
*/
explicit inline AutoStopwatch(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: parent_(nullptr)
, context_(cx)
, descendentsUserTime(0)
, descendentsSystemTime(0)
{
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
JSRuntime *runtime = context_->runtime();
if (!runtime->stopWatch.isActive) {
return;
}
#if defined(XP_UNIX)
int err = getrusage(RUSAGE_SELF, &timeStamp);
- if (!err)
+ if (err)
return;
#elif defined(XP_WIN)
FILETIME creationTime; // Ignored
FILETIME exitTime; // Ignored
BOOL success = GetProcessTimes(GetCurrentProcessID(),
&creationTime, &exitTime,
&kernelTimeStamp, &userTimeStamp);
@@ -483,25 +484,25 @@ struct AutoStopwatch MOZ_FINAL
// Durations in museconds of the total user/system time spent
// by the entire process between construction and destruction
// of this object.
uint64_t totalUserTime, totalSystemTime;
#if defined(XP_UNIX)
struct rusage stop;
int err = getrusage(RUSAGE_SELF, &stop);
- if (!err)
+ if (err)
return;
totalUserTime =
- (stop.ru_utime.tv_sec - timeStamp.ru_utime.tv_sec) * 1000000
- + (stop.ru_utime.tv_sec - timeStamp.ru_utime.tv_sec);
+ (stop.ru_utime.tv_usec - timeStamp.ru_utime.tv_usec) / 1000
+ + (stop.ru_utime.tv_sec - timeStamp.ru_utime.tv_sec) * 1000;
totalSystemTime =
- (stop.ru_stime.tv_sec - timeStamp.ru_stime.tv_sec) * 1000000
- + (stop.ru_stime.tv_sec - timeStamp.ru_stime.tv_sec);
+ (stop.ru_stime.tv_usec - timeStamp.ru_stime.tv_usec) / 1000
+ + (stop.ru_stime.tv_sec - timeStamp.ru_stime.tv_sec) * 1000;
#elif defined(XP_WIN)
FILETIME creationTime;
FILETIME exitTime;
FILETIME kernelTime;
FILETIME userTime;
BOOL success = GetProcessTimes(GetCurrentProcessID(),
&creationTime, &exitTime,
&kernelTime, &userTime);
@@ -589,21 +590,16 @@ struct AutoStopwatch MOZ_FINAL
bool
js::RunScript(JSContext *cx, RunState &state)
{
JS_CHECK_RECURSION(cx, return false);
js::AutoStopwatch stopWatch(cx);
-#ifdef NIGHTLY_BUILD
- if (AssertOnScriptEntryHook hook = cx->runtime()->assertOnScriptEntryHook_)
- (*hook)(cx, state.script());
-#endif
-
SPSEntryMarker marker(cx->runtime(), state.script());
state.script()->ensureNonLazyCanonicalFunction(cx);
if (jit::IsIonEnabled(cx)) {
jit::MethodStatus status = jit::CanEnter(cx, state);
if (status == jit::Method_Error)
return false;
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -343,23 +343,16 @@ xpc::TraceXPCGlobal(JSTracer *trc, JSObj
xpc::CompartmentPrivate* compartmentPrivate = xpc::CompartmentPrivate::Get(obj);
if (compartmentPrivate && compartmentPrivate->scope)
compartmentPrivate->scope->TraceInside(trc);
}
namespace xpc {
-uint64_t
-GetCompartmentCPOWMicroseconds(JSCompartment *compartment)
-{
- xpc::CompartmentPrivate *compartmentPrivate = xpc::CompartmentPrivate::Get(compartment);
- return compartmentPrivate ? PR_IntervalToMicroseconds(compartmentPrivate->CPOWTime) : 0;
-}
-
JSObject*
CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
JS::CompartmentOptions& aOptions)
{
MOZ_ASSERT(NS_IsMainThread(), "using a principal off the main thread?");
MOZ_ASSERT(principal);
MOZ_RELEASE_ASSERT(principal != nsContentUtils::GetNullSubjectPrincipal(),
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -621,17 +621,17 @@ public:
void InitSingletonScopes();
void DeleteSingletonScopes();
PRTime GetWatchdogTimestamp(WatchdogTimestampCategory aCategory);
void OnProcessNextEvent() {
mSlowScriptCheckpoint = mozilla::TimeStamp::NowLoRes();
mSlowScriptSecondHalf = false;
- js::ResetStopWatches(Get()->Runtime());
+ js::ResetStopwatches(Get()->Runtime());
}
void OnAfterProcessNextEvent() {
mSlowScriptCheckpoint = mozilla::TimeStamp();
mSlowScriptSecondHalf = false;
}
nsTArray<nsXPCWrappedJS*>& WrappedJSToReleaseArray() { return mWrappedJSToReleaseArray; }
@@ -3627,17 +3627,16 @@ public:
};
explicit CompartmentPrivate(JSCompartment *c)
: wantXrays(false)
, writeToGlobalPrototype(false)
, skipWriteToGlobalPrototype(false)
, universalXPConnectEnabled(false)
, forcePermissiveCOWs(false)
- , CPOWTime(0)
, skipCOWCallableChecks(false)
, scriptability(c)
, scope(nullptr)
{
MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
mozilla::PodArrayZero(wrapperDenialWarnings);
}
@@ -3681,19 +3680,16 @@ public:
// This is only ever set during mochitest runs when enablePrivilege is called.
// It allows the SpecialPowers scope to waive the normal chrome security
// wrappers and expose properties directly to content. This lets us avoid a
// bunch of overhead and complexity in our SpecialPowers automation glue.
//
// Using it in production is inherently unsafe.
bool forcePermissiveCOWs;
- // A running count of how much time we've spent processing CPOWs.
- PRIntervalTime CPOWTime;
-
// Disables the XPConnect security checks that deny access to callables and
// accessor descriptors on COWs. Do not use this unless you are bholley.
bool skipCOWCallableChecks;
// Whether we've emitted a warning about a property that was filtered out
// by a security wrapper. See XrayWrapper.cpp.
bool wrapperDenialWarnings[WrapperDenialTypeCount];
--- a/toolkit/components/aboutcompartments/content/aboutCompartments.js
+++ b/toolkit/components/aboutcompartments/content/aboutCompartments.js
@@ -5,71 +5,163 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
-function go() {
- let compartmentInfo = Cc["@mozilla.org/compartment-info;1"]
- .getService(Ci.nsICompartmentInfo);
- let compartments = compartmentInfo.getCompartments();
- let count = compartments.length;
- let addons = {};
- for (let i = 0; i < count; i++) {
- let compartment = compartments.queryElementAt(i, Ci.nsICompartment);
- if (addons[compartment.addonId]) {
- addons[compartment.addonId].time += compartment.time;
- addons[compartment.addonId].CPOWTime += compartment.CPOWTime;
- addons[compartment.addonId].compartments.push(compartment);
- } else {
- addons[compartment.addonId] = {
- time: compartment.time,
- CPOWTime: compartment.CPOWTime,
- compartments: [compartment]
- };
- }
+/**
+ * The various measures we extract from a nsICompartment.
+ */
+const MEASURES = [
+ {key: "totalUserTime", label: "Total user (ms)"},
+ {key: "totalSystemTime", label: "Total system (ms)"},
+ {key: "ownUserTime", label: "Own user (ms)"},
+ {key: "ownSystemTime", label: "Own system (ms)"},
+ {key: "cpowTime", label: "CPOW (ms)"},
+ {key: "visits", label: "Activations"},
+];
+
+/**
+ * All information on a single owner (add-on, page, built-ins).
+ *
+ * @param {string} id A unique identifier.
+ * @param {string} kind One of "<addon>", "<built-in>", "<page>".
+ * @param {string|null} A name for this owner. Not expected for add-ons.
+ */
+function Owner(id, kind, name) {
+ for (let {key} of MEASURES) {
+ this[key] = 0;
+ }
+ this.compartments = [];
+ this.id = id;
+ this.kind = kind;
+ this.name = name;
+}
+Owner.prototype = {
+ add: function(compartment) {
+ this.compartments.push(compartment);
+ for (let {key} of MEASURES) {
+ this[key] += compartment[key];
+ }
+ },
+ promiseName: function() {
+ if (this.kind != "<addon>") {
+ return Promise.resolve(this.name);
+ }
+ return new Promise(resolve =>
+ AddonManager.getAddonByID(this.id, a =>
+ resolve(a?a.name:null)
+ )
+ );
+ }
+};
+
+function getStatistics() {
+ let compartmentInfo = Cc["@mozilla.org/compartment-info;1"]
+ .getService(Ci.nsICompartmentInfo);
+ let compartments = compartmentInfo.getCompartments();
+ let count = compartments.length;
+ let data = {};
+ for (let i = 0; i < count; i++) {
+ let compartment = compartments.queryElementAt(i, Ci.nsICompartment);
+ let kind, id, name;
+ if (!compartment.isSystem) {
+ name = id = compartment.compartmentName;
+ kind = "<page>";
+ } else if (compartment.addonId == "<non-addon>") {
+ id = kind = name = "<built-in>";
+ } else {
+ name = id = compartment.addonId;
+ kind = "<addon>";
+ }
+ let key = kind + ":" + id;
+ let owner = data[key];
+ if (!owner) {
+ owner = data[key] = new Owner(id, kind, name);
}
- let dataDiv = document.getElementById("data");
- for (let addon in addons) {
- let el = document.createElement("tr");
- let name = document.createElement("td");
- let time = document.createElement("td");
- let cpow = document.createElement("td");
- name.className = "addon";
- time.className = "time";
- cpow.className = "cpow";
- name.textContent = addon;
- AddonManager.getAddonByID(addon, function(a) {
- if (a) {
- name.textContent = a.name;
- }
- });
- time.textContent = addons[addon].time +"μs";
- cpow.textContent = addons[addon].CPOWTime +"μs";
- el.appendChild(time);
- el.appendChild(cpow);
- el.appendChild(name);
- let div = document.createElement("tr");
- for (let comp of addons[addon].compartments) {
- let c = document.createElement("tr");
- let name = document.createElement("td");
- let time = document.createElement("td");
- let cpow = document.createElement("td");
- name.className = "addon";
- time.className = "time";
- cpow.className = "cpow";
- name.textContent = comp.label;
- time.textContent = comp.time +"μs";
- cpow.textContent = comp.CPOWTime +"μs";
- c.appendChild(time);
- c.appendChild(cpow);
- c.appendChild(name);
- div.appendChild(c);
- div.className = "details";
+ owner.add(compartment);
+ }
+ return [data[k] for (k of Object.keys(data))].sort((a, b) => a.totalUserTime <= b.totalUserTime);
+}
+
+function update() {
+ try {
+ console.log("Updating");
+
+ // Activate (or reactivate) monitoring
+ Cu.stopwatchMonitoring = true;
+
+ let dataElt = document.getElementById("data");
+ dataElt.innerHTML = "";
+
+ // Generate table headers
+ let headerElt = document.createElement("tr");
+ dataElt.appendChild(headerElt);
+ for (let column of [...MEASURES, {key:"compartments", name: "Compartments"}, {key: "name", name: ""}]) {
+ let el = document.createElement("td");
+ el.classList.add(column.key);
+ el.classList.add("header");
+ el.textContent = column.label;
+ headerElt.appendChild(el);
+ }
+
+ // Generate table contents
+ let data = getStatistics();
+ console.log("Data", data);
+ for (let item of data) {
+ // Make sure that we don't show compartments with
+ // no time spent.
+ let show = false;
+ for (let column of MEASURES) {
+ if (item[column.key]) {
+ show = true;
}
- el.addEventListener("click", function() { div.style.display = (div.style.display != "block" ? "block" : "none"); });
- el.appendChild(div);
- dataDiv.appendChild(el);
+ }
+ if (!show) {
+ continue;
+ }
+
+ let row = document.createElement("tr");
+ row.classList.add(item.kind);
+ dataElt.appendChild(row);
+
+ // Measures
+ for (let column of MEASURES) {
+ let el = document.createElement("td");
+ el.classList.add(column.key);
+ el.classList.add("contents");
+ el.textContent = item[column.key];
+ row.appendChild(el);
+ }
+
+ // Number of compartments
+ let el = document.createElement("td");
+ el.classList.add("contents");
+ el.classList.add("compartments");
+ el.textContent = item.compartments.length;
+ row.appendChild(el);
+
+ // Name
+ el = document.createElement("td");
+ el.classList.add("contents");
+ el.classList.add("name");
+ row.appendChild(el);
+ item.promiseName().then(name => {
+ name ? el.textContent = name : item.id;
+ });
}
+ } catch (ex) {
+ console.error(ex);
+ }
}
+
+function stop() {
+ Cu.stopwatchMonitoring = false;
+}
+
+function go() {
+ update();
+ window.setInterval(update, 5000);
+ window.addEventListener("beforeunload", stop);
+}
--- a/toolkit/components/aboutcompartments/content/aboutCompartments.xhtml
+++ b/toolkit/components/aboutcompartments/content/aboutCompartments.xhtml
@@ -24,20 +24,24 @@
.header {
font-weight: bold;
}
tr.details {
font-weight: lighter;
color: gray;
display: none;
}
+ tr.addons {
+ background-color: white;
+ }
+ tr.builtins {
+ background-color: rgb(1, 1, .5);
+ }
+ tr.pages {
+ background-color: rgb(.5, 1, 1);
+ }
</style>
</head>
<body onload="go()">
<table id="data">
- <tr class="header">
- <td class="time">time</td>
- <td class="cpow">time in CPOWs</td>
- <td class="addon">name</td>
- </tr>
</table>
</body>
</html>
--- a/toolkit/components/aboutcompartments/nsCompartmentInfo.cpp
+++ b/toolkit/components/aboutcompartments/nsCompartmentInfo.cpp
@@ -7,53 +7,97 @@
#include "nsMemory.h"
#include "nsLiteralString.h"
#include "nsCRTGlue.h"
#include "nsIJSRuntimeService.h"
#include "nsServiceManagerUtils.h"
#include "nsIMutableArray.h"
#include "nsJSUtils.h"
#include "xpcpublic.h"
+#include "jspubtd.h"
class nsCompartment : public nsICompartment {
public:
- nsCompartment(nsAString& aCompartmentName, nsAString& aAddonId,
- uint64_t aTime, uint64_t aCPOWTime)
- : mCompartmentName(aCompartmentName), mAddonId(aAddonId), mTime(aTime), mCPOWTime(aCPOWTime) {}
+ nsCompartment(nsAString& aCompartmentName, nsAString& aAddonId, bool aIsSystem, js::PerformanceData aPerformanceData)
+ : mCompartmentName(aCompartmentName)
+ , mAddonId(aAddonId)
+ , mIsSystem(aIsSystem)
+ , mPerformanceData(aPerformanceData)
+ {}
NS_DECL_ISUPPORTS
/* readonly attribute wstring compartmentName; */
NS_IMETHOD GetCompartmentName(nsAString& aCompartmentName) MOZ_OVERRIDE {
aCompartmentName.Assign(mCompartmentName);
return NS_OK;
};
- /* readonly attribute unsigned long time; */
- NS_IMETHOD GetTime(uint64_t* aTime) MOZ_OVERRIDE {
- *aTime = mTime;
- return NS_OK;
- }
/* readonly attribute wstring addon id; */
NS_IMETHOD GetAddonId(nsAString& aAddonId) MOZ_OVERRIDE {
aAddonId.Assign(mAddonId);
return NS_OK;
};
- /* readonly attribute unsigned long CPOW time; */
- NS_IMETHOD GetCPOWTime(uint64_t* aCPOWTime) MOZ_OVERRIDE {
- *aCPOWTime = mCPOWTime;
+ /* readonly attribute unsigned long long totalUserTime; */
+ NS_IMETHOD GetTotalUserTime(uint64_t *aTotalUserTime) {
+ *aTotalUserTime = mPerformanceData.totalUserTime;
+ return NS_OK;
+ };
+
+ /* readonly attribute unsigned long long totalSystemTime; */
+ NS_IMETHOD GetTotalSystemTime(uint64_t *aTotalSystemTime) {
+ *aTotalSystemTime = mPerformanceData.totalSystemTime;
+ return NS_OK;
+ };
+
+ /* readonly attribute unsigned long long ownUserTime; */
+ NS_IMETHOD GetOwnUserTime(uint64_t *aOwnUserTime) {
+ *aOwnUserTime = mPerformanceData.ownUserTime;
+ return NS_OK;
+ };
+
+ /* readonly attribute unsigned long long ownSystemTime; */
+ NS_IMETHOD GetOwnSystemTime(uint64_t *aOwnSystemTime) {
+ *aOwnSystemTime = mPerformanceData.ownSystemTime;
+ return NS_OK;
+ };
+
+ /* readonly attribute unsigned long long cpowTime; */
+ NS_IMETHOD GetCpowTime(uint64_t *aCpowTime) {
+ *aCpowTime = mPerformanceData.cpowTime;
+ return NS_OK;
+ };
+
+ /* readonly attribute unsigned long long visits; */
+ NS_IMETHOD GetVisits(uint64_t *aVisits) {
+ *aVisits = mPerformanceData.visits;
+ return NS_OK;
+ };
+
+ /* unsigned long long getMissedFrames (in unsigned long i); */
+ NS_IMETHOD GetMissedFrames(uint32_t i, uint64_t *_retval) {
+ if (i >= mozilla::ArrayLength(mPerformanceData.missedFrames)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ *_retval = mPerformanceData.missedFrames[i];
+ return NS_OK;
+ };
+
+ NS_IMETHOD GetIsSystem(bool *_retval) {
+ *_retval = mIsSystem;
return NS_OK;
}
private:
nsString mCompartmentName;
nsString mAddonId;
- uint64_t mTime;
- uint64_t mCPOWTime;
+ bool mIsSystem;
+ js::PerformanceData mPerformanceData;
+
virtual ~nsCompartment() {}
};
NS_IMPL_ISUPPORTS(nsCompartment, nsICompartment)
NS_IMPL_ISUPPORTS(nsCompartmentInfo, nsICompartmentInfo)
nsCompartmentInfo::nsCompartmentInfo()
{
@@ -72,23 +116,24 @@ nsCompartmentInfo::GetCompartments(nsIAr
svc->GetRuntime(&rt);
nsCOMPtr<nsIMutableArray> compartments = do_CreateInstance(NS_ARRAY_CONTRACTID);
CompartmentStatsVector stats;
if (!JS_GetCompartmentStats(rt, stats))
return NS_ERROR_OUT_OF_MEMORY;
size_t num = stats.length();
for (size_t pos = 0; pos < num; pos++) {
+ CompartmentTimeStats *c = &stats[pos];
nsString addonId;
- if (stats[pos].addonId) {
- AssignJSFlatString(addonId, (JSFlatString*)stats[pos].addonId);
+ if (c->addonId) {
+ AssignJSFlatString(addonId, (JSFlatString*)c->addonId);
} else {
addonId.AssignLiteral("<non-addon>");
}
- uint32_t cpowTime = xpc::GetCompartmentCPOWMicroseconds(stats[pos].compartment);
- nsCString compartmentName(stats[pos].compartmentName);
+ nsCString compartmentName(c->compartmentName);
NS_ConvertUTF8toUTF16 name(compartmentName);
- compartments->AppendElement(new nsCompartment(name, addonId, stats[pos].time, cpowTime), false);
+
+ compartments->AppendElement(new nsCompartment(name, addonId, c->isSystem, c->performance), false);
}
compartments.forget(aCompartments);
return NS_OK;
}
--- a/toolkit/components/aboutcompartments/nsICompartmentInfo.idl
+++ b/toolkit/components/aboutcompartments/nsICompartmentInfo.idl
@@ -2,26 +2,62 @@
/* 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/. */
#include "nsISupports.idl"
#include "nsIArray.idl"
-[scriptable, uuid(13dd4c09-ff11-4943-8dc2-d96eb69c963b)]
+[scriptable, uuid(3a23d383-052e-4199-8914-74c037fe359e)]
interface nsICompartment : nsISupports {
/* name of compartment */
readonly attribute AString compartmentName;
- /* time spent executing code in this compartment in microseconds */
- readonly attribute unsigned long long time;
+
/* the id of the addon associated with this compartment, or null */
readonly attribute AString addonId;
- /* time spent processing CPOWs in microseconds */
- readonly attribute unsigned long long CPOWTime;
+
+ /*
+ Total amount of time spent executing code in this compartment, in
+ milliseconds.
+
+ Note that these durations are only computed while
+ Components.utils.stopwatchMonitoring == true and that they are never
+ reset to 0.
+ */
+ readonly attribute unsigned long long totalUserTime;
+ readonly attribute unsigned long long totalSystemTime;
+ readonly attribute unsigned long long ownUserTime;
+ readonly attribute unsigned long long ownSystemTime;
+ readonly attribute unsigned long long cpowTime;
+
+ /* Number of times we have executed code in this compartment.
+ Updated only while Components.utils.stopwatchMonitoring == true,
+ never reset to 0.
+ */
+ readonly attribute unsigned long long visits;
+
+ /* `true` if this is a system compartment (either an add-on or a built-in).*/
+ readonly attribute bool isSystem;
+
+ /**
+ * The number of times execution of code in this compartment has apparently
+ * caused frame drops.
+ *
+ * getMissedFrames(0): number of times we have dropped at least 1 frame
+ * getMissedFrames(1): number of times we have dropped at least 2 successive frames
+ * ...
+ * getMissedFrames(i): number of times we have dropped at least 2^i successive frames
+ *
+ * Updated only while Components.utils.stopwatchMonitoring == true,
+ * never reset to 0.
+ */
+ unsigned long long getMissedFrames(in unsigned long i);
+ /* Maximal value of the argument to pass to `getMissedFrames`.*/
+ const unsigned long MISSED_FRAMES_RANGE = 8;
};
[scriptable, builtinclass, uuid(5795113a-39a1-4087-ba09-98b7d07d025a)]
interface nsICompartmentInfo : nsISupports {
nsIArray getCompartments();
};
%{C++