зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 2 changesets (bug 1147664) for b2g xpcshell failures in test_compartments.js
Backed out changeset cfd27d5ffc58 (bug 1147664) Backed out changeset cace9a3246c1 (bug 1147664)
This commit is contained in:
Родитель
467999bebd
Коммит
3f09481f19
|
@ -317,21 +317,16 @@ IterPerformanceStats(JSContext* cx,
|
||||||
}
|
}
|
||||||
|
|
||||||
JSRuntime* rt = JS_GetRuntime(cx);
|
JSRuntime* rt = JS_GetRuntime(cx);
|
||||||
|
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
|
||||||
// First report the shared groups
|
|
||||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
|
||||||
JSCompartment* compartment = c.get();
|
JSCompartment* compartment = c.get();
|
||||||
if (!c->principals()) {
|
if (!compartment->performanceMonitoring.isLinked()) {
|
||||||
// Compartments without principals could show up here, but
|
|
||||||
// reporting them doesn't really make sense.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!c->performanceMonitoring.hasSharedGroup()) {
|
|
||||||
// Don't report compartments that do not even have a PerformanceGroup.
|
// Don't report compartments that do not even have a PerformanceGroup.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
js::AutoCompartment autoCompartment(cx, compartment);
|
js::AutoCompartment autoCompartment(cx, compartment);
|
||||||
PerformanceGroup* group = compartment->performanceMonitoring.getSharedGroup(cx);
|
PerformanceGroup* group = compartment->performanceMonitoring.getGroup(cx);
|
||||||
|
|
||||||
if (group->data.ticks == 0) {
|
if (group->data.ticks == 0) {
|
||||||
// Don't report compartments that have never been used.
|
// Don't report compartments that have never been used.
|
||||||
continue;
|
continue;
|
||||||
|
@ -343,9 +338,7 @@ IterPerformanceStats(JSContext* cx,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(*walker)(cx,
|
if (!(*walker)(cx, group->data, group->uid, closure)) {
|
||||||
group->data, group->uid, nullptr,
|
|
||||||
closure)) {
|
|
||||||
// Issue in callback
|
// Issue in callback
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -354,35 +347,6 @@ IterPerformanceStats(JSContext* cx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then report the own groups
|
|
||||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
|
||||||
JSCompartment* compartment = c.get();
|
|
||||||
if (!c->principals()) {
|
|
||||||
// Compartments without principals could show up here, but
|
|
||||||
// reporting them doesn't really make sense.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!c->performanceMonitoring.hasOwnGroup()) {
|
|
||||||
// Don't report compartments that do not even have a PerformanceGroup.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
js::AutoCompartment autoCompartment(cx, compartment);
|
|
||||||
PerformanceGroup* ownGroup = compartment->performanceMonitoring.getOwnGroup(cx);
|
|
||||||
if (ownGroup->data.ticks == 0) {
|
|
||||||
// Don't report compartments that have never been used.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx);
|
|
||||||
if (!(*walker)(cx,
|
|
||||||
ownGroup->data, ownGroup->uid, &sharedGroup->uid,
|
|
||||||
closure)) {
|
|
||||||
// Issue in callback
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, report the process stats
|
|
||||||
*processStats = rt->stopwatch.performance;
|
*processStats = rt->stopwatch.performance;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5409,7 +5409,7 @@ BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp)
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
class AutoStopwatch;
|
struct AutoStopwatch;
|
||||||
|
|
||||||
// Container for performance data
|
// Container for performance data
|
||||||
// All values are monotonic.
|
// All values are monotonic.
|
||||||
|
@ -5540,30 +5540,21 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Each PerformanceGroupHolder handles:
|
// Indirection towards a PerformanceGroup.
|
||||||
// - a reference-counted indirection towards a PerformanceGroup shared
|
// This structure handles reference counting for instances of PerformanceGroup.
|
||||||
// by several compartments
|
|
||||||
// - a owned PerformanceGroup representing the performance of a single
|
|
||||||
// compartment.
|
|
||||||
//
|
//
|
||||||
struct PerformanceGroupHolder {
|
struct PerformanceGroupHolder {
|
||||||
// Get the shared group.
|
// Get the group.
|
||||||
// On first call, this causes a single Hashtable lookup.
|
// On first call, this causes a single Hashtable lookup.
|
||||||
// Successive calls do not require further lookups.
|
// Successive calls do not require further lookups.
|
||||||
js::PerformanceGroup* getSharedGroup(JSContext*);
|
js::PerformanceGroup* getGroup(JSContext*);
|
||||||
|
|
||||||
// Get the own group.
|
// `true` if the this holder is currently associated to a
|
||||||
js::PerformanceGroup* getOwnGroup(JSContext*);
|
|
||||||
|
|
||||||
// `true` if the this holder is currently associated to a shared
|
|
||||||
// PerformanceGroup, `false` otherwise. Use this method to avoid
|
// PerformanceGroup, `false` otherwise. Use this method to avoid
|
||||||
// instantiating a PerformanceGroup if you only need to get
|
// instantiating a PerformanceGroup if you only need to get
|
||||||
// available performance data.
|
// available performance data.
|
||||||
inline bool hasSharedGroup() const {
|
inline bool isLinked() const {
|
||||||
return sharedGroup_ != nullptr;
|
return group_ != nullptr;
|
||||||
}
|
|
||||||
inline bool hasOwnGroup() const {
|
|
||||||
return ownGroup_ != nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the link to the PerformanceGroup. This method is designed
|
// Remove the link to the PerformanceGroup. This method is designed
|
||||||
|
@ -5573,12 +5564,10 @@ struct PerformanceGroupHolder {
|
||||||
|
|
||||||
explicit PerformanceGroupHolder(JSRuntime* runtime)
|
explicit PerformanceGroupHolder(JSRuntime* runtime)
|
||||||
: runtime_(runtime)
|
: runtime_(runtime)
|
||||||
, sharedGroup_(nullptr)
|
, group_(nullptr)
|
||||||
, ownGroup_(nullptr)
|
|
||||||
{ }
|
{ }
|
||||||
~PerformanceGroupHolder();
|
~PerformanceGroupHolder();
|
||||||
|
private:
|
||||||
private:
|
|
||||||
// Return the key representing this PerformanceGroup in
|
// Return the key representing this PerformanceGroup in
|
||||||
// Runtime::Stopwatch.
|
// Runtime::Stopwatch.
|
||||||
// Do not deallocate the key.
|
// Do not deallocate the key.
|
||||||
|
@ -5586,11 +5575,10 @@ struct PerformanceGroupHolder {
|
||||||
|
|
||||||
JSRuntime *runtime_;
|
JSRuntime *runtime_;
|
||||||
|
|
||||||
// The PerformanceGroups held by this object.
|
// The PerformanceGroup held by this object.
|
||||||
// Initially set to `nullptr` until the first call to `getGroup`.
|
// Initially set to `nullptr` until the first cal to `getGroup`.
|
||||||
// May be reset to `nullptr` by a call to `unlink`.
|
// May be reset to `nullptr` by a call to `unlink`.
|
||||||
js::PerformanceGroup* sharedGroup_;
|
js::PerformanceGroup* group_;
|
||||||
js::PerformanceGroup* ownGroup_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5616,10 +5604,6 @@ extern JS_PUBLIC_API(bool)
|
||||||
SetStopwatchIsMonitoringJank(JSRuntime*, bool);
|
SetStopwatchIsMonitoringJank(JSRuntime*, bool);
|
||||||
extern JS_PUBLIC_API(bool)
|
extern JS_PUBLIC_API(bool)
|
||||||
GetStopwatchIsMonitoringJank(JSRuntime*);
|
GetStopwatchIsMonitoringJank(JSRuntime*);
|
||||||
extern JS_PUBLIC_API(bool)
|
|
||||||
SetStopwatchIsMonitoringPerCompartment(JSRuntime*, bool);
|
|
||||||
extern JS_PUBLIC_API(bool)
|
|
||||||
GetStopwatchIsMonitoringPerCompartment(JSRuntime*);
|
|
||||||
|
|
||||||
extern JS_PUBLIC_API(bool)
|
extern JS_PUBLIC_API(bool)
|
||||||
IsStopwatchActive(JSRuntime*);
|
IsStopwatchActive(JSRuntime*);
|
||||||
|
@ -5631,9 +5615,7 @@ extern JS_PUBLIC_API(PerformanceData*)
|
||||||
GetPerformanceData(JSRuntime*);
|
GetPerformanceData(JSRuntime*);
|
||||||
|
|
||||||
typedef bool
|
typedef bool
|
||||||
(PerformanceStatsWalker)(JSContext* cx,
|
(PerformanceStatsWalker)(JSContext* cx, const PerformanceData& stats, uint64_t uid, void* closure);
|
||||||
const PerformanceData& stats, uint64_t uid,
|
|
||||||
const uint64_t* parentId, void* closure);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the performance statistics.
|
* Extract the performance statistics.
|
||||||
|
|
|
@ -372,49 +372,15 @@ ExecuteState::pushInterpreterFrame(JSContext* cx)
|
||||||
scopeChain_, type_, evalInFrame_);
|
scopeChain_, type_, evalInFrame_);
|
||||||
}
|
}
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
// Implementation of per-performance group performance measurement.
|
// Implementation of per-performance group performance measurement.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// All mutable state is stored in `Runtime::stopwatch` (per-process
|
// All mutable state is stored in `Runtime::stopwatch` (per-process
|
||||||
// performance stats and logistics) and in `PerformanceGroup` (per
|
// performance stats and logistics) and in `PerformanceGroup` (per
|
||||||
// group performance stats).
|
// group performance stats).
|
||||||
class AutoStopwatch final
|
struct AutoStopwatch final
|
||||||
{
|
{
|
||||||
// The context with which this object was initialized.
|
|
||||||
// Non-null.
|
|
||||||
JSContext* const cx_;
|
|
||||||
|
|
||||||
// An indication of the number of times we have entered the event
|
|
||||||
// loop. Used only for comparison.
|
|
||||||
uint64_t iteration_;
|
|
||||||
|
|
||||||
// `true` if this object is currently used to monitor performance
|
|
||||||
// for a shared PerformanceGroup, `false` otherwise, i.e. if the
|
|
||||||
// stopwatch mechanism is off or if another stopwatch is already
|
|
||||||
// in charge of monitoring for the same PerformanceGroup.
|
|
||||||
bool isMonitoringForGroup_;
|
|
||||||
|
|
||||||
// `true` if this object is currently used to monitor performance
|
|
||||||
// for a single compartment, `false` otherwise, i.e. if the
|
|
||||||
// stopwatch mechanism is off or if another stopwatch is already
|
|
||||||
// in charge of monitoring for the same PerformanceGroup.
|
|
||||||
bool isMonitoringForSelf_;
|
|
||||||
|
|
||||||
// `true` if this stopwatch is the topmost stopwatch on the stack
|
|
||||||
// for this event, `false` otherwise.
|
|
||||||
bool isMonitoringForTop_;
|
|
||||||
|
|
||||||
// `true` if we are monitoring jank, `false` otherwise.
|
|
||||||
bool isMonitoringJank_;
|
|
||||||
// `true` if we are monitoring CPOW, `false` otherwise.
|
|
||||||
bool isMonitoringCPOW_;
|
|
||||||
|
|
||||||
// Timestamps captured while starting the stopwatch.
|
|
||||||
uint64_t userTimeStart_;
|
|
||||||
uint64_t systemTimeStart_;
|
|
||||||
uint64_t CPOWTimeStart_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// If the stopwatch is active, constructing an instance of
|
// If the stopwatch is active, constructing an instance of
|
||||||
// AutoStopwatch causes it to become the current owner of the
|
// AutoStopwatch causes it to become the current owner of the
|
||||||
// stopwatch.
|
// stopwatch.
|
||||||
|
@ -423,198 +389,120 @@ class AutoStopwatch final
|
||||||
explicit inline AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
explicit inline AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||||
: cx_(cx)
|
: cx_(cx)
|
||||||
, iteration_(0)
|
, iteration_(0)
|
||||||
, isMonitoringForGroup_(false)
|
, isActive_(false)
|
||||||
, isMonitoringForSelf_(false)
|
, isTop_(false)
|
||||||
, isMonitoringForTop_(false)
|
|
||||||
, isMonitoringJank_(false)
|
|
||||||
, isMonitoringCPOW_(false)
|
|
||||||
, userTimeStart_(0)
|
, userTimeStart_(0)
|
||||||
, systemTimeStart_(0)
|
, systemTimeStart_(0)
|
||||||
, CPOWTimeStart_(0)
|
, CPOWTimeStart_(0)
|
||||||
{
|
{
|
||||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||||
|
|
||||||
|
JSRuntime* runtime = JS_GetRuntime(cx_);
|
||||||
|
if (!runtime->stopwatch.isMonitoringJank())
|
||||||
|
return;
|
||||||
|
|
||||||
JSCompartment* compartment = cx_->compartment();
|
JSCompartment* compartment = cx_->compartment();
|
||||||
if (compartment->scheduledForDestruction)
|
if (compartment->scheduledForDestruction)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JSRuntime* runtime = cx_->runtime();
|
|
||||||
iteration_ = runtime->stopwatch.iteration;
|
iteration_ = runtime->stopwatch.iteration;
|
||||||
|
|
||||||
PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx);
|
PerformanceGroup *group = compartment->performanceMonitoring.getGroup(cx);
|
||||||
if (!sharedGroup) {
|
MOZ_ASSERT(group);
|
||||||
// Either this Runtime is not configured for Performance Monitoring, or we couldn't
|
|
||||||
// allocate the group, or there was a problem with the hashtable.
|
if (group->hasStopwatch(iteration_)) {
|
||||||
|
// Someone is already monitoring this group during this
|
||||||
|
// tick, no need for further monitoring.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sharedGroup->hasStopwatch(iteration_)) {
|
// Start the stopwatch.
|
||||||
// We are now in charge of monitoring this group for the tick,
|
if (!this->getTimes(runtime, &userTimeStart_, &systemTimeStart_))
|
||||||
// until destruction of `this` or until we enter a nested event
|
return;
|
||||||
// loop and `iteration_` is incremented.
|
isActive_ = true;
|
||||||
sharedGroup->acquireStopwatch(iteration_, this);
|
CPOWTimeStart_ = runtime->stopwatch.performance.totalCPOWTime;
|
||||||
isMonitoringForGroup_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PerformanceGroup* ownGroup = nullptr;
|
// We are now in charge of monitoring this group for the tick,
|
||||||
if (runtime->stopwatch.isMonitoringPerCompartment()) {
|
// until destruction of `this` or until we enter a nested event
|
||||||
// As above, but for the group representing just this compartment.
|
// loop and `iteration_` is incremented.
|
||||||
ownGroup = compartment->performanceMonitoring.getOwnGroup(cx);
|
group->acquireStopwatch(iteration_, this);
|
||||||
if (!ownGroup->hasStopwatch(iteration_)) {
|
|
||||||
ownGroup->acquireStopwatch(iteration_, this);
|
|
||||||
isMonitoringForSelf_ = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime->stopwatch.isEmpty) {
|
if (runtime->stopwatch.isEmpty) {
|
||||||
// This is the topmost stopwatch on the stack.
|
// This is the topmost stopwatch on the stack.
|
||||||
// It will be in charge of updating the per-process
|
// It will be in charge of updating the per-process
|
||||||
// performance data.
|
// performance data.
|
||||||
runtime->stopwatch.isEmpty = false;
|
runtime->stopwatch.isEmpty = false;
|
||||||
isMonitoringForTop_ = true;
|
runtime->stopwatch.performance.ticks++;
|
||||||
|
isTop_ = true;
|
||||||
MOZ_ASSERT(isMonitoringForGroup_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isMonitoringForGroup_ && !isMonitoringForSelf_) {
|
|
||||||
// We are not in charge of monitoring anything.
|
|
||||||
// (isMonitoringForTop_ implies isMonitoringForGroup_,
|
|
||||||
// so we do not need to check it)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
enter();
|
|
||||||
}
|
}
|
||||||
~AutoStopwatch() {
|
inline ~AutoStopwatch() {
|
||||||
if (!isMonitoringForGroup_ && !isMonitoringForSelf_) {
|
if (!isActive_) {
|
||||||
// We are not in charge of monitoring anything.
|
// We are not in charge of monitoring anything.
|
||||||
// (isMonitoringForTop_ implies isMonitoringForGroup_,
|
|
||||||
// so we do not need to check it)
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSRuntime* runtime = JS_GetRuntime(cx_);
|
||||||
JSCompartment* compartment = cx_->compartment();
|
JSCompartment* compartment = cx_->compartment();
|
||||||
if (compartment->scheduledForDestruction)
|
|
||||||
return;
|
|
||||||
|
|
||||||
JSRuntime* runtime = cx_->runtime();
|
MOZ_ASSERT(!compartment->scheduledForDestruction);
|
||||||
|
|
||||||
|
if (!runtime->stopwatch.isMonitoringJank()) {
|
||||||
|
// Monitoring has been stopped while we were
|
||||||
|
// executing the code. Drop everything.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (iteration_ != runtime->stopwatch.iteration) {
|
if (iteration_ != runtime->stopwatch.iteration) {
|
||||||
// We have entered a nested event loop at some point.
|
// We have entered a nested event loop at some point.
|
||||||
// Any information we may have is obsolete.
|
// Any information we may have is obsolete.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish and commit measures
|
PerformanceGroup *group = compartment->performanceMonitoring.getGroup(cx_);
|
||||||
exit();
|
MOZ_ASSERT(group);
|
||||||
|
|
||||||
// Now release groups.
|
// Compute time spent.
|
||||||
if (isMonitoringForGroup_) {
|
group->releaseStopwatch(iteration_, this);
|
||||||
PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx_);
|
uint64_t userTimeEnd, systemTimeEnd;
|
||||||
MOZ_ASSERT(sharedGroup);
|
if (!this->getTimes(runtime, &userTimeEnd, &systemTimeEnd))
|
||||||
sharedGroup->releaseStopwatch(iteration_, this);
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (isMonitoringForSelf_) {
|
uint64_t userTimeDelta = userTimeEnd - userTimeStart_;
|
||||||
PerformanceGroup* ownGroup = compartment->performanceMonitoring.getOwnGroup(cx_);
|
uint64_t systemTimeDelta = systemTimeEnd - systemTimeStart_;
|
||||||
MOZ_ASSERT(ownGroup);
|
uint64_t CPOWTimeDelta = runtime->stopwatch.performance.totalCPOWTime - CPOWTimeStart_;
|
||||||
ownGroup->releaseStopwatch(iteration_, this);
|
group->data.totalUserTime += userTimeDelta;
|
||||||
}
|
group->data.totalSystemTime += systemTimeDelta;
|
||||||
|
group->data.totalCPOWTime += CPOWTimeDelta;
|
||||||
if (isMonitoringForTop_)
|
|
||||||
runtime->stopwatch.isEmpty = true;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void enter() {
|
|
||||||
JSRuntime* runtime = cx_->runtime();
|
|
||||||
|
|
||||||
if (runtime->stopwatch.isMonitoringCPOW()) {
|
|
||||||
CPOWTimeStart_ = runtime->stopwatch.performance.totalCPOWTime;
|
|
||||||
isMonitoringCPOW_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime->stopwatch.isMonitoringJank()) {
|
|
||||||
if (this->getTimes(runtime, &userTimeStart_, &systemTimeStart_)) {
|
|
||||||
isMonitoringJank_ = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void exit() {
|
|
||||||
JSRuntime* runtime = cx_->runtime();
|
|
||||||
|
|
||||||
uint64_t userTimeDelta = 0;
|
|
||||||
uint64_t systemTimeDelta = 0;
|
|
||||||
if (isMonitoringJank_ && runtime->stopwatch.isMonitoringJank()) {
|
|
||||||
// We were monitoring jank when we entered and we still are.
|
|
||||||
uint64_t userTimeEnd, systemTimeEnd;
|
|
||||||
if (!this->getTimes(runtime, &userTimeEnd, &systemTimeEnd)) {
|
|
||||||
// We make no attempt to recover from this error. If
|
|
||||||
// we bail out here, we lose nothing of value, plus
|
|
||||||
// I'm nearly sure that this error cannot happen in
|
|
||||||
// practice.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
userTimeDelta = userTimeEnd - userTimeStart_;
|
|
||||||
systemTimeDelta = systemTimeEnd - systemTimeStart_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t CPOWTimeDelta = 0;
|
|
||||||
if (isMonitoringCPOW_ && runtime->stopwatch.isMonitoringCPOW()) {
|
|
||||||
// We were monitoring CPOW when we entered and we still are.
|
|
||||||
CPOWTimeDelta = runtime->stopwatch.performance.totalCPOWTime - CPOWTimeStart_;
|
|
||||||
|
|
||||||
}
|
|
||||||
commitDeltasToGroups(userTimeDelta, systemTimeDelta, CPOWTimeDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
void commitDeltasToGroups(uint64_t userTimeDelta,
|
|
||||||
uint64_t systemTimeDelta,
|
|
||||||
uint64_t CPOWTimeDelta)
|
|
||||||
{
|
|
||||||
JSCompartment* compartment = cx_->compartment();
|
|
||||||
|
|
||||||
PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx_);
|
|
||||||
MOZ_ASSERT(sharedGroup);
|
|
||||||
applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, sharedGroup->data);
|
|
||||||
|
|
||||||
if (isMonitoringForSelf_) {
|
|
||||||
PerformanceGroup* ownGroup = compartment->performanceMonitoring.getOwnGroup(cx_);
|
|
||||||
MOZ_ASSERT(ownGroup);
|
|
||||||
applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, ownGroup->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMonitoringForTop_) {
|
|
||||||
JSRuntime* runtime = cx_->runtime();
|
|
||||||
applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, runtime->stopwatch.performance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void applyDeltas(uint64_t userTimeDelta,
|
|
||||||
uint64_t systemTimeDelta,
|
|
||||||
uint64_t CPOWTimeDelta,
|
|
||||||
PerformanceData& data) const {
|
|
||||||
|
|
||||||
data.ticks++;
|
|
||||||
|
|
||||||
uint64_t totalTimeDelta = userTimeDelta + systemTimeDelta;
|
uint64_t totalTimeDelta = userTimeDelta + systemTimeDelta;
|
||||||
data.totalUserTime += userTimeDelta;
|
updateDurations(totalTimeDelta, group->data.durations);
|
||||||
data.totalSystemTime += systemTimeDelta;
|
group->data.ticks++;
|
||||||
data.totalCPOWTime += CPOWTimeDelta;
|
|
||||||
|
|
||||||
// Update an array containing the number of times we have missed
|
if (isTop_) {
|
||||||
// at least 2^0 successive ms, 2^1 successive ms, ...
|
// This is the topmost stopwatch on the stack.
|
||||||
// 2^i successive ms.
|
// Record the timing information.
|
||||||
|
runtime->stopwatch.performance.totalUserTime = userTimeEnd;
|
||||||
|
runtime->stopwatch.performance.totalSystemTime = systemTimeEnd;
|
||||||
|
updateDurations(totalTimeDelta, runtime->stopwatch.performance.durations);
|
||||||
|
runtime->stopwatch.isEmpty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Update an array containing the number of times we have missed
|
||||||
|
// at least 2^0 successive ms, 2^1 successive ms, ...
|
||||||
|
// 2^i successive ms.
|
||||||
|
template<int N>
|
||||||
|
void updateDurations(uint64_t totalTimeDelta, uint64_t (&array)[N]) const {
|
||||||
// Duration of one frame, i.e. 16ms in museconds
|
// Duration of one frame, i.e. 16ms in museconds
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
uint64_t duration = 1000;
|
uint64_t duration = 1000;
|
||||||
for (i = 0, duration = 1000;
|
for (i = 0, duration = 1000;
|
||||||
i < ArrayLength(data.durations) && duration < totalTimeDelta;
|
i < N && duration < totalTimeDelta;
|
||||||
++i, duration *= 2)
|
++i, duration *= 2) {
|
||||||
{
|
array[i]++;
|
||||||
data.durations[i]++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,9 +585,31 @@ class AutoStopwatch final
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The context with which this object was initialized.
|
||||||
|
// Non-null.
|
||||||
|
JSContext* const cx_;
|
||||||
|
|
||||||
private:
|
// An indication of the number of times we have entered the event
|
||||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
|
// loop. Used only for comparison.
|
||||||
|
uint64_t iteration_;
|
||||||
|
|
||||||
|
// `true` if this object is currently used to monitor performance,
|
||||||
|
// `false` otherwise, i.e. if the stopwatch mechanism is off or if
|
||||||
|
// another stopwatch is already in charge of monitoring for the
|
||||||
|
// same PerformanceGroup.
|
||||||
|
bool isActive_;
|
||||||
|
|
||||||
|
// `true` if this stopwatch is the topmost stopwatch on the stack
|
||||||
|
// for this event, `false` otherwise.
|
||||||
|
bool isTop_;
|
||||||
|
|
||||||
|
// Timestamps captured while starting the stopwatch.
|
||||||
|
uint64_t userTimeStart_;
|
||||||
|
uint64_t systemTimeStart_;
|
||||||
|
uint64_t CPOWTimeStart_;
|
||||||
|
|
||||||
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
|
@ -899,17 +899,6 @@ js::GetStopwatchIsMonitoringCPOW(JSRuntime* rt)
|
||||||
return rt->stopwatch.isMonitoringCPOW();
|
return rt->stopwatch.isMonitoringCPOW();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
js::SetStopwatchIsMonitoringPerCompartment(JSRuntime* rt, bool value)
|
|
||||||
{
|
|
||||||
return rt->stopwatch.setIsMonitoringPerCompartment(value);
|
|
||||||
}
|
|
||||||
bool
|
|
||||||
js::GetStopwatchIsMonitoringPerCompartment(JSRuntime* rt)
|
|
||||||
{
|
|
||||||
return rt->stopwatch.isMonitoringPerCompartment();
|
|
||||||
}
|
|
||||||
|
|
||||||
js::PerformanceGroupHolder::~PerformanceGroupHolder()
|
js::PerformanceGroupHolder::~PerformanceGroupHolder()
|
||||||
{
|
{
|
||||||
unlink();
|
unlink();
|
||||||
|
@ -929,18 +918,13 @@ js::PerformanceGroupHolder::getHashKey(JSContext* cx)
|
||||||
void
|
void
|
||||||
js::PerformanceGroupHolder::unlink()
|
js::PerformanceGroupHolder::unlink()
|
||||||
{
|
{
|
||||||
if (ownGroup_) {
|
if (!group_) {
|
||||||
js_delete(ownGroup_);
|
|
||||||
ownGroup_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sharedGroup_) {
|
|
||||||
// The group has never been instantiated.
|
// The group has never been instantiated.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
js::PerformanceGroup* group = sharedGroup_;
|
js::PerformanceGroup* group = group_;
|
||||||
sharedGroup_ = nullptr;
|
group_ = nullptr;
|
||||||
|
|
||||||
if (group->decRefCount() > 0) {
|
if (group->decRefCount() > 0) {
|
||||||
// The group has at least another owner.
|
// The group has at least another owner.
|
||||||
|
@ -949,51 +933,32 @@ js::PerformanceGroupHolder::unlink()
|
||||||
|
|
||||||
|
|
||||||
JSRuntime::Stopwatch::Groups::Ptr ptr =
|
JSRuntime::Stopwatch::Groups::Ptr ptr =
|
||||||
runtime_->stopwatch.groups().lookup(group->key_);
|
runtime_->stopwatch.groups_.lookup(group->key_);
|
||||||
MOZ_ASSERT(ptr);
|
MOZ_ASSERT(ptr);
|
||||||
runtime_->stopwatch.groups().remove(ptr);
|
runtime_->stopwatch.groups_.remove(ptr);
|
||||||
js_delete(group);
|
js_delete(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
PerformanceGroup*
|
PerformanceGroup*
|
||||||
js::PerformanceGroupHolder::getOwnGroup(JSContext* cx)
|
js::PerformanceGroupHolder::getGroup(JSContext* cx)
|
||||||
{
|
{
|
||||||
if (ownGroup_)
|
if (group_)
|
||||||
return ownGroup_;
|
return group_;
|
||||||
|
|
||||||
ownGroup_ = runtime_->new_<PerformanceGroup>(cx, nullptr);
|
|
||||||
return ownGroup_;
|
|
||||||
}
|
|
||||||
|
|
||||||
PerformanceGroup*
|
|
||||||
js::PerformanceGroupHolder::getSharedGroup(JSContext* cx)
|
|
||||||
{
|
|
||||||
if (sharedGroup_)
|
|
||||||
return sharedGroup_;
|
|
||||||
|
|
||||||
if (!runtime_->stopwatch.groups().initialized())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
void* key = getHashKey(cx);
|
void* key = getHashKey(cx);
|
||||||
JSRuntime::Stopwatch::Groups::AddPtr ptr = runtime_->stopwatch.groups().lookupForAdd(key);
|
JSRuntime::Stopwatch::Groups::AddPtr ptr =
|
||||||
|
runtime_->stopwatch.groups_.lookupForAdd(key);
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
sharedGroup_ = ptr->value();
|
group_ = ptr->value();
|
||||||
MOZ_ASSERT(sharedGroup_);
|
MOZ_ASSERT(group_);
|
||||||
} else {
|
} else {
|
||||||
sharedGroup_ = runtime_->new_<PerformanceGroup>(cx, key);
|
group_ = runtime_->new_<PerformanceGroup>(cx, key);
|
||||||
if (!sharedGroup_)
|
runtime_->stopwatch.groups_.add(ptr, key, group_);
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (!runtime_->stopwatch.groups().add(ptr, key, sharedGroup_)) {
|
|
||||||
js_delete(sharedGroup_);
|
|
||||||
sharedGroup_ = nullptr;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedGroup_->incRefCount();
|
group_->incRefCount();
|
||||||
|
|
||||||
return sharedGroup_;
|
return group_;
|
||||||
}
|
}
|
||||||
|
|
||||||
PerformanceData*
|
PerformanceData*
|
||||||
|
|
|
@ -1483,29 +1483,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||||
Performance measurements
|
Performance measurements
|
||||||
------------------------------------------ */
|
------------------------------------------ */
|
||||||
struct Stopwatch {
|
struct Stopwatch {
|
||||||
/**
|
|
||||||
* A map used to collapse compartments belonging to the same
|
|
||||||
* add-on (respectively to the same webpage, to the platform)
|
|
||||||
* into a single group.
|
|
||||||
*
|
|
||||||
* Keys: for system compartments, a `JSAddonId*` (which may be
|
|
||||||
* `nullptr`), and for webpages, a `JSPrincipals*` (which may
|
|
||||||
* not). Note that compartments may start as non-system
|
|
||||||
* compartments and become compartments later during their
|
|
||||||
* lifetime, which requires an invalidation.
|
|
||||||
*
|
|
||||||
* This map is meant to be accessed only by instances of
|
|
||||||
* PerformanceGroupHolder, which handle both reference-counting
|
|
||||||
* of the values and invalidation of the key/value pairs.
|
|
||||||
*/
|
|
||||||
typedef js::HashMap<void*, js::PerformanceGroup*,
|
|
||||||
js::DefaultHasher<void*>,
|
|
||||||
js::SystemAllocPolicy> Groups;
|
|
||||||
|
|
||||||
Groups& groups() {
|
|
||||||
return groups_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of times we have entered the event loop.
|
* The number of times we have entered the event loop.
|
||||||
* Used to reset counters whenever we enter the loop,
|
* Used to reset counters whenever we enter the loop,
|
||||||
|
@ -1546,7 +1523,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||||
, currentPerfGroupCallback(nullptr)
|
, currentPerfGroupCallback(nullptr)
|
||||||
, isMonitoringJank_(false)
|
, isMonitoringJank_(false)
|
||||||
, isMonitoringCPOW_(false)
|
, isMonitoringCPOW_(false)
|
||||||
, isMonitoringPerCompartment_(false)
|
|
||||||
, idCounter_(0)
|
, idCounter_(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
@ -1588,21 +1564,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||||
return isMonitoringJank_;
|
return isMonitoringJank_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setIsMonitoringPerCompartment(bool value) {
|
|
||||||
if (isMonitoringPerCompartment_ != value)
|
|
||||||
reset();
|
|
||||||
|
|
||||||
if (value && !groups_.initialized()) {
|
|
||||||
if (!groups_.init(128))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
isMonitoringPerCompartment_ = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool isMonitoringPerCompartment() const {
|
|
||||||
return isMonitoringPerCompartment_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate/deactivate stopwatch measurement of CPOW.
|
* Activate/deactivate stopwatch measurement of CPOW.
|
||||||
|
@ -1646,6 +1607,25 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||||
MonotonicTimeStamp userTimeFix;
|
MonotonicTimeStamp userTimeFix;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* A map used to collapse compartments belonging to the same
|
||||||
|
* add-on (respectively to the same webpage, to the platform)
|
||||||
|
* into a single group.
|
||||||
|
*
|
||||||
|
* Keys: for system compartments, a `JSAddonId*` (which may be
|
||||||
|
* `nullptr`), and for webpages, a `JSPrincipals*` (which may
|
||||||
|
* not). Note that compartments may start as non-system
|
||||||
|
* compartments and become compartments later during their
|
||||||
|
* lifetime, which requires an invalidation.
|
||||||
|
*
|
||||||
|
* This map is meant to be accessed only by instances of
|
||||||
|
* PerformanceGroupHolder, which handle both reference-counting
|
||||||
|
* of the values and invalidation of the key/value pairs.
|
||||||
|
*/
|
||||||
|
typedef js::HashMap<void*, js::PerformanceGroup*,
|
||||||
|
js::DefaultHasher<void*>,
|
||||||
|
js::SystemAllocPolicy> Groups;
|
||||||
|
|
||||||
Groups groups_;
|
Groups groups_;
|
||||||
friend struct js::PerformanceGroupHolder;
|
friend struct js::PerformanceGroupHolder;
|
||||||
|
|
||||||
|
@ -1654,7 +1634,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||||
*/
|
*/
|
||||||
bool isMonitoringJank_;
|
bool isMonitoringJank_;
|
||||||
bool isMonitoringCPOW_;
|
bool isMonitoringCPOW_;
|
||||||
bool isMonitoringPerCompartment_;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A counter used to generate unique identifiers for groups.
|
* A counter used to generate unique identifiers for groups.
|
||||||
|
|
|
@ -146,16 +146,6 @@ Probe.prototype = {
|
||||||
return this._impl.subtract(a, b);
|
return this._impl.subtract(a, b);
|
||||||
},
|
},
|
||||||
|
|
||||||
importChildCompartments: function(parent, children) {
|
|
||||||
if (!Array.isArray(children)) {
|
|
||||||
throw new TypeError();
|
|
||||||
}
|
|
||||||
if (!parent || !(parent instanceof PerformanceData)) {
|
|
||||||
throw new TypeError();
|
|
||||||
}
|
|
||||||
return this._impl.importChildCompartments(parent, children);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the probe.
|
* The name of the probe.
|
||||||
*/
|
*/
|
||||||
|
@ -238,8 +228,7 @@ let Probes = {
|
||||||
}
|
}
|
||||||
result.longestDuration = lastNonZero(result.durations);
|
result.longestDuration = lastNonZero(result.durations);
|
||||||
return result;
|
return result;
|
||||||
},
|
}
|
||||||
importChildCompartments: function() { /* nothing to do */ },
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -269,8 +258,7 @@ let Probes = {
|
||||||
return {
|
return {
|
||||||
totalCPOWTime: a.totalCPOWTime - b.totalCPOWTime
|
totalCPOWTime: a.totalCPOWTime - b.totalCPOWTime
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
importChildCompartments: function() { /* nothing to do */ },
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -299,8 +287,7 @@ let Probes = {
|
||||||
return {
|
return {
|
||||||
ticks: a.ticks - b.ticks
|
ticks: a.ticks - b.ticks
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
importChildCompartments: function() { /* nothing to do */ },
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"jank-content": new Probe("jank-content", {
|
"jank-content": new Probe("jank-content", {
|
||||||
|
@ -324,8 +311,7 @@ let Probes = {
|
||||||
},
|
},
|
||||||
subtract: function(a, b) {
|
subtract: function(a, b) {
|
||||||
return null;
|
return null;
|
||||||
},
|
}
|
||||||
importChildCompartments: function() { /* nothing to do */ },
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"cpow-content": new Probe("cpow-content", {
|
"cpow-content": new Probe("cpow-content", {
|
||||||
|
@ -349,22 +335,15 @@ let Probes = {
|
||||||
},
|
},
|
||||||
subtract: function(a, b) {
|
subtract: function(a, b) {
|
||||||
return null;
|
return null;
|
||||||
},
|
}
|
||||||
importChildCompartments: function() { /* nothing to do */ },
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"ticks-content": new Probe("ticks-content", {
|
"ticks-content": new Probe("ticks-content", {
|
||||||
_isActive: false,
|
|
||||||
set isActive(x) {
|
set isActive(x) {
|
||||||
this._isActive = x;
|
// Ignore: This probe is always active.
|
||||||
if (x) {
|
|
||||||
Process.broadcast("acquire", ["ticks"]);
|
|
||||||
} else {
|
|
||||||
Process.broadcast("release", ["ticks"]);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
get isActive() {
|
get isActive() {
|
||||||
return this._isActive;
|
return true;
|
||||||
},
|
},
|
||||||
extract: function(xpcom) {
|
extract: function(xpcom) {
|
||||||
return {};
|
return {};
|
||||||
|
@ -374,30 +353,8 @@ let Probes = {
|
||||||
},
|
},
|
||||||
subtract: function(a, b) {
|
subtract: function(a, b) {
|
||||||
return null;
|
return null;
|
||||||
},
|
}
|
||||||
importChildCompartments: function() { /* nothing to do */ },
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
compartments: new Probe("compartments", {
|
|
||||||
set isActive(x) {
|
|
||||||
performanceStatsService.isMonitoringPerCompartment = x;
|
|
||||||
},
|
|
||||||
get isActive() {
|
|
||||||
return performanceStatsService.isMonitoringPerCompartment;
|
|
||||||
},
|
|
||||||
extract: function(xpcom) {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
isEqual: function(a, b) {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
subtract: function(a, b) {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
importChildCompartments: function(parent, children) {
|
|
||||||
parent.children = children;
|
|
||||||
},
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -700,32 +657,16 @@ function PerformanceDiff(current, old = null) {
|
||||||
function Snapshot({xpcom, childProcesses, probes}) {
|
function Snapshot({xpcom, childProcesses, probes}) {
|
||||||
this.componentsData = [];
|
this.componentsData = [];
|
||||||
|
|
||||||
// Current process
|
// Parent process
|
||||||
if (xpcom) {
|
if (xpcom) {
|
||||||
let children = new Map();
|
|
||||||
let enumeration = xpcom.getComponentsData().enumerate();
|
let enumeration = xpcom.getComponentsData().enumerate();
|
||||||
while (enumeration.hasMoreElements()) {
|
while (enumeration.hasMoreElements()) {
|
||||||
let xpcom = enumeration.getNext().QueryInterface(Ci.nsIPerformanceStats);
|
let xpcom = enumeration.getNext().QueryInterface(Ci.nsIPerformanceStats);
|
||||||
let stat = new PerformanceData({xpcom, probes});
|
this.componentsData.push(new PerformanceData({xpcom, probes}));
|
||||||
if (!stat.parentId) {
|
|
||||||
this.componentsData.push(stat);
|
|
||||||
} else {
|
|
||||||
let siblings = children.get(stat.parentId);
|
|
||||||
if (!siblings) {
|
|
||||||
children.set(stat.parentId, (siblings = []));
|
|
||||||
}
|
|
||||||
siblings.push(stat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let parent of this.componentsData) {
|
|
||||||
for (let probe of probes) {
|
|
||||||
probe.importChildCompartments(parent, children.get(parent.groupId) || []);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Child processes
|
// Content processes
|
||||||
if (childProcesses) {
|
if (childProcesses) {
|
||||||
for (let {componentsData} of childProcesses) {
|
for (let {componentsData} of childProcesses) {
|
||||||
// We are only interested in `componentsData` for the time being.
|
// We are only interested in `componentsData` for the time being.
|
||||||
|
|
|
@ -17,12 +17,12 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Snapshot of the performance of a component, e.g. an add-on, a web
|
* Snapshot of the performance of a component, e.g. an add-on, a web
|
||||||
* page, system built-ins, a module or the entire process itself.
|
* page, system built-ins, or the entire process itself.
|
||||||
*
|
*
|
||||||
* All values are monotonic and are updated only when
|
* All values are monotonic and are updated only when
|
||||||
* `nsIPerformanceStatsService.isStopwatchActive` is `true`.
|
* `nsIPerformanceStatsService.isStopwatchActive` is `true`.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(1bc2d016-e9ae-4186-97c6-9478eddda245)]
|
[scriptable, uuid(47f8d36d-1d67-43cb-befd-d2f4720ac568)]
|
||||||
interface nsIPerformanceStats: nsISupports {
|
interface nsIPerformanceStats: nsISupports {
|
||||||
/**
|
/**
|
||||||
* An identifier unique to the component.
|
* An identifier unique to the component.
|
||||||
|
@ -32,16 +32,6 @@ interface nsIPerformanceStats: nsISupports {
|
||||||
*/
|
*/
|
||||||
readonly attribute AString groupId;
|
readonly attribute AString groupId;
|
||||||
|
|
||||||
/**
|
|
||||||
* If this component is part of a larger component, the larger
|
|
||||||
* component. Otherwise, null.
|
|
||||||
*
|
|
||||||
* As of this writing, there can be at most two levels of components:
|
|
||||||
* - compartments (a single module, iframe, etc.);
|
|
||||||
* - groups (an entire add-on, an entire webpage, etc.).
|
|
||||||
*/
|
|
||||||
readonly attribute AString parentId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the component:
|
* The name of the component:
|
||||||
* - for the process itself, "<process>";
|
* - for the process itself, "<process>";
|
||||||
|
@ -122,7 +112,7 @@ interface nsIPerformanceSnapshot: nsISupports {
|
||||||
nsIPerformanceStats getProcessData();
|
nsIPerformanceStats getProcessData();
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(60973d54-13e2-455c-a3c6-84dea5dfc8b9)]
|
[scriptable, builtinclass, uuid(0469e6af-95c3-4961-a385-4bc009128939)]
|
||||||
interface nsIPerformanceStatsService : nsISupports {
|
interface nsIPerformanceStatsService : nsISupports {
|
||||||
/**
|
/**
|
||||||
* `true` if we should monitor CPOW, `false` otherwise.
|
* `true` if we should monitor CPOW, `false` otherwise.
|
||||||
|
@ -134,13 +124,6 @@ interface nsIPerformanceStatsService : nsISupports {
|
||||||
*/
|
*/
|
||||||
[implicit_jscontext] attribute bool isMonitoringJank;
|
[implicit_jscontext] attribute bool isMonitoringJank;
|
||||||
|
|
||||||
/**
|
|
||||||
* `true` if all compartments need to be monitored individually,
|
|
||||||
* `false` if only performance groups (i.e. entire add-ons, entire
|
|
||||||
* webpages, etc.) need to be monitored.
|
|
||||||
*/
|
|
||||||
[implicit_jscontext] attribute bool isMonitoringPerCompartment;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capture a snapshot of the performance data.
|
* Capture a snapshot of the performance data.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
class nsPerformanceStats: public nsIPerformanceStats {
|
class nsPerformanceStats: public nsIPerformanceStats {
|
||||||
public:
|
public:
|
||||||
nsPerformanceStats(const nsAString& aName,
|
nsPerformanceStats(const nsAString& aName,
|
||||||
nsIPerformanceStats* aParent,
|
|
||||||
const nsAString& aGroupId,
|
const nsAString& aGroupId,
|
||||||
const nsAString& aAddonId,
|
const nsAString& aAddonId,
|
||||||
const nsAString& aTitle,
|
const nsAString& aTitle,
|
||||||
|
@ -45,10 +44,6 @@ public:
|
||||||
, mIsSystem(aIsSystem)
|
, mIsSystem(aIsSystem)
|
||||||
, mPerformanceData(aPerformanceData)
|
, mPerformanceData(aPerformanceData)
|
||||||
{
|
{
|
||||||
if (aParent) {
|
|
||||||
mozilla::DebugOnly<nsresult> rv = aParent->GetGroupId(mParentId);
|
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
explicit nsPerformanceStats() {}
|
explicit nsPerformanceStats() {}
|
||||||
|
|
||||||
|
@ -66,12 +61,6 @@ public:
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* readonly attribute AString parentId; */
|
|
||||||
NS_IMETHOD GetParentId(nsAString& aParentId) override {
|
|
||||||
aParentId.Assign(mParentId);
|
|
||||||
return NS_OK;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* readonly attribute AString addonId; */
|
/* readonly attribute AString addonId; */
|
||||||
NS_IMETHOD GetAddonId(nsAString& aAddonId) override {
|
NS_IMETHOD GetAddonId(nsAString& aAddonId) override {
|
||||||
aAddonId.Assign(mAddonId);
|
aAddonId.Assign(mAddonId);
|
||||||
|
@ -135,7 +124,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsString mName;
|
nsString mName;
|
||||||
nsString mParentId;
|
|
||||||
nsString mGroupId;
|
nsString mGroupId;
|
||||||
nsString mAddonId;
|
nsString mAddonId;
|
||||||
nsString mTitle;
|
nsString mTitle;
|
||||||
|
@ -171,18 +159,13 @@ private:
|
||||||
* entire process, rather than the statistics for a specific set of
|
* entire process, rather than the statistics for a specific set of
|
||||||
* compartments.
|
* compartments.
|
||||||
*/
|
*/
|
||||||
already_AddRefed<nsIPerformanceStats> ImportStats(JSContext* cx, const js::PerformanceData& data, uint64_t uid, nsIPerformanceStats* parent);
|
already_AddRefed<nsIPerformanceStats> ImportStats(JSContext* cx, const js::PerformanceData& data, uint64_t uid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callbacks for iterating through the `PerformanceStats` of a runtime.
|
* Callbacks for iterating through the `PerformanceStats` of a runtime.
|
||||||
*/
|
*/
|
||||||
bool IterPerformanceStatsCallbackInternal(JSContext* cx,
|
bool IterPerformanceStatsCallbackInternal(JSContext* cx, const js::PerformanceData& stats, uint64_t uid);
|
||||||
const js::PerformanceData& ownStats, const uint64_t ownId,
|
static bool IterPerformanceStatsCallback(JSContext* cx, const js::PerformanceData& stats, uint64_t uid, void* self);
|
||||||
const uint64_t* parentId);
|
|
||||||
static bool IterPerformanceStatsCallback(JSContext* cx,
|
|
||||||
const js::PerformanceData& ownStats, const uint64_t ownId,
|
|
||||||
const uint64_t* parentId,
|
|
||||||
void* self);
|
|
||||||
|
|
||||||
// If the context represents a window, extract the title and window ID.
|
// If the context represents a window, extract the title and window ID.
|
||||||
// Otherwise, extract "" and 0.
|
// Otherwise, extract "" and 0.
|
||||||
|
@ -192,11 +175,6 @@ private:
|
||||||
void GetGroupId(JSContext*,
|
void GetGroupId(JSContext*,
|
||||||
uint64_t uid,
|
uint64_t uid,
|
||||||
nsString& groupId);
|
nsString& groupId);
|
||||||
|
|
||||||
static void GetName(JSContext*,
|
|
||||||
JS::Handle<JSObject*> global,
|
|
||||||
nsString& name);
|
|
||||||
|
|
||||||
// If the context presents an add-on, extract the addon ID.
|
// If the context presents an add-on, extract the addon ID.
|
||||||
// Otherwise, extract "".
|
// Otherwise, extract "".
|
||||||
static void GetAddonId(JSContext*,
|
static void GetAddonId(JSContext*,
|
||||||
|
@ -210,7 +188,6 @@ private:
|
||||||
private:
|
private:
|
||||||
nsCOMArray<nsIPerformanceStats> mComponentsData;
|
nsCOMArray<nsIPerformanceStats> mComponentsData;
|
||||||
nsCOMPtr<nsIPerformanceStats> mProcessData;
|
nsCOMPtr<nsIPerformanceStats> mProcessData;
|
||||||
nsBaseHashtable<nsUint64HashKey, nsCOMPtr<nsIPerformanceStats>, nsCOMPtr<nsIPerformanceStats> > mCachedStats;
|
|
||||||
uint64_t mProcessId;
|
uint64_t mProcessId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -296,44 +273,8 @@ nsPerformanceSnapshot::GetIsSystem(JSContext*,
|
||||||
return nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(global));
|
return nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(global));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
|
||||||
void
|
|
||||||
nsPerformanceSnapshot::GetName(JSContext* cx,
|
|
||||||
JS::Handle<JSObject*> global,
|
|
||||||
nsString& name)
|
|
||||||
{
|
|
||||||
nsAutoCString cname;
|
|
||||||
do {
|
|
||||||
// Attempt to use the URL as name.
|
|
||||||
nsCOMPtr<nsIPrincipal> principal = nsContentUtils::ObjectPrincipal(global);
|
|
||||||
if (!principal) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri;
|
|
||||||
nsresult rv = principal->GetURI(getter_AddRefs(uri));
|
|
||||||
if (NS_FAILED(rv) || !uri) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = uri->GetSpec(cname);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
name.Assign(NS_ConvertUTF8toUTF16(cname));
|
|
||||||
return;
|
|
||||||
} while(false);
|
|
||||||
xpc::GetCurrentCompartmentName(cx, cname);
|
|
||||||
name.Assign(NS_ConvertUTF8toUTF16(cname));
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<nsIPerformanceStats>
|
already_AddRefed<nsIPerformanceStats>
|
||||||
nsPerformanceSnapshot::ImportStats(JSContext* cx, const js::PerformanceData& performance, const uint64_t uid, nsIPerformanceStats* parent) {
|
nsPerformanceSnapshot::ImportStats(JSContext* cx, const js::PerformanceData& performance, const uint64_t uid) {
|
||||||
if (performance.ticks == 0) {
|
|
||||||
// Ignore compartments with no activity.
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
|
JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
|
||||||
|
|
||||||
if (!global) {
|
if (!global) {
|
||||||
|
@ -352,34 +293,28 @@ nsPerformanceSnapshot::ImportStats(JSContext* cx, const js::PerformanceData& per
|
||||||
uint64_t windowId;
|
uint64_t windowId;
|
||||||
GetWindowData(cx, title, &windowId);
|
GetWindowData(cx, title, &windowId);
|
||||||
|
|
||||||
nsString name;
|
nsAutoString name;
|
||||||
GetName(cx, global, name);
|
nsAutoCString cname;
|
||||||
|
xpc::GetCurrentCompartmentName(cx, cname);
|
||||||
|
name.Assign(NS_ConvertUTF8toUTF16(cname));
|
||||||
|
|
||||||
bool isSystem = GetIsSystem(cx, global);
|
bool isSystem = GetIsSystem(cx, global);
|
||||||
|
|
||||||
nsCOMPtr<nsIPerformanceStats> result =
|
nsCOMPtr<nsIPerformanceStats> result =
|
||||||
new nsPerformanceStats(name, parent, groupId, addonId, title, windowId, isSystem, performance);
|
new nsPerformanceStats(name, groupId, addonId, title, windowId, isSystem, performance);
|
||||||
return result.forget();
|
return result.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ bool
|
/*static*/ bool
|
||||||
nsPerformanceSnapshot::IterPerformanceStatsCallback(JSContext* cx,
|
nsPerformanceSnapshot::IterPerformanceStatsCallback(JSContext* cx, const js::PerformanceData& stats, const uint64_t uid, void* self) {
|
||||||
const js::PerformanceData& stats, const uint64_t id,
|
return reinterpret_cast<nsPerformanceSnapshot*>(self)->IterPerformanceStatsCallbackInternal(cx, stats, uid);
|
||||||
const uint64_t* parentId,
|
|
||||||
void* self) {
|
|
||||||
return reinterpret_cast<nsPerformanceSnapshot*>(self)->IterPerformanceStatsCallbackInternal(cx, stats, id, parentId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nsPerformanceSnapshot::IterPerformanceStatsCallbackInternal(JSContext* cx,
|
nsPerformanceSnapshot::IterPerformanceStatsCallbackInternal(JSContext* cx, const js::PerformanceData& stats, const uint64_t uid) {
|
||||||
const js::PerformanceData& stats, const uint64_t id,
|
nsCOMPtr<nsIPerformanceStats> result = ImportStats(cx, stats, uid);
|
||||||
const uint64_t* parentId) {
|
|
||||||
|
|
||||||
nsCOMPtr<nsIPerformanceStats> parent = parentId ? mCachedStats.Get(*parentId) : nullptr;
|
|
||||||
nsCOMPtr<nsIPerformanceStats> result = ImportStats(cx, stats, id, parent);
|
|
||||||
if (result) {
|
if (result) {
|
||||||
mComponentsData.AppendElement(result);
|
mComponentsData.AppendElement(result);
|
||||||
mCachedStats.Put(id, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -393,12 +328,8 @@ nsPerformanceSnapshot::Init(JSContext* cx, uint64_t processId) {
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoString processGroupId;
|
|
||||||
processGroupId.AssignLiteral("process: ");
|
|
||||||
processGroupId.AppendInt(processId);
|
|
||||||
mProcessData = new nsPerformanceStats(NS_LITERAL_STRING("<process>"), // name
|
mProcessData = new nsPerformanceStats(NS_LITERAL_STRING("<process>"), // name
|
||||||
nullptr, // parent
|
NS_LITERAL_STRING("<process:?>"), // group id
|
||||||
processGroupId, // group id
|
|
||||||
NS_LITERAL_STRING(""), // add-on id
|
NS_LITERAL_STRING(""), // add-on id
|
||||||
NS_LITERAL_STRING(""), // title
|
NS_LITERAL_STRING(""), // title
|
||||||
0, // window id
|
0, // window id
|
||||||
|
@ -474,20 +405,6 @@ NS_IMETHODIMP nsPerformanceStatsService::SetIsMonitoringJank(JSContext* cx, bool
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
NS_IMETHODIMP nsPerformanceStatsService::GetIsMonitoringPerCompartment(JSContext* cx, bool *aIsStopwatchActive)
|
|
||||||
{
|
|
||||||
JSRuntime *runtime = JS_GetRuntime(cx);
|
|
||||||
*aIsStopwatchActive = js::GetStopwatchIsMonitoringPerCompartment(runtime);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
NS_IMETHODIMP nsPerformanceStatsService::SetIsMonitoringPerCompartment(JSContext* cx, bool aIsStopwatchActive)
|
|
||||||
{
|
|
||||||
JSRuntime *runtime = JS_GetRuntime(cx);
|
|
||||||
if (!js::SetStopwatchIsMonitoringPerCompartment(runtime, aIsStopwatchActive)) {
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* readonly attribute nsIPerformanceSnapshot snapshot; */
|
/* readonly attribute nsIPerformanceSnapshot snapshot; */
|
||||||
NS_IMETHODIMP nsPerformanceStatsService::GetSnapshot(JSContext* cx, nsIPerformanceSnapshot * *aSnapshot)
|
NS_IMETHODIMP nsPerformanceStatsService::GetSnapshot(JSContext* cx, nsIPerformanceSnapshot * *aSnapshot)
|
||||||
|
|
|
@ -28,7 +28,7 @@ function frameScript() {
|
||||||
getService(Ci.nsIPerformanceStatsService);
|
getService(Ci.nsIPerformanceStatsService);
|
||||||
|
|
||||||
// Make sure that the stopwatch is now active.
|
// Make sure that the stopwatch is now active.
|
||||||
let monitor = PerformanceStats.getMonitor(["jank", "cpow", "ticks", "compartments"]);
|
let monitor = PerformanceStats.getMonitor(["jank", "cpow", "ticks"]);
|
||||||
|
|
||||||
addMessageListener("compartments-test:getStatistics", () => {
|
addMessageListener("compartments-test:getStatistics", () => {
|
||||||
try {
|
try {
|
||||||
|
@ -158,10 +158,8 @@ function monotinicity_tester(source, testName) {
|
||||||
["jank", "totalSystemTime"],
|
["jank", "totalSystemTime"],
|
||||||
["cpow", "totalCPOWTime"]
|
["cpow", "totalCPOWTime"]
|
||||||
]) {
|
]) {
|
||||||
// Note that we cannot expect components data to be always smaller
|
SilentAssert.leq(item[probe][k], snapshot.processData[probe][k],
|
||||||
// than process data, as `getrusage` & co are not monotonic.
|
`Sanity check (${testName}): component has a lower ${k} than process`);
|
||||||
SilentAssert.leq(item[probe][k], 2 * snapshot.processData[probe][k],
|
|
||||||
`Sanity check (${testName}): ${k} of component is not impossibly larger than that of process`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let key = item.groupId;
|
let key = item.groupId;
|
||||||
|
@ -171,24 +169,6 @@ function monotinicity_tester(source, testName) {
|
||||||
}
|
}
|
||||||
map.set(key, item);
|
map.set(key, item);
|
||||||
}
|
}
|
||||||
for (let item of snapshot.componentsData) {
|
|
||||||
if (!item.parentId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let parent = map.get(item.parentId);
|
|
||||||
SilentAssert.ok(parent, `The parent exists ${item.parentId}`);
|
|
||||||
|
|
||||||
for (let [probe, k] of [
|
|
||||||
["jank", "totalUserTime"],
|
|
||||||
["jank", "totalSystemTime"],
|
|
||||||
["cpow", "totalCPOWTime"]
|
|
||||||
]) {
|
|
||||||
// Note that we cannot expect components data to be always smaller
|
|
||||||
// than parent data, as `getrusage` & co are not monotonic.
|
|
||||||
SilentAssert.leq(item[probe][k], 2 * parent[probe][k],
|
|
||||||
`Sanity check (${testName}): ${k} of component is not impossibly larger than that of parent`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let [key, item] of map) {
|
for (let [key, item] of map) {
|
||||||
sanityCheck(previous.componentsMap.get(key), item);
|
sanityCheck(previous.componentsMap.get(key), item);
|
||||||
previous.componentsMap.set(key, item);
|
previous.componentsMap.set(key, item);
|
||||||
|
|
|
@ -19,12 +19,10 @@ let promiseStatistics = Task.async(function*(name) {
|
||||||
let componentsData = [];
|
let componentsData = [];
|
||||||
let componentsEnum = snapshot.getComponentsData().enumerate();
|
let componentsEnum = snapshot.getComponentsData().enumerate();
|
||||||
while (componentsEnum.hasMoreElements()) {
|
while (componentsEnum.hasMoreElements()) {
|
||||||
let data = componentsEnum.getNext().QueryInterface(Ci.nsIPerformanceStats);
|
componentsData.push(componentsEnum.getNext().QueryInterface(Ci.nsIPerformanceStats));
|
||||||
let normalized = JSON.parse(JSON.stringify(data));
|
|
||||||
componentsData.push(data);
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
processData: JSON.parse(JSON.stringify(snapshot.getProcessData())),
|
processData: snapshot.getProcessData(),
|
||||||
componentsData
|
componentsData
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -37,19 +35,11 @@ let promiseSetMonitoring = Task.async(function*(to) {
|
||||||
yield Promise.resolve();
|
yield Promise.resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
let promiseSetPerCompartment = Task.async(function*(to) {
|
|
||||||
let service = Cc["@mozilla.org/toolkit/performance-stats-service;1"].
|
|
||||||
getService(Ci.nsIPerformanceStatsService);
|
|
||||||
service.isMonitoringPerCompartment = to;
|
|
||||||
yield Promise.resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
function getBuiltinStatistics(name, snapshot) {
|
function getBuiltinStatistics(name, snapshot) {
|
||||||
let stats = snapshot.componentsData.find(stats =>
|
let stats = snapshot.componentsData.find(stats =>
|
||||||
stats.isSystem && !stats.addonId
|
stats.isSystem && !stats.addonId
|
||||||
);
|
);
|
||||||
do_print(`Built-in statistics for ${name} were ${stats?"":"not "}found`);
|
do_print(`Built-in statistics for ${name} were ${stats?"":"not "}found`);
|
||||||
do_print(JSON.stringify(snapshot.componentsData, null, "\t"));
|
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,25 +57,17 @@ function burnCPU(ms) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureEquals(snap1, snap2, name) {
|
function ensureEquals(snap1, snap2, name) {
|
||||||
for (let k of Object.keys(snap1.processData)) {
|
Assert.equal(
|
||||||
if (k == "ticks") {
|
JSON.stringify(snap1.processData),
|
||||||
// Ticks monitoring cannot be deactivated
|
JSON.stringify(snap2.processData),
|
||||||
continue;
|
"Same process data: " + name);
|
||||||
}
|
|
||||||
Assert.equal(snap1.processData[k], snap2.processData[k], `Same process data value ${k} (${name})`)
|
|
||||||
}
|
|
||||||
let stats1 = snap1.componentsData.sort((a, b) => a.name <= b.name);
|
let stats1 = snap1.componentsData.sort((a, b) => a.name <= b.name);
|
||||||
let stats2 = snap2.componentsData.sort((a, b) => a.name <= b.name);
|
let stats2 = snap2.componentsData.sort((a, b) => a.name <= b.name);
|
||||||
Assert.equal(stats1.length, stats2.length, `Same number of components (${name})`);
|
Assert.equal(
|
||||||
for (let i = 0; i < stats1.length; ++i) {
|
JSON.stringify(stats1),
|
||||||
for (let k of Object.keys(stats1[i])) {
|
JSON.stringify(stats2),
|
||||||
if (k == "ticks") {
|
"Same components data: " + name
|
||||||
// Ticks monitoring cannot be deactivated
|
);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Assert.equal(stats1[i][k], stats1[i][k], `Same component data value ${i} ${k} (${name})`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasLowPrecision() {
|
function hasLowPrecision() {
|
||||||
|
@ -106,7 +88,6 @@ function hasLowPrecision() {
|
||||||
|
|
||||||
add_task(function* test_measure() {
|
add_task(function* test_measure() {
|
||||||
let skipPrecisionTests = hasLowPrecision();
|
let skipPrecisionTests = hasLowPrecision();
|
||||||
yield promiseSetPerCompartment(false);
|
|
||||||
|
|
||||||
do_print("Burn CPU without the stopwatch");
|
do_print("Burn CPU without the stopwatch");
|
||||||
yield promiseSetMonitoring(false);
|
yield promiseSetMonitoring(false);
|
||||||
|
@ -156,14 +137,4 @@ add_task(function* test_measure() {
|
||||||
Assert.equal(builtin2.totalCPOWTime, builtin1.totalCPOWTime, "No CPOW for built-in statistics");
|
Assert.equal(builtin2.totalCPOWTime, builtin1.totalCPOWTime, "No CPOW for built-in statistics");
|
||||||
Assert.equal(builtin4.totalUserTime, builtin3.totalUserTime, "After deactivating the stopwatch, we didn't count any time for the built-in");
|
Assert.equal(builtin4.totalUserTime, builtin3.totalUserTime, "After deactivating the stopwatch, we didn't count any time for the built-in");
|
||||||
Assert.equal(builtin4.totalCPOWTime, builtin3.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time for the built-in");
|
Assert.equal(builtin4.totalCPOWTime, builtin3.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time for the built-in");
|
||||||
|
|
||||||
// Ideally, we should be able to look for test_compartments.js, but
|
|
||||||
// it doesn't have its own compartment.
|
|
||||||
for (let stats of [stats1, stats2, stats3, stats4]) {
|
|
||||||
Assert.ok(!stats.componentsData.find(x => x.name.includes("Task.jsm")), "At this stage, Task.jsm doesn't show up in the components data");
|
|
||||||
}
|
|
||||||
yield promiseSetPerCompartment(true);
|
|
||||||
burnCPU(300);
|
|
||||||
let stats5 = yield promiseStatistics("With per-compartment monitoring");
|
|
||||||
Assert.ok(stats5.componentsData.find(x => x.name.includes("Task.jsm")), "With per-compartment monitoring, test_compartments.js shows up");
|
|
||||||
});
|
});
|
||||||
|
|
Загрузка…
Ссылка в новой задаче