summaryrefslogtreecommitdiffstats
path: root/toolkit/components/perfmonitoring/nsPerformanceStats.h
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/perfmonitoring/nsPerformanceStats.h')
-rw-r--r--toolkit/components/perfmonitoring/nsPerformanceStats.h825
1 files changed, 825 insertions, 0 deletions
diff --git a/toolkit/components/perfmonitoring/nsPerformanceStats.h b/toolkit/components/perfmonitoring/nsPerformanceStats.h
new file mode 100644
index 000000000..c82a3e92c
--- /dev/null
+++ b/toolkit/components/perfmonitoring/nsPerformanceStats.h
@@ -0,0 +1,825 @@
+/* -*- 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 Context for the main thread.
+ */
+ JSContext* const mContext;
+
+ /**
+ * 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 cx The container context. 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(JSContext* cx,
+ 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