Backed out changeset 00726df4997c (bug 1190074) for bustage on a CLOSED TREE

This commit is contained in:
Carsten "Tomcat" Book 2015-08-03 17:06:15 +02:00
Родитель 47e3ab6e7c
Коммит 9a0fd3701a
5 изменённых файлов: 186 добавлений и 146 удалений

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

@ -368,12 +368,12 @@ IterPerformanceStats(JSContext* cx,
continue; continue;
} }
js::AutoCompartment autoCompartment(cx, compartment); js::AutoCompartment autoCompartment(cx, compartment);
mozilla::RefPtr<PerformanceGroup> ownGroup = compartment->performanceMonitoring.getOwnGroup(); PerformanceGroup* ownGroup = compartment->performanceMonitoring.getOwnGroup(cx);
if (ownGroup->data.ticks == 0) { if (ownGroup->data.ticks == 0) {
// Don't report compartments that have never been used. // Don't report compartments that have never been used.
continue; continue;
} }
mozilla::RefPtr<PerformanceGroup> sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx); PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx);
if (!(*walker)(cx, if (!(*walker)(cx,
ownGroup->data, ownGroup->uid, &sharedGroup->uid, ownGroup->data, ownGroup->uid, &sharedGroup->uid,
closure)) { closure)) {
@ -383,7 +383,7 @@ IterPerformanceStats(JSContext* cx,
} }
// Finally, report the process stats // Finally, report the process stats
*processStats = rt->stopwatch.performance.getOwnGroup()->data; *processStats = rt->stopwatch.performance;
return true; return true;
} }

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

