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 mozilla_PerformanceCounter_h 8 #define mozilla_PerformanceCounter_h 9 10 #include "mozilla/Array.h" 11 #include "mozilla/Atomics.h" 12 #include "mozilla/TaskCategory.h" 13 #include "nsISupportsImpl.h" 14 #include "nsString.h" 15 16 namespace mozilla { 17 18 /* 19 * The DispatchCategory class is used to fake the inheritance 20 * of the TaskCategory enum so we can extend it to hold 21 * one more value corresponding to the category 22 * we use when a worker dispatches a call. 23 * 24 */ 25 class DispatchCategory final { 26 public: DispatchCategory(uint32_t aValue)27 explicit DispatchCategory(uint32_t aValue) : mValue(aValue) { 28 // Since DispatchCategory is adding one single value to the 29 // TaskCategory enum, we can check here that the value is 30 // the next index e.g. TaskCategory::Count 31 MOZ_ASSERT(aValue == (uint32_t)TaskCategory::Count); 32 } 33 DispatchCategory(TaskCategory aValue)34 constexpr explicit DispatchCategory(TaskCategory aValue) 35 : mValue((uint32_t)aValue) {} 36 GetValue()37 uint32_t GetValue() const { return mValue; } 38 39 static const DispatchCategory Worker; 40 41 private: 42 uint32_t mValue; 43 }; 44 45 typedef Array<Atomic<uint32_t>, (uint32_t)TaskCategory::Count + 1> 46 DispatchCounter; 47 48 // PerformanceCounter is a class that can be used to keep track of 49 // runnable execution times and dispatch counts. 50 // 51 // - runnable execution time: time spent in a runnable when called 52 // in nsThread::ProcessNextEvent (not counting recursive calls) 53 // - dispatch counts: number of times a tracked runnable is dispatched 54 // in nsThread. Useful to measure the activity of a tab or worker. 55 // 56 // The PerformanceCounter class is currently instantiated in DocGroup 57 // and WorkerPrivate in order to count how many scheduler dispatches 58 // are done through them, and how long the execution lasts. 59 // 60 // The execution time is calculated by the nsThread class (and its 61 // inherited WorkerThread class) in its ProcessNextEvent method. 62 // 63 // For each processed runnable, nsThread will reach out the 64 // PerformanceCounter attached to the runnable via its DocGroup 65 // or WorkerPrivate and call IncrementExecutionDuration() 66 // 67 // Notice that the execution duration counting takes into account 68 // recursivity. If an event triggers a recursive call to 69 // nsThread::ProcessNextEVent, the counter will discard the time 70 // spent in sub events. 71 class PerformanceCounter final { 72 public: 73 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PerformanceCounter) 74 75 explicit PerformanceCounter(const nsACString& aName); 76 77 /** 78 * This is called everytime a runnable is dispatched. 79 * 80 * aCategory can be used to distinguish counts per TaskCategory 81 * 82 * Note that an overflow will simply reset the counter. 83 */ 84 void IncrementDispatchCounter(DispatchCategory aCategory); 85 86 /** 87 * This is called via nsThread::ProcessNextEvent to measure runnable 88 * execution duration. 89 * 90 * Note that an overflow will simply reset the counter. 91 */ 92 void IncrementExecutionDuration(uint32_t aMicroseconds); 93 94 /** 95 * Returns a category/counter array of all dispatches. 96 */ 97 const DispatchCounter& GetDispatchCounter() const; 98 99 /** 100 * Returns the total execution duration. 101 */ 102 uint64_t GetExecutionDuration() const; 103 104 /** 105 * Returns the number of dispatches per TaskCategory. 106 */ 107 uint32_t GetDispatchCount(DispatchCategory aCategory) const; 108 109 /** 110 * Returns the total number of dispatches. 111 */ 112 uint64_t GetTotalDispatchCount() const; 113 114 /** 115 * Returns the unique id for the instance. 116 * 117 * Used to distinguish instances since the lifespan of 118 * a PerformanceCounter can be shorter than the 119 * host it's tracking. That leads to edge cases 120 * where a counter appears to have values that go 121 * backwards. Having this id let the consumers 122 * detect that they are dealing with a new counter 123 * when it happens. 124 */ 125 uint64_t GetID() const; 126 127 private: 128 ~PerformanceCounter() = default; 129 130 Atomic<uint64_t> mExecutionDuration; 131 Atomic<uint64_t> mTotalDispatchCount; 132 DispatchCounter mDispatchCounter; 133 nsCString mName; 134 const uint64_t mID; 135 }; 136 137 } // namespace mozilla 138 139 #endif // mozilla_PerformanceCounter_h 140