/* 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 PerfStats_h #define PerfStats_h #include "mozilla/Atomics.h" #include "mozilla/TimeStamp.h" #include "mozilla/StaticMutex.h" #include "mozilla/StaticPtr.h" #include "mozilla/MozPromise.h" #include // PerfStats // // Framework for low overhead selective collection of internal performance // metrics through ChromeUtils. // // Gathering: in C++, wrap execution in an RAII class // PerfStats::AutoMetricRecording or call // PerfStats::RecordMeasurement{Start,End} manually. Use // RecordMeasurementCount() for incrementing counters. // // Controlling: Use ChromeUtils.setPerfStatsFeatures(array), where an empty // array disables all metrics. Pass metric names as strings, e.g. // ["LayerTransactions", "Rasterizing"]. To enable all features, use // ChromeUtils.enableAllPerfStatsFeatures(); // // Reporting: Results can be accessed with ChromeUtils.CollectPerfStats(). // Browsertime will sum results across processes and report them. // Define a new metric by adding it to this list. It will be created as a class // enum value mozilla::PerfStats::Metric::MyMetricName. #define FOR_EACH_PERFSTATS_METRIC(MACRO) \ MACRO(DisplayListBuilding) \ MACRO(Rasterizing) \ MACRO(WrDisplayListBuilding) \ MACRO(LayerTransactions) \ MACRO(FrameBuilding) \ MACRO(Compositing) \ MACRO(Reflowing) \ MACRO(Styling) \ MACRO(HttpChannelCompletion) \ MACRO(HttpChannelCompletion_Network) \ MACRO(HttpChannelCompletion_Cache) \ MACRO(HttpChannelAsyncOpenToTransactionPending) \ MACRO(HttpChannelResponseStartParentToContent) \ MACRO(HttpChannelResponseEndParentToContent) \ MACRO(HttpTransactionWaitTime) \ MACRO(ResponseEndSocketToParent) \ MACRO(OnStartRequestSocketToParent) \ MACRO(OnDataAvailableSocketToParent) \ MACRO(OnStopRequestSocketToParent) \ MACRO(OnStartRequestToContent) \ MACRO(OnDataAvailableToContent) \ MACRO(OnStopRequestToContent) \ MACRO(JSBC_Compression) \ MACRO(JSBC_Decompression) \ MACRO(JSBC_IO_Read) \ MACRO(JSBC_IO_Write) \ MACRO(MinorGC) \ MACRO(MajorGC) \ MACRO(NonIdleMajorGC) \ MACRO(A11Y_DoInitialUpdate) \ MACRO(A11Y_ProcessQueuedCacheUpdate) \ MACRO(A11Y_ContentRemovedNode) \ MACRO(A11Y_ContentRemovedAcc) \ MACRO(A11Y_PruneOrInsertSubtree) \ MACRO(A11Y_ShutdownChildrenInSubtree) \ MACRO(A11Y_ShowEvent) \ MACRO(A11Y_RecvCache) \ MACRO(A11Y_ProcessShowEvent) \ MACRO(A11Y_CoalesceEvents) \ MACRO(A11Y_CoalesceMutationEvents) \ MACRO(A11Y_ProcessHideEvent) \ MACRO(A11Y_SendCache) \ MACRO(A11Y_WillRefresh) \ MACRO(A11Y_AccessibilityServiceInit) \ MACRO(A11Y_PlatformShowHideEvent) namespace mozilla { namespace dom { // Forward declaration. class ContentParent; } // namespace dom class PerfStats { public: typedef MozPromise PerfStatsPromise; // MetricMask is a bitmask based on 'Metric', i.e. Metric::LayerBuilding (2) // is synonymous to 1 << 2 in MetricMask. using MetricMask = uint64_t; using MetricCounter = uint32_t; enum class Metric : MetricMask { #define DECLARE_ENUM(metric) metric, FOR_EACH_PERFSTATS_METRIC(DECLARE_ENUM) #undef DECLARE_ENUM Max }; static void RecordMeasurementStart(Metric aMetric) { if (!(sCollectionMask & (1 << static_cast(aMetric)))) { return; } RecordMeasurementStartInternal(aMetric); } static void RecordMeasurementEnd(Metric aMetric) { if (!(sCollectionMask & (1 << static_cast(aMetric)))) { return; } RecordMeasurementEndInternal(aMetric); } static void RecordMeasurement(Metric aMetric, TimeDuration aDuration) { if (!(sCollectionMask & (1 << static_cast(aMetric)))) { return; } RecordMeasurementInternal(aMetric, aDuration); } static void RecordMeasurementCounter(Metric aMetric, MetricMask aIncrementAmount) { if (!(sCollectionMask & (1 << static_cast(aMetric)))) { return; } RecordMeasurementCounterInternal(aMetric, aIncrementAmount); } template class AutoMetricRecording { public: AutoMetricRecording() { PerfStats::RecordMeasurementStart(N); } ~AutoMetricRecording() { PerfStats::RecordMeasurementEnd(N); } }; static void SetCollectionMask(MetricMask aMask); static MetricMask GetCollectionMask(); static RefPtr CollectPerfStatsJSON() { return GetSingleton()->CollectPerfStatsJSONInternal(); } static nsCString CollectLocalPerfStatsJSON() { return GetSingleton()->CollectLocalPerfStatsJSONInternal(); } static void StorePerfStats(dom::ContentParent* aParent, const nsACString& aPerfStats) { GetSingleton()->StorePerfStatsInternal(aParent, aPerfStats); } // Returns the mask with the bit set for a given metric name, or 0 if not // found static MetricMask GetFeatureMask(const char* aMetricName); private: static PerfStats* GetSingleton(); static void RecordMeasurementStartInternal(Metric aMetric); static void RecordMeasurementEndInternal(Metric aMetric); static void RecordMeasurementInternal(Metric aMetric, TimeDuration aDuration); static void RecordMeasurementCounterInternal(Metric aMetric, MetricCounter aIncrementAmount); void ResetCollection(); void StorePerfStatsInternal(dom::ContentParent* aParent, const nsACString& aPerfStats); RefPtr CollectPerfStatsJSONInternal(); nsCString CollectLocalPerfStatsJSONInternal(); static Atomic sCollectionMask; static StaticMutex sMutex MOZ_UNANNOTATED; static StaticAutoPtr sSingleton; TimeStamp mRecordedStarts[static_cast(Metric::Max)]; double mRecordedTimes[static_cast(Metric::Max)]; MetricCounter mRecordedCounts[static_cast(Metric::Max)]; nsTArray mStoredPerfStats; }; static_assert(static_cast(1) << (static_cast(PerfStats::Metric::Max) - 1) <= std::numeric_limits::max(), "More metrics than can fit into sCollectionMask bitmask"); } // namespace mozilla #endif // PerfStats_h