Backed out changeset 33afbc6c4997 (bug 1208747)

This commit is contained in:
Carsten "Tomcat" Book 2015-10-21 11:39:22 +02:00
Родитель 1a65e75c7e
Коммит a55a2ef59a
7 изменённых файлов: 386 добавлений и 1254 удалений

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

@ -1,8 +1,8 @@
#include "vm/Stopwatch.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/IntegerTypeTraits.h"
#include "mozilla/unused.h"
#include <mozilla/ArrayUtils.h>
#include <mozilla/IntegerTypeTraits.h>
#include <mozilla/unused.h>
namespace js {
@ -338,7 +338,6 @@ AutoStopwatch::addToGroups(uint64_t cyclesDelta, uint64_t CPOWTimeDelta)
if (!addToGroup(runtime, cyclesDelta, CPOWTimeDelta, *group))
return false;
}
return true;
}
bool
@ -352,7 +351,6 @@ AutoStopwatch::addToGroup(JSRuntime* runtime, uint64_t cyclesDelta, uint64_t CPO
group->addRecentTicks(iteration_, 1);
group->addRecentCycles(iteration_, cyclesDelta);
group->addRecentCPOW(iteration_, CPOWTimeDelta);
return true;
}
uint64_t

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

@ -3265,6 +3265,47 @@ static const JSWrapObjectCallbacks WrapObjectCallbacks = {
xpc::WrapperFactory::PrepareForWrapping
};
/**
* Group JSCompartments into PerformanceGroups.
*
* - All JSCompartments from the same add-on belong to the same
* PerformanceGroup.
* - All JSCompartments from the same same webpage (including
* frames) belong to the same PerformanceGroup.
* - All other JSCompartments (normally, system add-ons)
* belong to to a big uncategorized PerformanceGroup.
*/
static void*
GetCurrentPerfGroupCallback(JSContext* cx) {
RootedObject global(cx, CurrentGlobalOrNull(cx));
if (!global) {
// This can happen for the atom compartments, which is system
// code.
return nullptr;
}
JSAddonId* addonId = AddonIdOfObject(global);
if (addonId) {
// If this is an add-on, use the id as key.
return addonId;
}
// If the compartment belongs to a webpage, use the address of the
// topmost scriptable window, hence regrouping all frames of a
// window.
RefPtr<nsGlobalWindow> win = WindowOrNull(global);
if (win) {
nsCOMPtr<nsIDOMWindow> top;
nsresult rv = win->GetScriptableTop(getter_AddRefs(top));
NS_ENSURE_SUCCESS(rv, nullptr);
return top.get();
}
// Otherwise, this is platform code, use `nullptr` as key.
return nullptr;
}
XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
: CycleCollectedJSRuntime(nullptr, JS::DefaultHeapMaxBytes, JS::DefaultNurseryBytes),
mJSContextStack(new XPCJSContextStack(this)),
@ -3444,6 +3485,8 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
// Watch for the JS boolean options.
ReloadPrefsCallback(nullptr, this);
Preferences::RegisterCallback(ReloadPrefsCallback, JS_OPTIONS_DOT_STR, this);
JS_SetCurrentPerfGroupCallback(runtime, ::GetCurrentPerfGroupCallback);
}
// static

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

@ -67,7 +67,7 @@ using namespace mozilla;
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAppStartup, Init)
#if defined(MOZ_HAS_PERFSTATS)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPerformanceStatsService, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPerformanceStatsService)
#endif // defined (MOZ_HAS_PERFSTATS)
#if defined(MOZ_HAS_TERMINATOR)

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

