mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset d7d9bbfa72c5 (bug 674779) for m-bc orange on a CLOSED TREE
This commit is contained in:
parent
302e802646
commit
0bcfdb9d36
@ -19,11 +19,9 @@ CPOWTimer::~CPOWTimer()
|
|||||||
if (!obj)
|
if (!obj)
|
||||||
return;
|
return;
|
||||||
JSCompartment *compartment = js::GetObjectCompartment(obj);
|
JSCompartment *compartment = js::GetObjectCompartment(obj);
|
||||||
if (!compartment)
|
xpc::CompartmentPrivate *compartmentPrivate = xpc::CompartmentPrivate::Get(compartment);
|
||||||
|
if (!compartmentPrivate)
|
||||||
return;
|
return;
|
||||||
js::PerformanceData *performance = js::GetPerformanceData(compartment);
|
PRIntervalTime time = PR_IntervalNow() - startInterval;
|
||||||
if (!performance)
|
compartmentPrivate->CPOWTime += time;
|
||||||
return;
|
|
||||||
uint64_t time = PR_IntervalToMicroseconds(PR_IntervalNow() - startInterval);
|
|
||||||
performance->cpowTime += time;
|
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,6 @@ LOCAL_INCLUDES += [
|
|||||||
'/dom/base',
|
'/dom/base',
|
||||||
'/js/ipc',
|
'/js/ipc',
|
||||||
'/js/public',
|
'/js/public',
|
||||||
'/js/src',
|
|
||||||
'/js/xpconnect/src',
|
'/js/xpconnect/src',
|
||||||
'/js/xpconnect/wrappers',
|
'/js/xpconnect/wrappers',
|
||||||
]
|
]
|
||||||
|
@ -173,9 +173,8 @@ JS_GetCompartmentStats(JSRuntime *rt, CompartmentStatsVector &stats)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
CompartmentTimeStats *stat = &stats.back();
|
CompartmentTimeStats *stat = &stats.back();
|
||||||
|
stat->time = c.get()->totalTime;
|
||||||
stat->compartment = c.get();
|
stat->compartment = c.get();
|
||||||
stat->performance = stat->compartment->performance;
|
|
||||||
stat->isSystem = stat->compartment->isSystem;
|
|
||||||
stat->addonId = c.get()->addonId;
|
stat->addonId = c.get()->addonId;
|
||||||
if (rt->compartmentNameCallback) {
|
if (rt->compartmentNameCallback) {
|
||||||
(*rt->compartmentNameCallback)(rt, stat->compartment,
|
(*rt->compartmentNameCallback)(rt, stat->compartment,
|
||||||
@ -5802,11 +5801,3 @@ JS::GetObjectZone(JSObject *obj)
|
|||||||
{
|
{
|
||||||
return obj->zone();
|
return obj->zone();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(PerformanceData*)
|
|
||||||
js::GetPerformanceData(JSCompartment *c)
|
|
||||||
{
|
|
||||||
if (!c)
|
|
||||||
return nullptr;
|
|
||||||
return &c->performance;
|
|
||||||
}
|
|
||||||
|
@ -975,8 +975,8 @@ struct CompartmentTimeStats {
|
|||||||
char compartmentName[1024];
|
char compartmentName[1024];
|
||||||
JSAddonId *addonId;
|
JSAddonId *addonId;
|
||||||
JSCompartment *compartment;
|
JSCompartment *compartment;
|
||||||
bool isSystem;
|
uint64_t time; // microseconds
|
||||||
js::PerformanceData performance;
|
uint64_t cpowTime; // microseconds
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef js::Vector<CompartmentTimeStats, 0, js::SystemAllocPolicy> CompartmentStatsVector;
|
typedef js::Vector<CompartmentTimeStats, 0, js::SystemAllocPolicy> CompartmentStatsVector;
|
||||||
@ -5126,33 +5126,4 @@ StringifySavedFrameStack(JSContext *cx, HandleObject stack, MutableHandleString
|
|||||||
|
|
||||||
} /* namespace JS */
|
} /* namespace JS */
|
||||||
|
|
||||||
|
|
||||||
/* Stopwatch-based CPU monitoring. */
|
|
||||||
|
|
||||||
namespace js {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset any stopwatch currently measuring.
|
|
||||||
*
|
|
||||||
* This function is designed to be called when we process a new event.
|
|
||||||
*/
|
|
||||||
extern JS_PUBLIC_API(void)
|
|
||||||
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 */
|
#endif /* jsapi_h */
|
||||||
|
@ -50,6 +50,7 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
|
|||||||
#endif
|
#endif
|
||||||
global_(nullptr),
|
global_(nullptr),
|
||||||
enterCompartmentDepth(0),
|
enterCompartmentDepth(0),
|
||||||
|
totalTime(0),
|
||||||
data(nullptr),
|
data(nullptr),
|
||||||
objectMetadataCallback(nullptr),
|
objectMetadataCallback(nullptr),
|
||||||
lastAnimationTime(0),
|
lastAnimationTime(0),
|
||||||
|
@ -170,12 +170,18 @@ struct JSCompartment
|
|||||||
int64_t startInterval;
|
int64_t startInterval;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
js::PerformanceData performance;
|
int64_t totalTime;
|
||||||
void enter() {
|
void enter() {
|
||||||
|
if (addonId && !enterCompartmentDepth) {
|
||||||
|
startInterval = PRMJ_Now();
|
||||||
|
}
|
||||||
enterCompartmentDepth++;
|
enterCompartmentDepth++;
|
||||||
}
|
}
|
||||||
void leave() {
|
void leave() {
|
||||||
enterCompartmentDepth--;
|
enterCompartmentDepth--;
|
||||||
|
if (addonId && !enterCompartmentDepth) {
|
||||||
|
totalTime += (PRMJ_Now() - startInterval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bool hasBeenEntered() { return !!enterCompartmentDepth; }
|
bool hasBeenEntered() { return !!enterCompartmentDepth; }
|
||||||
|
|
||||||
|
@ -479,60 +479,6 @@ struct PerThreadDataFriendFields
|
|||||||
template <typename T> friend class JS::Rooted;
|
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 microseconds, 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()
|
|
||||||
: totalUserTime(0)
|
|
||||||
, totalSystemTime(0)
|
|
||||||
, ownUserTime(0)
|
|
||||||
, ownSystemTime(0)
|
|
||||||
, cpowTime(0)
|
|
||||||
, visits(0)
|
|
||||||
{
|
|
||||||
memset(missedFrames, 0, sizeof(missedFrames));
|
|
||||||
}
|
|
||||||
PerformanceData(const PerformanceData& from)
|
|
||||||
: 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 */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* jspubtd_h */
|
#endif /* jspubtd_h */
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "vm/Interpreter-inl.h"
|
#include "vm/Interpreter-inl.h"
|
||||||
|
|
||||||
#include "mozilla/ArrayUtils.h"
|
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/FloatingPoint.h"
|
#include "mozilla/FloatingPoint.h"
|
||||||
#include "mozilla/PodOperations.h"
|
#include "mozilla/PodOperations.h"
|
||||||
@ -53,13 +52,6 @@
|
|||||||
#include "vm/ScopeObject-inl.h"
|
#include "vm/ScopeObject-inl.h"
|
||||||
#include "vm/Stack-inl.h"
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
#if defined(XP_UNIX)
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#elif defined(XP_WIN)
|
|
||||||
#include <Processthreadsapi.h>
|
|
||||||
#include <Windows.h>
|
|
||||||
#endif // defined(XP_UNIX) || defined(XP_WIN)
|
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
@ -419,191 +411,11 @@ ExecuteState::pushInterpreterFrame(JSContext *cx)
|
|||||||
type_, evalInFrame_);
|
type_, evalInFrame_);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace js {
|
|
||||||
|
|
||||||
// Implementation of per-compartment performance measurement.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// All mutable state is stored in `Runtime::stopwatch`.
|
|
||||||
struct AutoStopwatch MOZ_FINAL
|
|
||||||
{
|
|
||||||
// If the stopwatch is active, constructing an instance of
|
|
||||||
// AutoStopwatch causes it to become the current owner of the
|
|
||||||
// stopwatch.
|
|
||||||
//
|
|
||||||
// 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)
|
|
||||||
return;
|
|
||||||
#elif defined(XP_WIN)
|
|
||||||
FILETIME creationTime; // Ignored
|
|
||||||
FILETIME exitTime; // Ignored
|
|
||||||
|
|
||||||
BOOL success = GetProcessTimes(GetCurrentProcess(),
|
|
||||||
&creationTime, &exitTime,
|
|
||||||
&kernelTimeStamp_, &userTimeStamp_);
|
|
||||||
if (!success)
|
|
||||||
return;
|
|
||||||
#endif // defined(XP_UNIX) || defined(XP_WIN)
|
|
||||||
|
|
||||||
// Push on top of previous owner.
|
|
||||||
parent_ = runtime->stopwatch.owner;
|
|
||||||
runtime->stopwatch.owner = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the stopwatch is active, destructing an instance of
|
|
||||||
// AutoStopwatch causes ownership to return to the previous owner.
|
|
||||||
inline ~AutoStopwatch()
|
|
||||||
{
|
|
||||||
JSRuntime *runtime = context_->runtime();
|
|
||||||
if (runtime->stopwatch.owner != this) {
|
|
||||||
// We are not the owner of the stopwatch, either because
|
|
||||||
// we never acquired it, because we have entered a nested
|
|
||||||
// event loop, or because some stopwatch lower on the
|
|
||||||
// stack encountered an error.
|
|
||||||
// If there is any ongoing measure, discard it.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this destructor cannot proceed to completion without error,
|
|
||||||
// prepare to cancel any ongoing measure.
|
|
||||||
runtime->stopwatch.owner = nullptr;
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
return;
|
|
||||||
|
|
||||||
totalUserTime =
|
|
||||||
(stop.ru_utime.tv_usec - timeStamp_.ru_utime.tv_usec)
|
|
||||||
+ (stop.ru_utime.tv_sec - timeStamp_.ru_utime.tv_sec) * 1000000;
|
|
||||||
totalSystemTime =
|
|
||||||
(stop.ru_stime.tv_usec - timeStamp_.ru_stime.tv_usec)
|
|
||||||
+ (stop.ru_stime.tv_sec - timeStamp_.ru_stime.tv_sec) * 1000000;
|
|
||||||
#elif defined(XP_WIN)
|
|
||||||
FILETIME creationTime; // Ignored
|
|
||||||
FILETIME exitTime; // Ignored
|
|
||||||
FILETIME kernelTime;
|
|
||||||
FILETIME userTime;
|
|
||||||
BOOL success = GetProcessTimes(GetCurrentProcess(),
|
|
||||||
&creationTime, &exitTime,
|
|
||||||
&kernelTime, &userTime);
|
|
||||||
if (!success)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Convert values to a data structure that supports arithmetics.
|
|
||||||
ULARGE_INTEGER userTimeInt, userTimeStampInt;
|
|
||||||
userTimeInt.LowPart = userTime.dwLowDateTime;
|
|
||||||
userTimeInt.HighPart = userTime.dwHighDateTime;
|
|
||||||
userTimeStampInt.LowPart = userTimeStamp_.dwLowDateTime;
|
|
||||||
userTimeStampInt.HighPart = userTimeStamp_.dwHighDateTime;
|
|
||||||
|
|
||||||
totalUserTime = (userTimeInt.QuadPart - userTimeStampInt.QuadPart) / 10; // 100 ns to 1 mus
|
|
||||||
|
|
||||||
ULARGE_INTEGER kernelTimeInt, kernelTimeStampInt;
|
|
||||||
kernelTimeInt.LowPart = kernelTime.dwLowDateTime;
|
|
||||||
kernelTimeInt.HighPart = kernelTime.dwHighDateTime;
|
|
||||||
kernelTimeStampInt.LowPart = kernelTimeStamp_.dwLowDateTime;
|
|
||||||
kernelTimeStampInt.HighPart = kernelTimeStamp_.dwHighDateTime;
|
|
||||||
|
|
||||||
totalSystemTime = (kernelTimeInt.QuadPart - kernelTimeStampInt.QuadPart) / 10; // 100 ns to 1 mus
|
|
||||||
#endif // defined(XP_UNIX) || defined (XP_WIN)
|
|
||||||
|
|
||||||
// Process durations.
|
|
||||||
//
|
|
||||||
// Note that durations are per-process, while our measures attempt
|
|
||||||
// to be per-thread. In other words, the data we extract may be
|
|
||||||
// badly skewed by activity on other threads. We can only hope that
|
|
||||||
// things will eventually average out.
|
|
||||||
|
|
||||||
JSCompartment *compartment = context_->compartment();
|
|
||||||
compartment->performance.visits++;
|
|
||||||
compartment->performance.totalUserTime += totalUserTime;
|
|
||||||
compartment->performance.totalSystemTime += totalSystemTime;
|
|
||||||
|
|
||||||
uint64_t ownUserTime = totalUserTime - descendentsUserTime_;
|
|
||||||
uint64_t ownSystemTime = totalSystemTime - descendentsSystemTime_;
|
|
||||||
compartment->performance.ownUserTime += ownUserTime;
|
|
||||||
compartment->performance.ownSystemTime += ownSystemTime;
|
|
||||||
|
|
||||||
if (parent_) {
|
|
||||||
// The time we just spent executing code in this compartment
|
|
||||||
// should be substracted to determine the parent's own time.
|
|
||||||
parent_->descendentsUserTime_ += totalUserTime;
|
|
||||||
parent_->descendentsSystemTime_ += totalSystemTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t totalDuration = totalUserTime + totalSystemTime;
|
|
||||||
|
|
||||||
// Store performance information in the compartment
|
|
||||||
|
|
||||||
uint64_t missedFrames = 16 * 1000; // Duration of one frame, i.e. 16ms in museconds
|
|
||||||
for (size_t i = 0; i < ArrayLength(compartment->performance.missedFrames); ++i) {
|
|
||||||
if (totalDuration < missedFrames)
|
|
||||||
break;
|
|
||||||
compartment->performance.missedFrames[i]++;
|
|
||||||
missedFrames *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
runtime->stopwatch.owner = parent_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// The AutoStopwatch for the caller compartment.
|
|
||||||
AutoStopwatch *parent_;
|
|
||||||
|
|
||||||
// The context with which this object was initialized.
|
|
||||||
JSContext *context_;
|
|
||||||
|
|
||||||
// Total time spent so far executing compartments that have been
|
|
||||||
// called by this compartment, in museconds. These values are
|
|
||||||
// updated upon destruction of callee AutoStopwatch instances.
|
|
||||||
uint64_t descendentsUserTime_;
|
|
||||||
uint64_t descendentsSystemTime_;
|
|
||||||
|
|
||||||
// Kernel and user time at the time of construction of this
|
|
||||||
// instance of AutoStopwatch. Unspecified if the stopwatch is not
|
|
||||||
// active.
|
|
||||||
#if defined(XP_UNIX)
|
|
||||||
struct rusage timeStamp_;
|
|
||||||
#elif defined(XP_WIN)
|
|
||||||
FILETIME kernelTimeStamp_;
|
|
||||||
FILETIME userTimeStamp_;
|
|
||||||
#endif // defined(XP_UNIX) || defined(XP_WIN)
|
|
||||||
|
|
||||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
js::RunScript(JSContext *cx, RunState &state)
|
js::RunScript(JSContext *cx, RunState &state)
|
||||||
{
|
{
|
||||||
JS_CHECK_RECURSION(cx, return false);
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
|
|
||||||
#if defined(NIGHTLY_BUILD)
|
|
||||||
js::AutoStopwatch stopwatch(cx);
|
|
||||||
#endif // defined(NIGHTLY_BUILD)
|
|
||||||
|
|
||||||
SPSEntryMarker marker(cx->runtime(), state.script());
|
SPSEntryMarker marker(cx->runtime(), state.script());
|
||||||
|
|
||||||
state.script()->ensureNonLazyCanonicalFunction(cx);
|
state.script()->ensureNonLazyCanonicalFunction(cx);
|
||||||
|
@ -848,21 +848,3 @@ JS::UpdateJSRuntimeProfilerSampleBufferGen(JSRuntime *runtime, uint32_t generati
|
|||||||
runtime->setProfilerSampleBufferGen(generation);
|
runtime->setProfilerSampleBufferGen(generation);
|
||||||
runtime->updateProfilerSampleBufferLapCount(lapCount);
|
runtime->updateProfilerSampleBufferLapCount(lapCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
js::ResetStopwatches(JSRuntime *rt)
|
|
||||||
{
|
|
||||||
rt->stopwatch.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
js::SetStopwatchActive(JSRuntime *rt, bool isActive)
|
|
||||||
{
|
|
||||||
rt->stopwatch.isActive = isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::IsStopwatchActive(JSRuntime *rt)
|
|
||||||
{
|
|
||||||
return rt->stopwatch.isActive;
|
|
||||||
}
|
|
||||||
|
@ -566,7 +566,6 @@ class PerThreadData : public PerThreadDataFriendFields
|
|||||||
|
|
||||||
class AutoLockForExclusiveAccess;
|
class AutoLockForExclusiveAccess;
|
||||||
|
|
||||||
struct AutoStopwatch;
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
struct JSRuntime : public JS::shadow::Runtime,
|
struct JSRuntime : public JS::shadow::Runtime,
|
||||||
@ -1421,53 +1420,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||||||
|
|
||||||
/* Last time at which an animation was played for this runtime. */
|
/* Last time at which an animation was played for this runtime. */
|
||||||
int64_t lastAnimationTime;
|
int64_t lastAnimationTime;
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* ------------------------------------------
|
|
||||||
Performance measurements
|
|
||||||
------------------------------------------ */
|
|
||||||
struct Stopwatch {
|
|
||||||
/**
|
|
||||||
* The current owner of the stopwatch.
|
|
||||||
*
|
|
||||||
* This is `nullptr` if we have not started executing JS code
|
|
||||||
* in this tick yet, or if we are not using stopwatch
|
|
||||||
* monitoring. If monitoring is activated, whenever we
|
|
||||||
* instantiate an `AutoStopwatch`, it becomes the owner, and
|
|
||||||
* whenever we destruct it, it returns ownership to the
|
|
||||||
* previous owner.
|
|
||||||
*
|
|
||||||
* Note that `owner` is reset to `nullptr` if we start
|
|
||||||
* processing a nested event. By design, this has the
|
|
||||||
* side-effect of discarding any ongoing measurement that
|
|
||||||
* would otherwise be completely skewed by the nested event
|
|
||||||
* loop.
|
|
||||||
*/
|
|
||||||
js::AutoStopwatch *owner;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* `true` if stopwatch monitoring is active, `false` otherwise.
|
|
||||||
*/
|
|
||||||
bool isActive;
|
|
||||||
|
|
||||||
Stopwatch()
|
|
||||||
: owner(nullptr)
|
|
||||||
, isActive(false)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the stopwatch.
|
|
||||||
*
|
|
||||||
* This method is meant to be called whewnever we start processing
|
|
||||||
* an event, to ensure that stop any ongoing measurement that would
|
|
||||||
* otherwise provide irrelevant results.
|
|
||||||
*/
|
|
||||||
void reset() {
|
|
||||||
owner = nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Stopwatch stopwatch;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
@ -122,7 +122,7 @@ interface ScheduledGCCallback : nsISupports
|
|||||||
/**
|
/**
|
||||||
* interface of Components.utils
|
* interface of Components.utils
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(9b153002-3bc6-4d83-b825-64d21b13a098)]
|
[scriptable, uuid(2617a800-63c1-11e4-9803-0800200c9a66)]
|
||||||
interface nsIXPCComponents_Utils : nsISupports
|
interface nsIXPCComponents_Utils : nsISupports
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -679,14 +679,6 @@ interface nsIXPCComponents_Utils : nsISupports
|
|||||||
* startup, measured with a monotonic clock.
|
* startup, measured with a monotonic clock.
|
||||||
*/
|
*/
|
||||||
double now();
|
double now();
|
||||||
|
|
||||||
/*
|
|
||||||
* Whether we are currently monitoring CPU use on this thread.
|
|
||||||
*
|
|
||||||
* Note that CPU monitoring is rather expensive, so it generally
|
|
||||||
* not be active at all times.
|
|
||||||
*/
|
|
||||||
attribute boolean stopwatchMonitoring;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3529,22 +3529,6 @@ nsXPCComponents_Utils::Now(double *aRetval)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsXPCComponents_Utils::SetStopwatchMonitoring(bool aValue)
|
|
||||||
{
|
|
||||||
JSRuntime* rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
|
||||||
SetStopwatchActive(rt, aValue);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsXPCComponents_Utils::GetStopwatchMonitoring(bool* aResult)
|
|
||||||
{
|
|
||||||
JSRuntime* rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
|
||||||
*aResult = IsStopwatchActive(rt);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
@ -348,6 +348,13 @@ xpc::TraceXPCGlobal(JSTracer *trc, JSObject *obj)
|
|||||||
|
|
||||||
namespace xpc {
|
namespace xpc {
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
GetCompartmentCPOWMicroseconds(JSCompartment *compartment)
|
||||||
|
{
|
||||||
|
xpc::CompartmentPrivate *compartmentPrivate = xpc::CompartmentPrivate::Get(compartment);
|
||||||
|
return compartmentPrivate ? PR_IntervalToMicroseconds(compartmentPrivate->CPOWTime) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
|
CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
|
||||||
JS::CompartmentOptions& aOptions)
|
JS::CompartmentOptions& aOptions)
|
||||||
|
@ -626,7 +626,6 @@ public:
|
|||||||
void OnProcessNextEvent() {
|
void OnProcessNextEvent() {
|
||||||
mSlowScriptCheckpoint = mozilla::TimeStamp::NowLoRes();
|
mSlowScriptCheckpoint = mozilla::TimeStamp::NowLoRes();
|
||||||
mSlowScriptSecondHalf = false;
|
mSlowScriptSecondHalf = false;
|
||||||
js::ResetStopwatches(Get()->Runtime());
|
|
||||||
}
|
}
|
||||||
void OnAfterProcessNextEvent() {
|
void OnAfterProcessNextEvent() {
|
||||||
mSlowScriptCheckpoint = mozilla::TimeStamp();
|
mSlowScriptCheckpoint = mozilla::TimeStamp();
|
||||||
@ -3624,6 +3623,7 @@ public:
|
|||||||
, skipWriteToGlobalPrototype(false)
|
, skipWriteToGlobalPrototype(false)
|
||||||
, universalXPConnectEnabled(false)
|
, universalXPConnectEnabled(false)
|
||||||
, forcePermissiveCOWs(false)
|
, forcePermissiveCOWs(false)
|
||||||
|
, CPOWTime(0)
|
||||||
, skipCOWCallableChecks(false)
|
, skipCOWCallableChecks(false)
|
||||||
, scriptability(c)
|
, scriptability(c)
|
||||||
, scope(nullptr)
|
, scope(nullptr)
|
||||||
@ -3677,6 +3677,9 @@ public:
|
|||||||
// Using it in production is inherently unsafe.
|
// Using it in production is inherently unsafe.
|
||||||
bool forcePermissiveCOWs;
|
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
|
// Disables the XPConnect security checks that deny access to callables and
|
||||||
// accessor descriptors on COWs. Do not use this unless you are bholley.
|
// accessor descriptors on COWs. Do not use this unless you are bholley.
|
||||||
bool skipCOWCallableChecks;
|
bool skipCOWCallableChecks;
|
||||||
|
@ -10,158 +10,66 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|||||||
|
|
||||||
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
|
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
|
||||||
|
|
||||||
/**
|
|
||||||
* The various measures we extract from a nsICompartment.
|
|
||||||
*/
|
|
||||||
const MEASURES = [
|
|
||||||
{key: "totalUserTime", label: "Total user (µs)"},
|
|
||||||
{key: "totalSystemTime", label: "Total system (µs)"},
|
|
||||||
{key: "ownUserTime", label: "Own user (µs)"},
|
|
||||||
{key: "ownSystemTime", label: "Own system (µs)"},
|
|
||||||
{key: "cpowTime", label: "CPOW (µs)"},
|
|
||||||
{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);
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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() {
|
function go() {
|
||||||
update();
|
let compartmentInfo = Cc["@mozilla.org/compartment-info;1"]
|
||||||
window.setInterval(update, 5000);
|
.getService(Ci.nsICompartmentInfo);
|
||||||
window.addEventListener("beforeunload", stop);
|
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]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.compartmentName;
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
el.addEventListener("click", function() { div.style.display = (div.style.display != "block" ? "block" : "none"); });
|
||||||
|
el.appendChild(div);
|
||||||
|
dataDiv.appendChild(el);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,19 +29,15 @@
|
|||||||
color: gray;
|
color: gray;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
tr.addons {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
tr.builtins {
|
|
||||||
background-color: rgb(1, 1, .5);
|
|
||||||
}
|
|
||||||
tr.pages {
|
|
||||||
background-color: rgb(.5, 1, 1);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body onload="go()">
|
<body onload="go()">
|
||||||
<table id="data">
|
<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>
|
</table>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
FAIL_ON_WARNINGS = True
|
|
||||||
|
|
||||||
JAR_MANIFESTS += ['jar.mn']
|
JAR_MANIFESTS += ['jar.mn']
|
||||||
|
|
||||||
XPIDL_MODULE = 'compartments'
|
XPIDL_MODULE = 'compartments'
|
||||||
@ -22,6 +20,4 @@ EXPORTS += [
|
|||||||
'nsCompartmentInfo.h'
|
'nsCompartmentInfo.h'
|
||||||
]
|
]
|
||||||
|
|
||||||
BROWSER_CHROME_MANIFESTS += ['tests/mochi/browser.ini']
|
|
||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
FINAL_LIBRARY = 'xul'
|
||||||
|
@ -12,16 +12,12 @@
|
|||||||
#include "nsIMutableArray.h"
|
#include "nsIMutableArray.h"
|
||||||
#include "nsJSUtils.h"
|
#include "nsJSUtils.h"
|
||||||
#include "xpcpublic.h"
|
#include "xpcpublic.h"
|
||||||
#include "jspubtd.h"
|
|
||||||
|
|
||||||
class nsCompartment : public nsICompartment {
|
class nsCompartment : public nsICompartment {
|
||||||
public:
|
public:
|
||||||
nsCompartment(nsAString& aCompartmentName, nsAString& aAddonId, bool aIsSystem, js::PerformanceData aPerformanceData)
|
nsCompartment(nsAString& aCompartmentName, nsAString& aAddonId,
|
||||||
: mCompartmentName(aCompartmentName)
|
uint64_t aTime, uint64_t aCPOWTime)
|
||||||
, mAddonId(aAddonId)
|
: mCompartmentName(aCompartmentName), mAddonId(aAddonId), mTime(aTime), mCPOWTime(aCPOWTime) {}
|
||||||
, mIsSystem(aIsSystem)
|
|
||||||
, mPerformanceData(aPerformanceData)
|
|
||||||
{}
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
@ -31,68 +27,28 @@ public:
|
|||||||
return NS_OK;
|
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; */
|
/* readonly attribute wstring addon id; */
|
||||||
NS_IMETHOD GetAddonId(nsAString& aAddonId) MOZ_OVERRIDE {
|
NS_IMETHOD GetAddonId(nsAString& aAddonId) MOZ_OVERRIDE {
|
||||||
aAddonId.Assign(mAddonId);
|
aAddonId.Assign(mAddonId);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* readonly attribute unsigned long long totalUserTime; */
|
/* readonly attribute unsigned long CPOW time; */
|
||||||
NS_IMETHOD GetTotalUserTime(uint64_t *aTotalUserTime) {
|
NS_IMETHOD GetCPOWTime(uint64_t* aCPOWTime) MOZ_OVERRIDE {
|
||||||
*aTotalUserTime = mPerformanceData.totalUserTime;
|
*aCPOWTime = mCPOWTime;
|
||||||
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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsString mCompartmentName;
|
nsString mCompartmentName;
|
||||||
nsString mAddonId;
|
nsString mAddonId;
|
||||||
bool mIsSystem;
|
uint64_t mTime;
|
||||||
js::PerformanceData mPerformanceData;
|
uint64_t mCPOWTime;
|
||||||
|
|
||||||
virtual ~nsCompartment() {}
|
virtual ~nsCompartment() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,18 +77,17 @@ nsCompartmentInfo::GetCompartments(nsIArray** aCompartments)
|
|||||||
|
|
||||||
size_t num = stats.length();
|
size_t num = stats.length();
|
||||||
for (size_t pos = 0; pos < num; pos++) {
|
for (size_t pos = 0; pos < num; pos++) {
|
||||||
CompartmentTimeStats *c = &stats[pos];
|
|
||||||
nsString addonId;
|
nsString addonId;
|
||||||
if (c->addonId) {
|
if (stats[pos].addonId) {
|
||||||
AssignJSFlatString(addonId, (JSFlatString*)c->addonId);
|
AssignJSFlatString(addonId, (JSFlatString*)stats[pos].addonId);
|
||||||
} else {
|
} else {
|
||||||
addonId.AssignLiteral("<non-addon>");
|
addonId.AssignLiteral("<non-addon>");
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCString compartmentName(c->compartmentName);
|
uint32_t cpowTime = xpc::GetCompartmentCPOWMicroseconds(stats[pos].compartment);
|
||||||
|
nsCString compartmentName(stats[pos].compartmentName);
|
||||||
NS_ConvertUTF8toUTF16 name(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);
|
compartments.forget(aCompartments);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -7,52 +7,16 @@
|
|||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
#include "nsIArray.idl"
|
#include "nsIArray.idl"
|
||||||
|
|
||||||
[scriptable, uuid(3a23d383-052e-4199-8914-74c037fe359e)]
|
[scriptable, uuid(13dd4c09-ff11-4943-8dc2-d96eb69c963b)]
|
||||||
interface nsICompartment : nsISupports {
|
interface nsICompartment : nsISupports {
|
||||||
/* name of compartment */
|
/* name of compartment */
|
||||||
readonly attribute AString compartmentName;
|
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 */
|
/* the id of the addon associated with this compartment, or null */
|
||||||
readonly attribute AString addonId;
|
readonly attribute AString addonId;
|
||||||
|
/* time spent processing CPOWs in microseconds */
|
||||||
/*
|
|
||||||
Total amount of time spent executing code in this compartment, in
|
|
||||||
microseconds.
|
|
||||||
|
|
||||||
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;
|
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);
|
|
||||||
/* Number of values that may be consulted in `getMissedFrames`.*/
|
|
||||||
const unsigned long MISSED_FRAMES_RANGE = 8;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(5795113a-39a1-4087-ba09-98b7d07d025a)]
|
[scriptable, builtinclass, uuid(5795113a-39a1-4087-ba09-98b7d07d025a)]
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
[DEFAULT]
|
|
||||||
support-files =
|
|
||||||
browser_compartments.html
|
|
||||||
content.js
|
|
||||||
|
|
||||||
[browser_compartments.js]
|
|
@ -1,23 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>
|
|
||||||
browser_compartments.html
|
|
||||||
</title>
|
|
||||||
<script type="text/javascript">
|
|
||||||
// Use some CPU
|
|
||||||
// Compute an arbitrary value, print it out to make sure that the JS
|
|
||||||
// engine doesn't discard all our computation.
|
|
||||||
var date = Date.now();
|
|
||||||
var array = [];
|
|
||||||
var i = 0;
|
|
||||||
while (Date.now() - date <= 200) {
|
|
||||||
array[i%2] = i++;
|
|
||||||
}
|
|
||||||
console.log("Arbitrary value", array);
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
browser_compartments.html
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,123 +0,0 @@
|
|||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
|
|
||||||
const ROOT = getRootDirectory(gTestPath);
|
|
||||||
const FRAME_SCRIPTS = [
|
|
||||||
ROOT + "content.js",
|
|
||||||
];
|
|
||||||
const URL = "chrome://mochitests/content/browser/toolkit/components/aboutcompartments/tests/mochi/browser_compartments.html";
|
|
||||||
|
|
||||||
let mm = Cc["@mozilla.org/globalmessagemanager;1"]
|
|
||||||
.getService(Ci.nsIMessageListenerManager);
|
|
||||||
|
|
||||||
for (let script of FRAME_SCRIPTS) {
|
|
||||||
mm.loadFrameScript(script, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
registerCleanupFunction(() => {
|
|
||||||
for (let script of FRAME_SCRIPTS) {
|
|
||||||
mm.removeDelayedFrameScript(script, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function promiseContentResponse(browser, name, message) {
|
|
||||||
let mm = browser.messageManager;
|
|
||||||
let promise = new Promise(resolve => {
|
|
||||||
function removeListener() {
|
|
||||||
mm.removeMessageListener(name, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
function listener(msg) {
|
|
||||||
removeListener();
|
|
||||||
resolve(msg.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
mm.addMessageListener(name, listener);
|
|
||||||
registerCleanupFunction(removeListener);
|
|
||||||
});
|
|
||||||
mm.sendAsyncMessage(name, message);
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStatistics() {
|
|
||||||
let compartmentInfo = Cc["@mozilla.org/compartment-info;1"]
|
|
||||||
.getService(Ci.nsICompartmentInfo);
|
|
||||||
let data = compartmentInfo.getCompartments();
|
|
||||||
let result = [];
|
|
||||||
for (let i = 0; i < data.length; ++i) {
|
|
||||||
result.push(data.queryElementAt(i, Ci.nsICompartment));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function* promiseTabLoadEvent(tab, url)
|
|
||||||
{
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
function handleLoadEvent(event) {
|
|
||||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
|
||||||
event.target.location.href == "about:blank" ||
|
|
||||||
(url && event.target.location.href != url)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tab.linkedBrowser.removeEventListener("load", handleLoadEvent, true);
|
|
||||||
resolve(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
tab.linkedBrowser.addEventListener("load", handleLoadEvent, true, true);
|
|
||||||
if (url)
|
|
||||||
tab.linkedBrowser.loadURI(url);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(function* init() {
|
|
||||||
let monitoring = Cu.stopwatchMonitoring;
|
|
||||||
Cu.stopwatchMonitoring = true;
|
|
||||||
registerCleanupFunction(() => {
|
|
||||||
Cu.stopwatchMonitoring = monitoring;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(function* test() {
|
|
||||||
info("Extracting initial state");
|
|
||||||
let stats0 = getStatistics();
|
|
||||||
Assert.notEqual(stats0.length, 0, "There is more than one compartment");
|
|
||||||
Assert.ok(!stats0.find(stat => stat.compartmentName.indexOf(URL) != -1),
|
|
||||||
"The url doesn't appear yet");
|
|
||||||
stats0.forEach(stat => {
|
|
||||||
Assert.ok(stat.totalUserTime >= stat.ownUserTime, "Total >= own user time: " + stat.compartmentName);
|
|
||||||
Assert.ok(stat.totalSystemTime >= stat.ownSystemTime, "Total >= own system time: " + stat.compartmentName);
|
|
||||||
});
|
|
||||||
|
|
||||||
let newTab = gBrowser.addTab();
|
|
||||||
let browser = newTab.linkedBrowser;
|
|
||||||
// Setup monitoring in the tab
|
|
||||||
info("Setting up monitoring in the tab");
|
|
||||||
let childMonitoring = yield promiseContentResponse(browser, "compartments-test:setMonitoring", true);
|
|
||||||
|
|
||||||
info("Waiting for load to be complete");
|
|
||||||
yield promiseTabLoadEvent(newTab, URL);
|
|
||||||
|
|
||||||
if (!gMultiProcessBrowser) {
|
|
||||||
// In non-e10s mode, the stats are counted in the single process
|
|
||||||
let stats1 = getStatistics();
|
|
||||||
let pageStats = stats1.find(stat => stat.compartmentName.indexOf(URL) != -1);
|
|
||||||
Assert.notEqual(pageStats, null, "The new page appears in the single-process statistics");
|
|
||||||
Assert.notEqual(pageStats.totalUserTime, 0, "Total single-process user time is > 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regardless of e10s, the stats should be accessible in the content process (or pseudo-process)
|
|
||||||
let stats2 = yield promiseContentResponse(browser, "compartments-test:getCompartments", null);
|
|
||||||
let pageStats = stats2.find(stat => stat.compartmentName.indexOf(URL) != -1);
|
|
||||||
Assert.notEqual(pageStats, null, "The new page appears in the content statistics");
|
|
||||||
Assert.notEqual(pageStats.totalUserTime, 0, "Total content user time is > 0");
|
|
||||||
Assert.ok(pageStats.totalUserTime >= 1000, "Total content user time is at least 1ms");
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
yield promiseContentResponse(browser, "compartments-test:setMonitoring", childMonitoring);
|
|
||||||
gBrowser.removeTab(newTab);
|
|
||||||
});
|
|
@ -1,36 +0,0 @@
|
|||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
|
|
||||||
|
|
||||||
addMessageListener("compartments-test:setMonitoring", msg => {
|
|
||||||
let stopwatchMonitoring = Cu.stopwatchMonitoring;
|
|
||||||
Cu.stopwatchMonitoring = msg.data;
|
|
||||||
sendAsyncMessage("compartments-test:setMonitoring", stopwatchMonitoring);
|
|
||||||
});
|
|
||||||
|
|
||||||
addMessageListener("compartments-test:getCompartments", () => {
|
|
||||||
let compartmentInfo = Cc["@mozilla.org/compartment-info;1"]
|
|
||||||
.getService(Ci.nsICompartmentInfo);
|
|
||||||
let data = compartmentInfo.getCompartments();
|
|
||||||
let result = [];
|
|
||||||
for (let i = 0; i < data.length; ++i) {
|
|
||||||
let xpcom = data.queryElementAt(i, Ci.nsICompartment);
|
|
||||||
let object = {};
|
|
||||||
for (let k of Object.keys(xpcom)) {
|
|
||||||
let value = xpcom[k];
|
|
||||||
if (typeof value != "function") {
|
|
||||||
object[k] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
object.frames = [];
|
|
||||||
for (let i = 0; i < Ci.nsICompartment.MISSED_FRAMES_RANGE; ++i) {
|
|
||||||
object.frames[i] = xpcom.getMissedFrames(i);
|
|
||||||
}
|
|
||||||
result.push(object);
|
|
||||||
}
|
|
||||||
sendAsyncMessage("compartments-test:getCompartments", result);
|
|
||||||
});
|
|
@ -26,13 +26,11 @@ let AddonWatcher = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._callback) {
|
if (this._callback) {
|
||||||
// Already initialized
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._interval = Preferences.get("browser.addon-watch.interval", 15000);
|
this._interval = Preferences.get("browser.addon-watch.interval", 15000);
|
||||||
if (this._interval == -1) {
|
if (this._interval == -1) {
|
||||||
// Deactivated by preferences
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,9 +41,6 @@ let AddonWatcher = {
|
|||||||
// probably some malformed JSON, ignore and carry on
|
// probably some malformed JSON, ignore and carry on
|
||||||
this._ignoreList = new Set();
|
this._ignoreList = new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start monitoring
|
|
||||||
Cu.stopwatchMonitoring = true;
|
|
||||||
this._timer.initWithCallback(this._checkAddons.bind(this), this._interval, Ci.nsITimer.TYPE_REPEATING_SLACK);
|
this._timer.initWithCallback(this._checkAddons.bind(this), this._interval, Ci.nsITimer.TYPE_REPEATING_SLACK);
|
||||||
},
|
},
|
||||||
uninit: function() {
|
uninit: function() {
|
||||||
@ -53,7 +48,6 @@ let AddonWatcher = {
|
|||||||
this._timer.cancel();
|
this._timer.cancel();
|
||||||
this._timer = null;
|
this._timer = null;
|
||||||
}
|
}
|
||||||
Cu.stopwatchMonitoring = false;
|
|
||||||
},
|
},
|
||||||
_checkAddons: function() {
|
_checkAddons: function() {
|
||||||
let compartmentInfo = Cc["@mozilla.org/compartment-info;1"]
|
let compartmentInfo = Cc["@mozilla.org/compartment-info;1"]
|
||||||
|
Loading…
Reference in New Issue
Block a user