mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 22:55:23 +00:00
826 lines
24 KiB
C++
826 lines
24 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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/. */
|
|
|
|
#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;
|
|
class nsPerformanceGroupDetails;
|
|
|
|
typedef mozilla::Vector<RefPtr<nsPerformanceGroup>> GroupVector;
|
|
|
|
/**
|
|
* A data structure for registering observers interested in
|
|
* performance alerts.
|
|
*
|
|
* Each performance group owns a single instance of this class.
|
|
* Additionally, the service owns instances designed to observe the
|
|
* performance alerts in all add-ons (respectively webpages).
|
|
*/
|
|
class nsPerformanceObservationTarget final: public nsIPerformanceObservable {
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIPERFORMANCEOBSERVABLE
|
|
|
|
/**
|
|
* `true` if this target has at least once performance observer
|
|
* registered, `false` otherwise.
|
|
*/
|
|
bool HasObservers() const;
|
|
|
|
/**
|
|
* Notify all the observers that jank has happened.
|
|
*/
|
|
void NotifyJankObservers(nsIPerformanceGroupDetails* source, nsIPerformanceAlert* gravity);
|
|
|
|
/**
|
|
* Set the details on the group being observed.
|
|
*/
|
|
void SetTarget(nsPerformanceGroupDetails* details);
|
|
|
|
private:
|
|
~nsPerformanceObservationTarget() {}
|
|
|
|
// The observers for this target. We hold them as a vector, despite
|
|
// the linear removal cost, as we expect that the typical number of
|
|
// observers will be lower than 3, and that (un)registrations will
|
|
// be fairly infrequent.
|
|
mozilla::Vector<nsCOMPtr<nsIPerformanceObserver>> mObservers;
|
|
|
|
// Details on the group being observed. May be `nullptr`.
|
|
RefPtr<nsPerformanceGroupDetails> mDetails;
|
|
};
|
|
|
|
/**
|
|
* The base class for entries of maps from addon id/window id to
|
|
* performance group.
|
|
*
|
|
* Performance observers may be registered before their group is
|
|
* created (e.g., one may register an observer for an add-on before
|
|
* all its modules are loaded, or even before the add-on is loaded at
|
|
* all or for an observer for a webpage before all its iframes are
|
|
* loaded). This class serves to hold the observation target until the
|
|
* performance group may be created, and then to associate the
|
|
* observation target and the performance group.
|
|
*/
|
|
class nsGroupHolder {
|
|
public:
|
|
nsGroupHolder()
|
|
: mGroup(nullptr)
|
|
, mPendingObservationTarget(nullptr)
|
|
{ }
|
|
|
|
/**
|
|
* Get the observation target, creating it if necessary.
|
|
*/
|
|
nsPerformanceObservationTarget* ObservationTarget();
|
|
|
|
/**
|
|
* Get the group, if it has been created.
|
|
*
|
|
* May return `null` if the group hasn't been created yet.
|
|
*/
|
|
class nsPerformanceGroup* GetGroup();
|
|
|
|
/**
|
|
* Set the group.
|
|
*
|
|
* Once this method has been called, calling
|
|
* `this->ObservationTarget()` and `group->ObservationTarget()` is equivalent.
|
|
*
|
|
* Must only be called once.
|
|
*/
|
|
void SetGroup(class nsPerformanceGroup*);
|
|
private:
|
|
// The group. Initially `nullptr`, until we have called `SetGroup`.
|
|
class nsPerformanceGroup* mGroup;
|
|
|
|
// The observation target. Instantiated by the first call to
|
|
// `ObservationTarget()`.
|
|
RefPtr<nsPerformanceObservationTarget> mPendingObservationTarget;
|
|
};
|
|
|
|
/**
|
|
* An implementation of the nsIPerformanceStatsService.
|
|
*
|
|
* Note that this implementation is not thread-safe.
|
|
*/
|
|
class nsPerformanceStatsService final : public nsIPerformanceStatsService,
|
|
public nsIObserver
|
|
{
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIPERFORMANCESTATSSERVICE
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
nsPerformanceStatsService();
|
|
nsresult Init();
|
|
|
|
private:
|
|
nsresult InitInternal();
|
|
void Dispose();
|
|
~nsPerformanceStatsService();
|
|
|
|
protected:
|
|
friend nsPerformanceGroup;
|
|
|
|
/**
|
|
* `false` until `Init()` and after `Dispose()`, `true` inbetween.
|
|
*/
|
|
bool mIsAvailable;
|
|
|
|
/**
|
|
* `true` once we have called `Dispose()`.
|
|
*/
|
|
bool mDisposed;
|
|
|
|
/**
|
|
* 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, js::PerformanceGroupVector&);
|
|
static bool GetPerformanceGroupsCallback(JSContext* cx, js::PerformanceGroupVector&, 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,
|
|
public nsGroupHolder {
|
|
explicit AddonIdToGroup(const nsAString* key)
|
|
: nsStringHashKey(key)
|
|
{ }
|
|
};
|
|
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,
|
|
public nsGroupHolder {
|
|
explicit WindowIdToGroup(const uint64_t* key)
|
|
: nsUint64HashKey(key)
|
|
{}
|
|
};
|
|
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;
|
|
|
|
bool mIsHandlingUserInput;
|
|
|
|
/**
|
|
* The number of user inputs since the start of the process. Used to
|
|
* determine whether the current iteration has triggered a
|
|
* (JS-implemented) user input.
|
|
*/
|
|
uint64_t mUserInputCount;
|
|
|
|
/**********************************************************
|
|
*
|
|
* 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,
|
|
js::PerformanceGroupVector& recentGroups,
|
|
void* closure);
|
|
bool StopwatchCommit(uint64_t iteration, js::PerformanceGroupVector& 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 isJankVisible If `true`, expect that the user will notice
|
|
* any slowdown.
|
|
* @param group The group containing the data to commit.
|
|
*/
|
|
void CommitGroup(uint64_t iteration,
|
|
uint64_t userTime, uint64_t systemTime, uint64_t cycles,
|
|
bool isJankVisible,
|
|
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;
|
|
|
|
|
|
/**********************************************************
|
|
*
|
|
* Determining whether jank is user-visible.
|
|
*/
|
|
|
|
/**
|
|
* `true` if we believe that any slowdown can cause a noticeable
|
|
* delay in handling user-input.
|
|
*
|
|
* In the current implementation, we return `true` if the latest
|
|
* user input was less than MAX_DURATION_OF_INTERACTION_MS ago. This
|
|
* includes all inputs (mouse, keyboard, other devices), with the
|
|
* exception of mousemove.
|
|
*/
|
|
bool IsHandlingUserInput();
|
|
|
|
|
|
public:
|
|
/**********************************************************
|
|
*
|
|
* Letting observers register themselves to watch for performance
|
|
* alerts.
|
|
*
|
|
* To avoid saturating clients with alerts (or even creating loops
|
|
* of alerts), each alert is buffered. At the end of each iteration
|
|
* of the event loop, groups that have caused performance alerts
|
|
* are registered in a set of pending alerts, and the collection
|
|
* timer hasn't been started yet, it is started. Once the timer
|
|
* firers, we gather all the pending alerts, empty the set and
|
|
* dispatch to observers.
|
|
*/
|
|
|
|
/**
|
|
* Clear the set of pending alerts and dispatch the pending alerts
|
|
* to observers.
|
|
*/
|
|
void NotifyJankObservers(const mozilla::Vector<uint64_t>& previousJankLevels);
|
|
|
|
private:
|
|
/**
|
|
* The set of groups for which we know that an alert should be
|
|
* raised. This set is cleared once `mPendingAlertsCollector`
|
|
* fires.
|
|
*
|
|
* Invariant: no group may appear twice in this vector.
|
|
*/
|
|
GroupVector mPendingAlerts;
|
|
|
|
/**
|
|
* A timer callback in charge of collecting the groups in
|
|
* `mPendingAlerts` and triggering `NotifyJankObservers` to dispatch
|
|
* performance alerts.
|
|
*/
|
|
RefPtr<class PendingAlertsCollector> mPendingAlertsCollector;
|
|
|
|
|
|
/**
|
|
* Observation targets that are not attached to a specific group.
|
|
*/
|
|
struct UniversalTargets {
|
|
UniversalTargets();
|
|
/**
|
|
* A target for observers interested in watching all addons.
|
|
*/
|
|
RefPtr<nsPerformanceObservationTarget> mAddons;
|
|
|
|
/**
|
|
* A target for observers interested in watching all windows.
|
|
*/
|
|
RefPtr<nsPerformanceObservationTarget> mWindows;
|
|
};
|
|
UniversalTargets mUniversalTargets;
|
|
|
|
/**
|
|
* The threshold, in microseconds, above which a performance group is
|
|
* considered "slow" and should raise performance alerts.
|
|
*/
|
|
uint64_t mJankAlertThreshold;
|
|
|
|
/**
|
|
* A buffering delay, in milliseconds, used by the service to
|
|
* regroup performance alerts, before observers are actually
|
|
* noticed. Higher delays let the system avoid redundant
|
|
* notifications for the same group, and are generally better for
|
|
* performance.
|
|
*/
|
|
uint32_t mJankAlertBufferingDelay;
|
|
|
|
/**
|
|
* The threshold above which jank, as reported by the refresh drivers,
|
|
* is considered user-visible.
|
|
*
|
|
* A value of n means that any jank above 2^n ms will be considered
|
|
* user visible.
|
|
*/
|
|
short mJankLevelVisibilityThreshold;
|
|
|
|
/**
|
|
* The number of microseconds during which we assume that a
|
|
* user-interaction can keep the code jank-critical. Any user
|
|
* interaction that lasts longer than this duration is expected to
|
|
* either have already caused jank or have caused a nested event
|
|
* loop.
|
|
*
|
|
* In either case, we consider that monitoring
|
|
* jank-during-interaction after this duration is useless.
|
|
*/
|
|
uint64_t mMaxExpectedDurationOfInteractionUS;
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* 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 final: public nsIPerformanceGroupDetails {
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIPERFORMANCEGROUPDETAILS
|
|
|
|
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;
|
|
bool IsContentProcess() const;
|
|
private:
|
|
~nsPerformanceGroupDetails() {}
|
|
|
|
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:
|
|
|
|
// 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;
|
|
|
|
/**
|
|
* Identification details for this group.
|
|
*/
|
|
nsPerformanceGroupDetails* Details() const;
|
|
|
|
/**
|
|
* Cleanup any references.
|
|
*/
|
|
void Dispose();
|
|
|
|
/**
|
|
* Set the observation target for this group.
|
|
*
|
|
* This method must be called exactly once, when the performance
|
|
* group is attached to its `nsGroupHolder`.
|
|
*/
|
|
void SetObservationTarget(nsPerformanceObservationTarget*);
|
|
|
|
|
|
/**
|
|
* `true` if we have already noticed that a performance alert should
|
|
* be raised for this group but we have not dispatched it yet,
|
|
* `false` otherwise.
|
|
*/
|
|
bool HasPendingAlert() const;
|
|
void SetHasPendingAlert(bool value);
|
|
|
|
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;
|
|
}
|
|
~nsPerformanceGroup();
|
|
|
|
private:
|
|
/**
|
|
* Identification details for this group.
|
|
*/
|
|
RefPtr<nsPerformanceGroupDetails> mDetails;
|
|
|
|
/**
|
|
* 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;
|
|
|
|
// Observing performance alerts.
|
|
|
|
public:
|
|
/**
|
|
* The observation target, used to register observers.
|
|
*/
|
|
nsPerformanceObservationTarget* ObservationTarget() const;
|
|
|
|
/**
|
|
* Record a jank duration.
|
|
*
|
|
* Update the highest recent jank if necessary.
|
|
*/
|
|
void RecordJank(uint64_t jank);
|
|
uint64_t HighestRecentJank();
|
|
|
|
/**
|
|
* Record a CPOW duration.
|
|
*
|
|
* Update the highest recent CPOW if necessary.
|
|
*/
|
|
void RecordCPOW(uint64_t cpow);
|
|
uint64_t HighestRecentCPOW();
|
|
|
|
/**
|
|
* Record that this group has recently been involved in handling
|
|
* user input. Note that heuristics are involved here, so the
|
|
* result is not 100% accurate.
|
|
*/
|
|
void RecordUserInput();
|
|
bool HasRecentUserInput();
|
|
|
|
/**
|
|
* Reset recent values (recent highest CPOW and jank, involvement in
|
|
* user input).
|
|
*/
|
|
void ResetRecent();
|
|
private:
|
|
/**
|
|
* The target used by observers to register for watching slow
|
|
* performance alerts caused by this group.
|
|
*
|
|
* May be nullptr for groups that cannot be watched (the top group).
|
|
*/
|
|
RefPtr<class nsPerformanceObservationTarget> mObservationTarget;
|
|
|
|
/**
|
|
* The highest jank encountered since jank observers for this group
|
|
* were last called, in microseconds.
|
|
*/
|
|
uint64_t mHighestJank;
|
|
|
|
/**
|
|
* The highest CPOW encountered since jank observers for this group
|
|
* were last called, in microseconds.
|
|
*/
|
|
uint64_t mHighestCPOW;
|
|
|
|
/**
|
|
* `true` if this group has been involved in handling user input,
|
|
* `false` otherwise.
|
|
*
|
|
* Note that we use heuristics to determine whether a group is
|
|
* involved in handling user input, so this value is not 100%
|
|
* accurate.
|
|
*/
|
|
bool mHasRecentUserInput;
|
|
|
|
/**
|
|
* `true` if this group has caused a performance alert and this alert
|
|
* hasn't been dispatched yet.
|
|
*
|
|
* We use this as part of the buffering of performance alerts. If
|
|
* the group generates several alerts several times during the
|
|
* buffering delay, we only wish to add the group once to the list
|
|
* of alerts.
|
|
*/
|
|
bool mHasPendingAlert;
|
|
};
|
|
|
|
#endif
|