1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef PerfStats_h
8 #define PerfStats_h
9 
10 #include "mozilla/TimeStamp.h"
11 #include "mozilla/StaticMutex.h"
12 #include "mozilla/StaticPtr.h"
13 #include "mozilla/MozPromise.h"
14 #include <memory>
15 #include <string>
16 #include <limits>
17 
18 namespace mozilla {
19 
20 class PerfStats {
21  public:
22   typedef MozPromise<nsCString, bool, true> PerfStatsPromise;
23 
24   enum class Metric : uint32_t {
25     DisplayListBuilding = 0,
26     Rasterizing,
27     LayerBuilding,
28     LayerTransactions,
29     Compositing,
30     Reflowing,
31     Styling,
32     HttpChannelCompletion,
33     HttpChannelCompletion_Network,
34     HttpChannelCompletion_Cache,
35     Max
36   };
37 
38   // MetricMask is a bitmask based on 'Metric', i.e. Metric::LayerBuilding (2)
39   // is synonymous to 1 << 2 in MetricMask.
40   using MetricMask = uint64_t;
41 
RecordMeasurementStart(Metric aMetric)42   static void RecordMeasurementStart(Metric aMetric) {
43     if (!(sCollectionMask & (1 << static_cast<uint64_t>(aMetric)))) {
44       return;
45     }
46     RecordMeasurementStartInternal(aMetric);
47   }
48 
RecordMeasurementEnd(Metric aMetric)49   static void RecordMeasurementEnd(Metric aMetric) {
50     if (!(sCollectionMask & (1 << static_cast<uint64_t>(aMetric)))) {
51       return;
52     }
53     RecordMeasurementEndInternal(aMetric);
54   }
55 
RecordMeasurement(Metric aMetric,TimeDuration aDuration)56   static void RecordMeasurement(Metric aMetric, TimeDuration aDuration) {
57     if (!(sCollectionMask & (1 << static_cast<uint64_t>(aMetric)))) {
58       return;
59     }
60     RecordMeasurementInternal(aMetric, aDuration);
61   }
62 
63   template <Metric N>
64   class AutoMetricRecording {
65    public:
AutoMetricRecording()66     AutoMetricRecording() { PerfStats::RecordMeasurementStart(N); }
~AutoMetricRecording()67     ~AutoMetricRecording() { PerfStats::RecordMeasurementEnd(N); }
68   };
69 
70   static void SetCollectionMask(MetricMask aMask);
71 
CollectPerfStatsJSON()72   static RefPtr<PerfStatsPromise> CollectPerfStatsJSON() {
73     return GetSingleton()->CollectPerfStatsJSONInternal();
74   }
75 
CollectLocalPerfStatsJSON()76   static nsCString CollectLocalPerfStatsJSON() {
77     return GetSingleton()->CollectLocalPerfStatsJSONInternal();
78   }
79 
80  private:
81   static PerfStats* GetSingleton();
82   static void RecordMeasurementStartInternal(Metric aMetric);
83   static void RecordMeasurementEndInternal(Metric aMetric);
84   static void RecordMeasurementInternal(Metric aMetric, TimeDuration aDuration);
85 
86   RefPtr<PerfStatsPromise> CollectPerfStatsJSONInternal();
87   nsCString CollectLocalPerfStatsJSONInternal();
88 
89   static MetricMask sCollectionMask;
90   static StaticMutex sMutex;
91   static StaticAutoPtr<PerfStats> sSingleton;
92   TimeStamp mRecordedStarts[static_cast<size_t>(Metric::Max)];
93   double mRecordedTimes[static_cast<size_t>(Metric::Max)];
94 };
95 
96 static_assert(1 << (static_cast<uint64_t>(PerfStats::Metric::Max) - 1) <=
97                   std::numeric_limits<PerfStats::MetricMask>::max(),
98               "More metrics than can fit into sCollectionMask bitmask");
99 
100 }  // namespace mozilla
101 
102 #endif  // PerfStats_h
103