@ -22,7 +22,7 @@
* All values are monotonic and are updated only when
* `nsIPerformanceStatsService.isStopwatchActive` is `true`.
*/
[scriptable, uuid(f171c901-1888-4087-a002-c2751e510f92)]
[scriptable, uuid(89440555-dd81-4a22-8747-049bcf0ab586)]
interface nsIPerformanceStats: nsISupports {
/**
* An identifier unique to the component.
@ -33,7 +33,21 @@ interface nsIPerformanceStats: nsISupports {
readonly attribute AString groupId;
/**
* A somewhat human-readable name for the component.
* 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:
* - for the process itself, "<process>";
* - for platform code, "<platform>";
* - for an add-on, the identifier of the addon (e.g. "myaddon@foo.bar");
* - for a webpage, the url of the page.
*/
readonly attribute AString name;
@ -49,6 +63,12 @@ interface nsIPerformanceStats: nsISupports {
*/
readonly attribute uint64_t windowId;
/**
* If the component is code executed in a window, the title of the topmost
* window (i.e. the tab), otherwise an empty string.
*/
readonly attribute AString title;
/**
* Total amount of time spent executing code in this group, in
* microseconds.
@ -89,7 +109,7 @@ interface nsIPerformanceStats: nsISupports {
/**
* A snapshot of the performance data of the process.
*/
[scriptable, uuid(0ac38e2a-2613-4e3f-9f21-95f085c177de)]
[scriptable, uuid(2e0c50e2-3aff-4cc8-88a6-c0dc200da8fc)]
interface nsIPerformanceSnapshot: nsISupports {
/**
* Data on all individual components.
@ -107,7 +127,7 @@ interface nsIPerformanceSnapshot: nsISupports {
nsIPerformanceStats getProcessData();
};
[scriptable, builtinclass, uuid(aad18f7c-9ff7-4e22-8cd1-60ab0b57c698)]
[scriptable, builtinclass, uuid(60973d54-13e2-455c-a3c6-84dea5dfc8b9)]
interface nsIPerformanceStatsService : nsISupports {
/**
* `true` if we should monitor CPOW, `false` otherwise.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -6,487 +6,27 @@
#ifndef nsPerformanceStats_h
#define nsPerformanceStats_h
#include "jsapi.h"
#include "nsHashKeys.h"
#include "nsTHashtable.h"
#include "nsIObserver.h"
#include "nsPIDOMWindow.h"
#include "nsIPerformanceStats.h"
class nsPerformanceGroup;
typedef mozilla::Vector<RefPtr<js::PerformanceGroup>> JSGroupVector;
typedef mozilla::Vector<RefPtr<nsPerformanceGroup>> GroupVector;
/**
* An implementation of the nsIPerformanceStatsService.
*
* Note that this implementation is not thread-safe.
*/
class nsPerformanceStatsService : public nsIPerformanceStatsService,
public nsIObserver
class nsPerformanceStatsService : public nsIPerformanceStatsService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPERFORMANCESTATSSERVICE
NS_DECL_NSIOBSERVER
nsPerformanceStatsService();
nsresult Init();
private:
nsresult InitInternal();
void Dispose();
nsresult UpdateTelemetry();
virtual ~nsPerformanceStatsService();
protected:
friend nsPerformanceGroup;
/**
* A unique identifier for the process.
*
* Process HANDLE under Windows, pid under Unix.
*/
const uint64_t mProcessId;
/**
* The JS Runtime for the main thread.
*/
JSRuntime* const mRuntime;
/**
* Generate unique identifiers.
*/
uint64_t GetNextId();
uint64_t mUIdCounter;
/**
* Extract a snapshot of performance statistics from a performance group.
*/
static nsIPerformanceStats* GetStatsForGroup(const js::PerformanceGroup* group);
static nsIPerformanceStats* GetStatsForGroup(const nsPerformanceGroup* group);
/**
* Get the performance groups associated to a given JS compartment.
*
* A compartment is typically associated to the following groups:
* - the top group, shared by the entire process;
* - the window group, if the code is executed in a window, shared
* by all compartments for that window (typically, all frames);
* - the add-on group, if the code is executed as an add-on, shared
* by all compartments for that add-on (typically, all modules);
* - the compartment's own group.
*
* Pre-condition: the VM must have entered the JS compartment.
*
* The caller is expected to cache the results of this method, as
* calling it more than once may not return the same instances of
* performance groups.
*/
bool GetPerformanceGroups(JSContext* cx, JSGroupVector&);
static bool GetPerformanceGroupsCallback(JSContext* cx, JSGroupVector&, void* closure);
/**********************************************************
*
* Sets of all performance groups, indexed by several keys.
*
* These sets do not keep the performance groups alive. Rather, a
* performance group is inserted in the relevant sets upon
* construction and removed from the sets upon destruction or when
* we Dispose() of the service.
*
* A `nsPerformanceGroup` is typically kept alive (as a
* `js::PerformanceGroup`) by the JSCompartment to which it is
* associated. It may also temporarily be kept alive by the JS
* stack, in particular in case of nested event loops.
*/
/**
* Set of performance groups associated to add-ons, indexed
* by add-on id. Each item is shared by all the compartments
* that belong to the add-on.
*/
struct AddonIdToGroup: public nsStringHashKey {
explicit AddonIdToGroup(const nsAString* key)
: nsStringHashKey(key)
, mGroup(nullptr)
{ }
nsPerformanceGroup* mGroup;
};
nsTHashtable<AddonIdToGroup> mAddonIdToGroup;
/**
* Set of performance groups associated to windows, indexed by outer
* window id. Each item is shared by all the compartments that
* belong to the window.
*/
struct WindowIdToGroup: public nsUint64HashKey {
explicit WindowIdToGroup(const uint64_t* key)
: nsUint64HashKey(key)
, mGroup(nullptr)
{}
nsPerformanceGroup* mGroup;
};
nsTHashtable<WindowIdToGroup> mWindowIdToGroup;
/**
* Set of all performance groups.
*/
struct Groups: public nsPtrHashKey<nsPerformanceGroup> {
explicit Groups(const nsPerformanceGroup* key)
: nsPtrHashKey<nsPerformanceGroup>(key)
{}
};
nsTHashtable<Groups> mGroups;
/**
* The performance group representing the runtime itself. All
* compartments are associated to this group.
*/
RefPtr<nsPerformanceGroup> mTopGroup;
/**********************************************************
*
* Measuring and recording the CPU use of the system.
*
*/
/**
* Get the OS-reported time spent in userland/systemland, in
* microseconds. On most platforms, this data is per-thread,
* but on some platforms we need to fall back to per-process.
*
* Data is not guaranteed to be monotonic.
*/
nsresult GetResources(uint64_t* userTime, uint64_t* systemTime) const;
/**
* Amount of user/system CPU time used by the thread (or process,
* for platforms that don't support per-thread measure) since start.
* Updated by `StopwatchStart` at most once per event.
*
* Unit: microseconds.
*/
uint64_t mUserTimeStart;
uint64_t mSystemTimeStart;
/**********************************************************
*
* Callbacks triggered by the JS VM when execution of JavaScript
* code starts/completes.
*
* As measures of user CPU time/system CPU time have low resolution
* (and are somewhat slow), we measure both only during the calls to
* `StopwatchStart`/`StopwatchCommit` and we make the assumption
* that each group's user/system CPU time is proportional to the
* number of clock cycles spent executing code in the group between
* `StopwatchStart`/`StopwatchCommit`.
*
* The results may be skewed by the thread being rescheduled to a
* different CPU during the measure, but we expect that on average,
* the skew will have limited effects, and will generally tend to
* make already-slow executions appear slower.
*/
/**
* Execution of JavaScript code has started. This may happen several
* times in succession if the JavaScript code contains nested event
* loops, in which case only the innermost call will receive
* `StopwatchCommitCallback`.
*
* @param iteration The number of times we have started executing
* JavaScript code.
*/
static bool StopwatchStartCallback(uint64_t iteration, void* closure);
bool StopwatchStart(uint64_t iteration);
/**
* Execution of JavaScript code has reached completion (including
* enqueued microtasks). In cse of tested event loops, any ongoing
* measurement on outer loops is silently cancelled without any call
* to this method.
*
* @param iteration The number of times we have started executing
* JavaScript code.
* @param recentGroups The groups that have seen activity during this
* event.
*/
static bool StopwatchCommitCallback(uint64_t iteration, JSGroupVector& recentGroups, void* closure);
bool StopwatchCommit(uint64_t iteration, JSGroupVector& recentGroups);
/**
* The number of times we have started executing JavaScript code.
*/
uint64_t mIteration;
/**
* Commit performance measures of a single group.
*
* Data is transfered from `group->recent*` to `group->data`.
*
*
* @param iteration The current iteration.
* @param userTime The total user CPU time for this thread (or
* process, if per-thread data is not available) between the
* calls to `StopwatchStart` and `StopwatchCommit`.
* @param systemTime The total system CPU time for this thread (or
* process, if per-thread data is not available) between the
* calls to `StopwatchStart` and `StopwatchCommit`.
* @param cycles The total number of cycles for this thread
* between the calls to `StopwatchStart` and `StopwatchCommit`.
* @param group The group containing the data to commit.
*/
void CommitGroup(uint64_t iteration,
uint64_t userTime, uint64_t systemTime, uint64_t cycles,
nsPerformanceGroup* group);
/**********************************************************
*
* To check whether our algorithm makes sense, we keep count of the
* number of times the process has been rescheduled to another CPU
* while we were monitoring the performance of a group and we upload
* this data through Telemetry.
*/
nsresult UpdateTelemetry();
uint64_t mProcessStayed;
uint64_t mProcessMoved;
uint32_t mProcessUpdateCounter;
/**********************************************************
*
* Options controlling measurements.
*/
/**
* Determine if we are measuring the performance of every individual
* compartment (in particular, every individual module, frame,
* sandbox). Note that this makes measurements noticeably slower.
*/
bool mIsMonitoringPerCompartment;
};
/**
* Container for performance data.
*
* All values are monotonic.
*
* All values are updated after running to completion.
*/
struct PerformanceData {
/**
* Number of times we have spent at least 2^n consecutive
* milliseconds executing code in this group.
* durations[0] is increased whenever we spend at least 1 ms
* executing code in this group
* durations[1] whenever we spend 2ms+
* ...
* durations[i] whenever we spend 2^ims+
*/
uint64_t mDurations[10];
/**
* Total amount of time spent executing code in this group, in
* microseconds.
*/
uint64_t mTotalUserTime;
uint64_t mTotalSystemTime;
uint64_t mTotalCPOWTime;
/**
* Total number of times code execution entered this group, since
* process launch. This may be greater than the number of times we
* have entered the event loop.
*/
uint64_t mTicks;
PerformanceData();
PerformanceData(const PerformanceData& from) = default;
PerformanceData& operator=(const PerformanceData& from) = default;
};
/**
* Identification information for an item that can hold performance
* data.
*/
class nsPerformanceGroupDetails {
public:
nsPerformanceGroupDetails(const nsAString& aName,
const nsAString& aGroupId,
const nsAString& aAddonId,
const uint64_t aWindowId,
const uint64_t aProcessId,
const bool aIsSystem)
: mName(aName)
, mGroupId(aGroupId)
, mAddonId(aAddonId)
, mWindowId(aWindowId)
, mProcessId(aProcessId)
, mIsSystem(aIsSystem)
{ }
public:
const nsAString& Name() const;
const nsAString& GroupId() const;
const nsAString& AddonId() const;
uint64_t WindowId() const;
uint64_t ProcessId() const;
bool IsAddon() const;
bool IsWindow() const;
bool IsSystem() const;
private:
const nsString mName;
const nsString mGroupId;
const nsString mAddonId;
const uint64_t mWindowId;
const uint64_t mProcessId;
const bool mIsSystem;
};
/**
* The kind of compartments represented by this group.
*/
enum class PerformanceGroupScope {
/**
* This group represents the entire runtime (i.e. the thread).
*/
RUNTIME,
/**
* This group represents all the compartments executed in a window.
*/
WINDOW,
/**
* This group represents all the compartments provided by an addon.
*/
ADDON,
/**
* This group represents a single compartment.
*/
COMPARTMENT,
};
/**
* A concrete implementation of `js::PerformanceGroup`, also holding
* performance data. Instances may represent individual compartments,
* windows, addons or the entire runtime.
*
* This class is intended to be the sole implementation of
* `js::PerformanceGroup`.
*/
class nsPerformanceGroup final: public js::PerformanceGroup,
public nsPerformanceGroupDetails
{
public:
// Ideally, we would define the enum class in nsPerformanceGroup,
// but this seems to choke some versions of gcc.
typedef PerformanceGroupScope GroupScope;
/**
* Construct a performance group.
*
* @param rt The container runtime. Used to generate a unique identifier.
* @param service The performance service. Used during destruction to
* cleanup the hash tables.
* @param name A name for the group, designed mostly for debugging purposes,
* so it should be at least somewhat human-readable.
* @param addonId The identifier of the add-on. Should be "" when the
* group is not part of an add-on,
* @param windowId The identifier of the window. Should be 0 when the
* group is not part of a window.
* @param processId A unique identifier for the process.
* @param isSystem `true` if the code of the group is executed with
* system credentials, `false` otherwise.
* @param scope the scope of this group.
*/
static nsPerformanceGroup*
Make(JSRuntime* rt,
nsPerformanceStatsService* service,
const nsAString& name,
const nsAString& addonId,
uint64_t windowId,
uint64_t processId,
bool isSystem,
GroupScope scope);
/**
* Utility: type-safer conversion from js::PerformanceGroup to nsPerformanceGroup.
*/
static inline nsPerformanceGroup* Get(js::PerformanceGroup* self) {
return static_cast<nsPerformanceGroup*>(self);
}
static inline const nsPerformanceGroup* Get(const js::PerformanceGroup* self) {
return static_cast<const nsPerformanceGroup*>(self);
}
/**
* The performance data committed to this group.
*/
PerformanceData data;
/**
* The scope of this group. Used to determine whether the group
* should be (de)activated.
*/
GroupScope Scope() const;
/**
* Cleanup any references.
*/
void Dispose();
protected:
nsPerformanceGroup(nsPerformanceStatsService* service,
const nsAString& name,
const nsAString& groupId,
const nsAString& addonId,
uint64_t windowId,
uint64_t processId,
bool isSystem,
GroupScope scope);
/**
* Virtual implementation of `delete`, to make sure that objects are
* destoyed with an implementation of `delete` compatible with the
* implementation of `new` used to allocate them.
*
* Called by SpiderMonkey.
*/
virtual void Delete() override {
delete this;
}
virtual ~nsPerformanceGroup();
private:
/**
* The stats service. Used to perform cleanup during destruction.
*/
RefPtr<nsPerformanceStatsService> mService;
/**
* The scope of this group. Used to determine whether the group
* should be (de)activated.
*/
const GroupScope mScope;
};
#endif

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

@ -9577,7 +9577,7 @@
},
"PERF_MONITORING_TEST_CPU_RESCHEDULING_PROPORTION_MOVED": {
"alert_emails": ["dteller@mozilla.com"],
"expires_in_version": "48",
"expires_in_version": "45",
"kind": "linear",
"high": "100",
"n_buckets": "20",