@ -13,7 +13,6 @@
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "mozilla/Range.h" #include "mozilla/Range.h"
#include "mozilla/RangedPtr.h" #include "mozilla/RangedPtr.h"
#include "mozilla/RefPtr.h"
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h> #include <stddef.h>
@ -5515,22 +5514,15 @@ struct PerformanceGroup {
stopwatch_ = nullptr; stopwatch_ = nullptr;
} }
// Refcounting. For use with mozilla::RefPtr. explicit PerformanceGroup(JSContext* cx, void* key);
void AddRef(); ~PerformanceGroup()
void Release(); {
MOZ_ASSERT(refCount_ == 0);
// Construct a PerformanceGroup for a single compartment. }
explicit PerformanceGroup(JSRuntime* rt); private:
// Construct a PerformanceGroup for a group of compartments.
explicit PerformanceGroup(JSContext* rt, void* key);
private:
PerformanceGroup& operator=(const PerformanceGroup&) = delete; PerformanceGroup& operator=(const PerformanceGroup&) = delete;
PerformanceGroup(const PerformanceGroup&) = delete; PerformanceGroup(const PerformanceGroup&) = delete;
JSRuntime* runtime_;
// The stopwatch currently monitoring the group, // The stopwatch currently monitoring the group,
// or `nullptr` if none. Used ony for comparison. // or `nullptr` if none. Used ony for comparison.
const AutoStopwatch* stopwatch_; const AutoStopwatch* stopwatch_;
@ -5542,14 +5534,20 @@ private:
// The hash key for this PerformanceGroup. // The hash key for this PerformanceGroup.
void* const key_; void* const key_;
// A reference counter. // Increment/decrement the refcounter, return the updated value.
uint64_t incRefCount() {
MOZ_ASSERT(refCount_ + 1 > 0);
return ++refCount_;
}
uint64_t decRefCount() {
MOZ_ASSERT(refCount_ > 0);
return --refCount_;
}
friend struct PerformanceGroupHolder;
private:
// A reference counter. Maintained by PerformanceGroupHolder.
uint64_t refCount_; uint64_t refCount_;
// `true` if this PerformanceGroup may be shared by several
// compartments, `false` if it is dedicated to a single
// compartment.
const bool isSharedGroup_;
}; };
// //
@ -5566,7 +5564,7 @@ struct PerformanceGroupHolder {
js::PerformanceGroup* getSharedGroup(JSContext*); js::PerformanceGroup* getSharedGroup(JSContext*);
// Get the own group. // Get the own group.
js::PerformanceGroup* getOwnGroup(); js::PerformanceGroup* getOwnGroup(JSContext*);
// `true` if the this holder is currently associated to a shared // `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
@ -5586,6 +5584,8 @@ struct PerformanceGroupHolder {
explicit PerformanceGroupHolder(JSRuntime* runtime) explicit PerformanceGroupHolder(JSRuntime* runtime)
: runtime_(runtime) : runtime_(runtime)
, sharedGroup_(nullptr)
, ownGroup_(nullptr)
{ } { }
~PerformanceGroupHolder(); ~PerformanceGroupHolder();
@ -5600,8 +5600,8 @@ struct PerformanceGroupHolder {
// The PerformanceGroups held by this object. // The PerformanceGroups held by this object.
// Initially set to `nullptr` until the first call to `getGroup`. // Initially set to `nullptr` until the first call to `getGroup`.
// May be reset to `nullptr` by a call to `unlink`. // May be reset to `nullptr` by a call to `unlink`.
mozilla::RefPtr<js::PerformanceGroup> sharedGroup_; js::PerformanceGroup* sharedGroup_;
mozilla::RefPtr<js::PerformanceGroup> ownGroup_; js::PerformanceGroup* ownGroup_;
}; };
/** /**

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

@ -389,6 +389,22 @@ class AutoStopwatch final
// loop. Used only for comparison. // loop. Used only for comparison.
uint64_t iteration_; 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. // `true` if we are monitoring jank, `false` otherwise.
bool isMonitoringJank_; bool isMonitoringJank_;
// `true` if we are monitoring CPOW, `false` otherwise. // `true` if we are monitoring CPOW, `false` otherwise.
@ -399,20 +415,6 @@ class AutoStopwatch final
uint64_t systemTimeStart_; uint64_t systemTimeStart_;
uint64_t CPOWTimeStart_; uint64_t CPOWTimeStart_;
// The performance group shared by this compartment and possibly
// others, or `nullptr` if another AutoStopwatch is already in
// charge of monitoring that group.
mozilla::RefPtr<js::PerformanceGroup> sharedGroup_;
// The toplevel group, representing the entire process, or `nullptr`
// if another AutoStopwatch is already in charge of monitoring that group.
mozilla::RefPtr<js::PerformanceGroup> topGroup_;
// The performance group specific to this compartment, or
// `nullptr` if another AutoStopwatch is already in charge of
// monitoring that group.
mozilla::RefPtr<js::PerformanceGroup> ownGroup_;
public: 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
@ -422,6 +424,9 @@ 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)
, isMonitoringForSelf_(false)
, isMonitoringForTop_(false)
, isMonitoringJank_(false) , isMonitoringJank_(false)
, isMonitoringCPOW_(false) , isMonitoringCPOW_(false)
, userTimeStart_(0) , userTimeStart_(0)
@ -437,23 +442,52 @@ class AutoStopwatch final
JSRuntime* runtime = cx_->runtime(); JSRuntime* runtime = cx_->runtime();
iteration_ = runtime->stopwatch.iteration; iteration_ = runtime->stopwatch.iteration;
sharedGroup_ = acquireGroup(compartment->performanceMonitoring.getSharedGroup(cx)); PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx);
if (sharedGroup_) if (!sharedGroup) {
topGroup_ = acquireGroup(runtime->stopwatch.performance.getOwnGroup()); // Either this Runtime is not configured for Performance Monitoring, or we couldn't
// allocate the group, or there was a problem with the hashtable.
return;
}
if (runtime->stopwatch.isMonitoringPerCompartment()) if (!sharedGroup->hasStopwatch(iteration_)) {
ownGroup_ = acquireGroup(compartment->performanceMonitoring.getOwnGroup()); // We are now in charge of monitoring this group for the tick,
// until destruction of `this` or until we enter a nested event
// loop and `iteration_` is incremented.
sharedGroup->acquireStopwatch(iteration_, this);
isMonitoringForGroup_ = true;
}
if (!sharedGroup_ && !ownGroup_) { PerformanceGroup* ownGroup = nullptr;
if (runtime->stopwatch.isMonitoringPerCompartment()) {
// As above, but for the group representing just this compartment.
ownGroup = compartment->performanceMonitoring.getOwnGroup(cx);
if (!ownGroup->hasStopwatch(iteration_)) {
ownGroup->acquireStopwatch(iteration_, this);
isMonitoringForSelf_ = true;
}
}
if (runtime->stopwatch.isEmpty) {
// This is the topmost stopwatch on the stack.
// It will be in charge of updating the per-process
// performance data.
runtime->stopwatch.isEmpty = false;
isMonitoringForTop_ = true;
MOZ_ASSERT(isMonitoringForGroup_);
}
if (!isMonitoringForGroup_ && !isMonitoringForSelf_) {
// 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;
} }
enter(); enter();
} }
~AutoStopwatch() ~AutoStopwatch() {
{ if (!isMonitoringForGroup_ && !isMonitoringForSelf_) {
if (!sharedGroup_ && !ownGroup_) {
// We are not in charge of monitoring anything. // We are not in charge of monitoring anything.
// (isMonitoringForTop_ implies isMonitoringForGroup_, // (isMonitoringForTop_ implies isMonitoringForGroup_,
// so we do not need to check it) // so we do not need to check it)
@ -471,19 +505,31 @@ class AutoStopwatch final
return; return;
} }
releaseGroup(sharedGroup_);
releaseGroup(topGroup_);
releaseGroup(ownGroup_);
// Finish and commit measures // Finish and commit measures
exit(); exit();
// Now release groups.
if (isMonitoringForGroup_) {
PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx_);
MOZ_ASSERT(sharedGroup);
sharedGroup->releaseStopwatch(iteration_, this);
}
if (isMonitoringForSelf_) {
PerformanceGroup* ownGroup = compartment->performanceMonitoring.getOwnGroup(cx_);
MOZ_ASSERT(ownGroup);
ownGroup->releaseStopwatch(iteration_, this);
}
if (isMonitoringForTop_)
runtime->stopwatch.isEmpty = true;
} }
private: private:
void enter() { void enter() {
JSRuntime* runtime = cx_->runtime(); JSRuntime* runtime = cx_->runtime();
if (runtime->stopwatch.isMonitoringCPOW()) { if (runtime->stopwatch.isMonitoringCPOW()) {
CPOWTimeStart_ = runtime->stopwatch.performance.getOwnGroup()->data.totalCPOWTime; CPOWTimeStart_ = runtime->stopwatch.performance.totalCPOWTime;
isMonitoringCPOW_ = true; isMonitoringCPOW_ = true;
} }
@ -517,54 +563,46 @@ class AutoStopwatch final
uint64_t CPOWTimeDelta = 0; uint64_t CPOWTimeDelta = 0;
if (isMonitoringCPOW_ && runtime->stopwatch.isMonitoringCPOW()) { if (isMonitoringCPOW_ && runtime->stopwatch.isMonitoringCPOW()) {
// We were monitoring CPOW when we entered and we still are. // We were monitoring CPOW when we entered and we still are.
CPOWTimeDelta = runtime->stopwatch.performance.getOwnGroup()->data.totalCPOWTime - CPOWTimeStart_; CPOWTimeDelta = runtime->stopwatch.performance.totalCPOWTime - CPOWTimeStart_;
} }
commitDeltasToGroups(userTimeDelta, systemTimeDelta, CPOWTimeDelta); commitDeltasToGroups(userTimeDelta, systemTimeDelta, CPOWTimeDelta);
} }
// Attempt to acquire a group void commitDeltasToGroups(uint64_t userTimeDelta,
// If the group is `null` or if the group already has a stopwatch, uint64_t systemTimeDelta,
// do nothing and return `null`. uint64_t CPOWTimeDelta)
// Otherwise, bind the group to `this` for the current iteration {
// and return `group`. JSCompartment* compartment = cx_->compartment();
PerformanceGroup* acquireGroup(PerformanceGroup* group) {
if (!group)
return nullptr;
if (group->hasStopwatch(iteration_)) PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx_);
return nullptr; MOZ_ASSERT(sharedGroup);
applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, sharedGroup->data);
group->acquireStopwatch(iteration_, this); if (isMonitoringForSelf_) {
return group; 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);
}
} }
// Release a group.
// Noop if `group` is null or if `this` is not the stopwatch
// of `group` for the current iteration.
void releaseGroup(PerformanceGroup* group) {
if (group)
group->releaseStopwatch(iteration_, this);
}
void commitDeltasToGroups(uint64_t userTimeDelta, uint64_t systemTimeDelta, void applyDeltas(uint64_t userTimeDelta,
uint64_t CPOWTimeDelta) const { uint64_t systemTimeDelta,
applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, sharedGroup_); uint64_t CPOWTimeDelta,
applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, topGroup_); PerformanceData& data) const {
applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, ownGroup_);
}
void applyDeltas(uint64_t userTimeDelta, uint64_t systemTimeDelta, data.ticks++;
uint64_t CPOWTimeDelta, PerformanceGroup* group) const {
if (!group)
return;
group->data.ticks++;
uint64_t totalTimeDelta = userTimeDelta + systemTimeDelta; uint64_t totalTimeDelta = userTimeDelta + systemTimeDelta;
group->data.totalUserTime += userTimeDelta; data.totalUserTime += userTimeDelta;
group->data.totalSystemTime += systemTimeDelta; data.totalSystemTime += systemTimeDelta;
group->data.totalCPOWTime += CPOWTimeDelta; data.totalCPOWTime += CPOWTimeDelta;
// Update an array containing the number of times we have missed // Update an array containing the number of times we have missed
// at least 2^0 successive ms, 2^1 successive ms, ... // at least 2^0 successive ms, 2^1 successive ms, ...
@ -574,10 +612,10 @@ class AutoStopwatch final
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(group->data.durations) && duration < totalTimeDelta; i < ArrayLength(data.durations) && duration < totalTimeDelta;
++i, duration *= 2) ++i, duration *= 2)
{ {
group->data.durations[i]++; data.durations[i]++;
} }
} }

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

@ -222,8 +222,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
largeAllocationFailureCallback(nullptr), largeAllocationFailureCallback(nullptr),
oomCallback(nullptr), oomCallback(nullptr),
debuggerMallocSizeOf(ReturnZeroSize), debuggerMallocSizeOf(ReturnZeroSize),
lastAnimationTime(0), lastAnimationTime(0)
stopwatch(thisFromCtor())
{ {
setGCStoreBufferPtr(&gc.storeBuffer); setGCStoreBufferPtr(&gc.storeBuffer);
@ -931,17 +930,40 @@ js::PerformanceGroupHolder::getHashKey(JSContext* cx)
void void
js::PerformanceGroupHolder::unlink() js::PerformanceGroupHolder::unlink()
{ {
ownGroup_ = nullptr; if (ownGroup_) {
js_delete(ownGroup_);
ownGroup_ = nullptr;
}
if (!sharedGroup_) {
// The group has never been instantiated.
return;
}
js::PerformanceGroup* group = sharedGroup_;
sharedGroup_ = nullptr; sharedGroup_ = nullptr;
if (group->decRefCount() > 0) {
// The group has at least another owner.
return;
}
JSRuntime::Stopwatch::Groups::Ptr ptr =
runtime_->stopwatch.groups().lookup(group->key_);
MOZ_ASSERT(ptr);
runtime_->stopwatch.groups().remove(ptr);
js_delete(group);
} }
PerformanceGroup* PerformanceGroup*
js::PerformanceGroupHolder::getOwnGroup() js::PerformanceGroupHolder::getOwnGroup(JSContext* cx)
{ {
if (ownGroup_) if (ownGroup_)
return ownGroup_; return ownGroup_;
return ownGroup_ = runtime_->new_<PerformanceGroup>(runtime_); ownGroup_ = runtime_->new_<PerformanceGroup>(cx, nullptr);
return ownGroup_;
} }
PerformanceGroup* PerformanceGroup*
@ -963,58 +985,31 @@ js::PerformanceGroupHolder::getSharedGroup(JSContext* cx)
if (!sharedGroup_) if (!sharedGroup_)
return nullptr; return nullptr;
runtime_->stopwatch.groups().add(ptr, key, sharedGroup_); if (!runtime_->stopwatch.groups().add(ptr, key, sharedGroup_)) {
js_delete(sharedGroup_);
sharedGroup_ = nullptr;
return nullptr;
}
} }
sharedGroup_->incRefCount();
return sharedGroup_; return sharedGroup_;
} }
PerformanceData* PerformanceData*
js::GetPerformanceData(JSRuntime* rt) js::GetPerformanceData(JSRuntime* rt)
{ {
return &rt->stopwatch.performance.getOwnGroup()->data; return &rt->stopwatch.performance;
} }
js::PerformanceGroup::PerformanceGroup(JSRuntime* rt) js::PerformanceGroup::PerformanceGroup(JSContext* cx, void* key)
: uid(rt->stopwatch.uniqueId()), : uid(cx->runtime()->stopwatch.uniqueId())
runtime_(rt), , stopwatch_(nullptr)
stopwatch_(nullptr), , iteration_(0)
iteration_(0), , key_(key)
key_(nullptr), , refCount_(0)
refCount_(0),
isSharedGroup_(false)
{ }
js::PerformanceGroup::PerformanceGroup(JSContext* cx, void* key)
: uid(cx->runtime()->stopwatch.uniqueId()),
runtime_(cx->runtime()),
stopwatch_(nullptr),
iteration_(0),
key_(key),
refCount_(0),
isSharedGroup_(true)
{ }
void
js::PerformanceGroup::AddRef()
{ {
++refCount_;
}
void
js::PerformanceGroup::Release()
{
MOZ_ASSERT(refCount_ > 0);
--refCount_;
if (refCount_ > 0)
return;
if (!isSharedGroup_)
return;
JSRuntime::Stopwatch::Groups::Ptr ptr = runtime_->stopwatch.groups().lookup(key_);
MOZ_ASSERT(ptr);
runtime_->stopwatch.groups().remove(ptr);
js_delete(this);
} }
void void

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

@ -1512,11 +1512,6 @@ struct JSRuntime : public JS::shadow::Runtime,
return groups_; return groups_;
} }
/**
* Performance data on the entire runtime.
*/
js::PerformanceGroupHolder performance;
/** /**
* 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,
@ -1528,6 +1523,17 @@ struct JSRuntime : public JS::shadow::Runtime,
*/ */
uint64_t iteration; uint64_t iteration;
/**
* `true` if no stopwatch has been registered for the
* current run of the event loop, `false` until then.
*/
bool isEmpty;
/**
* Performance data on the entire runtime.
*/
js::PerformanceData performance;
/** /**
* Callback used to ask the embedding to determine in which * Callback used to ask the embedding to determine in which
* Performance Group the current execution belongs. Typically, this is * Performance Group the current execution belongs. Typically, this is
@ -1540,9 +1546,9 @@ struct JSRuntime : public JS::shadow::Runtime,
*/ */
JSCurrentPerfGroupCallback currentPerfGroupCallback; JSCurrentPerfGroupCallback currentPerfGroupCallback;
Stopwatch(JSRuntime* runtime) Stopwatch()
: performance(runtime) : iteration(0)
, iteration(0) , isEmpty(true)
, currentPerfGroupCallback(nullptr) , currentPerfGroupCallback(nullptr)
, isMonitoringJank_(false) , isMonitoringJank_(false)
, isMonitoringCPOW_(false) , isMonitoringCPOW_(false)
@ -1559,6 +1565,7 @@ struct JSRuntime : public JS::shadow::Runtime,
*/ */
void reset() { void reset() {
++iteration; ++iteration;
isEmpty = true;
} }
/** /**
* Activate/deactivate stopwatch measurement of jank. * Activate/deactivate stopwatch measurement of jank.