BaseProfilerCounts.h (11916B)
1 /* -*- Mode: C++; tab-width: 2; 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 BaseProfilerCounts_h 8 #define BaseProfilerCounts_h 9 10 #ifndef MOZ_GECKO_PROFILER 11 12 # define BASE_PROFILER_DEFINE_COUNT_TOTAL(label, category, description) 13 # define BASE_PROFILER_DEFINE_COUNT(label, category, description) 14 # define BASE_PROFILER_DEFINE_STATIC_COUNT_TOTAL(label, category, description) 15 # define AUTO_BASE_PROFILER_COUNT_TOTAL(label, count) 16 # define AUTO_BASE_PROFILER_COUNT(label) 17 # define AUTO_BASE_PROFILER_STATIC_COUNT(label, count) 18 # define AUTO_BASE_PROFILER_FORCE_ALLOCATION(label) 19 20 #else 21 22 # include "mozilla/Assertions.h" 23 # include "mozilla/Atomics.h" 24 25 namespace mozilla { 26 namespace baseprofiler { 27 28 class BaseProfilerCount; 29 MFBT_API void profiler_add_sampled_counter(BaseProfilerCount* aCounter); 30 MFBT_API void profiler_remove_sampled_counter(BaseProfilerCount* aCounter); 31 32 typedef Atomic<int64_t, MemoryOrdering::Relaxed> ProfilerAtomicSigned; 33 typedef Atomic<uint64_t, MemoryOrdering::Relaxed> ProfilerAtomicUnsigned; 34 35 // Counter support 36 // There are two types of counters: 37 // 1) a simple counter which can be added to or subtracted from. This could 38 // track the number of objects of a type, the number of calls to something 39 // (reflow, JIT, etc). 40 // 2) a combined counter which has the above, plus a number-of-calls counter 41 // that is incremented by 1 for each call to modify the count. This provides 42 // an optional source for a 'heatmap' of access. This can be used (for 43 // example) to track the amount of memory allocated, and provide a heatmap of 44 // memory operations (allocs/frees). 45 // 46 // Counters are sampled by the profiler once per sample-period. At this time, 47 // all counters are global to the process. In the future, there might be more 48 // versions with per-thread or other discriminators. 49 // 50 // Typical usage: 51 // There are two ways to use counters: With heap-created counter objects, 52 // or using macros. Note: the macros use statics, and will be slightly 53 // faster/smaller, and you need to care about creating them before using 54 // them. They're similar to the use-pattern for the other AUTO_PROFILER* 55 // macros, but they do need the PROFILER_DEFINE* to be use to instantiate 56 // the statics. 57 // 58 // PROFILER_DEFINE_COUNT(mything, "JIT", "Some JIT byte count") 59 // ... 60 // void foo() { ... AUTO_PROFILER_COUNT(mything, number_of_bytes_used); ... } 61 // 62 // or (to also get a heatmap) 63 // 64 // PROFILER_DEFINE_COUNT_TOTAL(mything, "JIT", "Some JIT byte count") 65 // ... 66 // void foo() { 67 // ... 68 // AUTO_PROFILER_COUNT_TOTAL(mything, number_of_bytes_generated); 69 // ... 70 // } 71 // 72 // To use without statics/macros: 73 // 74 // UniquePtr<ProfilerCounter> myCounter; 75 // ... 76 // myCounter = 77 // MakeUnique<ProfilerCounter>("mything", "JIT", "Some JIT byte count")); 78 // ... 79 // void foo() { ... myCounter->Add(number_of_bytes_generated0; ... } 80 81 class BaseProfilerCount { 82 public: 83 BaseProfilerCount(const char* aLabel, ProfilerAtomicSigned* aCounter, 84 ProfilerAtomicUnsigned* aNumber, const char* aCategory, 85 const char* aDescription) 86 : mLabel(aLabel), 87 mCategory(aCategory), 88 mDescription(aDescription), 89 mCounter(aCounter), 90 mNumber(aNumber) { 91 # define COUNTER_CANARY 0xDEADBEEF 92 # ifdef DEBUG 93 mCanary = COUNTER_CANARY; 94 mPrevNumber = 0; 95 # endif 96 // Can't call profiler_* here since this may be non-xul-library 97 } 98 # ifdef DEBUG 99 ~BaseProfilerCount() { mCanary = 0; } 100 # endif 101 102 void Sample(int64_t& aCounter, uint64_t& aNumber) { 103 MOZ_ASSERT(mCanary == COUNTER_CANARY); 104 105 aCounter = *mCounter; 106 aNumber = mNumber ? *mNumber : 0; 107 # ifdef DEBUG 108 MOZ_ASSERT(aNumber >= mPrevNumber); 109 mPrevNumber = aNumber; 110 # endif 111 } 112 113 // We don't define ++ and Add() here, since the static defines directly 114 // increment the atomic counters, and the subclasses implement ++ and 115 // Add() directly. 116 117 // These typically are static strings (for example if you use the macros 118 // below) 119 const char* mLabel; 120 const char* mCategory; 121 const char* mDescription; 122 // We're ok with these being un-ordered in race conditions. These are 123 // pointers because we want to be able to use statics and increment them 124 // directly. Otherwise we could just have them inline, and not need the 125 // constructor args. 126 // These can be static globals (using the macros below), though they 127 // don't have to be - their lifetime must be longer than the use of them 128 // by the profiler (see profiler_add/remove_sampled_counter()). If you're 129 // using a lot of these, they probably should be allocated at runtime (see 130 // class ProfilerCountOnly below). 131 ProfilerAtomicSigned* mCounter; 132 ProfilerAtomicUnsigned* mNumber; // may be null 133 134 # ifdef DEBUG 135 uint32_t mCanary; 136 uint64_t mPrevNumber; // value of number from the last Sample() 137 # endif 138 }; 139 140 // Designed to be allocated dynamically, and simply incremented with obj++ 141 // or obj->Add(n) 142 class ProfilerCounter final : public BaseProfilerCount { 143 public: 144 ProfilerCounter(const char* aLabel, const char* aCategory, 145 const char* aDescription) 146 : BaseProfilerCount(aLabel, &mCounter, nullptr, aCategory, aDescription) { 147 // Assume we're in libxul 148 profiler_add_sampled_counter(this); 149 } 150 151 ~ProfilerCounter() { profiler_remove_sampled_counter(this); } 152 153 BaseProfilerCount& operator++() { 154 Add(1); 155 return *this; 156 } 157 158 void Add(int64_t aNumber) { mCounter += aNumber; } 159 160 ProfilerAtomicSigned mCounter; 161 }; 162 163 // Also keeps a heatmap (number of calls to ++/Add()) 164 class ProfilerCounterTotal final : public BaseProfilerCount { 165 public: 166 ProfilerCounterTotal(const char* aLabel, const char* aCategory, 167 const char* aDescription) 168 : BaseProfilerCount(aLabel, &mCounter, &mNumber, aCategory, 169 aDescription) { 170 // Assume we're in libxul 171 profiler_add_sampled_counter(this); 172 } 173 174 ~ProfilerCounterTotal() { profiler_remove_sampled_counter(this); } 175 176 BaseProfilerCount& operator++() { 177 Add(1); 178 return *this; 179 } 180 181 void Add(int64_t aNumber) { 182 mCounter += aNumber; 183 mNumber++; 184 } 185 186 ProfilerAtomicSigned mCounter; 187 ProfilerAtomicUnsigned mNumber; 188 }; 189 190 // Defines a counter that is sampled on each profiler tick, with a running 191 // count (signed), and number-of-instances. Note that because these are two 192 // independent Atomics, there is a possiblity that count will not include 193 // the last call, but number of uses will. I think this is not worth 194 // worrying about 195 # define BASE_PROFILER_DEFINE_COUNT_TOTAL(label, category, description) \ 196 ProfilerAtomicSigned profiler_count_##label(0); \ 197 ProfilerAtomicUnsigned profiler_number_##label(0); \ 198 const char profiler_category_##label[] = category; \ 199 const char profiler_description_##label[] = description; \ 200 UniquePtr<::mozilla::baseprofiler::BaseProfilerCount> AutoCount_##label; 201 202 // This counts, but doesn't keep track of the number of calls to 203 // AUTO_PROFILER_COUNT() 204 # define BASE_PROFILER_DEFINE_COUNT(label, category, description) \ 205 ProfilerAtomicSigned profiler_count_##label(0); \ 206 const char profiler_category_##label[] = category; \ 207 const char profiler_description_##label[] = description; \ 208 UniquePtr<::mozilla::baseprofiler::BaseProfilerCount> AutoCount_##label; 209 210 // This will create a static initializer if used, but avoids a possible 211 // allocation. 212 # define BASE_PROFILER_DEFINE_STATIC_COUNT_TOTAL(label, category, \ 213 description) \ 214 ProfilerAtomicSigned profiler_count_##label(0); \ 215 ProfilerAtomicUnsigned profiler_number_##label(0); \ 216 ::mozilla::baseprofiler::BaseProfilerCount AutoCount_##label( \ 217 #label, &profiler_count_##label, &profiler_number_##label, category, \ 218 description); 219 220 // If we didn't care about static initializers, we could avoid the need for 221 // a ptr to the BaseProfilerCount object. 222 223 // XXX It would be better to do this without the if() and without the 224 // theoretical race to set the UniquePtr (i.e. possible leak). 225 # define AUTO_BASE_PROFILER_COUNT_TOTAL(label, count) \ 226 do { \ 227 profiler_number_##label++; /* do this first*/ \ 228 profiler_count_##label += count; \ 229 if (!AutoCount_##label) { \ 230 /* Ignore that we could call this twice in theory, and that we leak \ 231 * them \ 232 */ \ 233 AutoCount_##label.reset(new BaseProfilerCount( \ 234 #label, &profiler_count_##label, &profiler_number_##label, \ 235 profiler_category_##label, profiler_description_##label)); \ 236 ::mozilla::baseprofiler::profiler_add_sampled_counter( \ 237 AutoCount_##label.get()); \ 238 } \ 239 } while (0) 240 241 # define AUTO_BASE_PROFILER_COUNT(label, count) \ 242 do { \ 243 profiler_count_##label += count; /* do this first*/ \ 244 if (!AutoCount_##label) { \ 245 /* Ignore that we could call this twice in theory, and that we leak \ 246 * them \ 247 */ \ 248 AutoCount_##label.reset(new BaseProfilerCount( \ 249 #label, nullptr, &profiler_number_##label, \ 250 profiler_category_##label, profiler_description_##label)); \ 251 ::mozilla::baseprofiler::profiler_add_sampled_counter( \ 252 AutoCount_##label.get()); \ 253 } \ 254 } while (0) 255 256 # define AUTO_BASE_PROFILER_STATIC_COUNT(label, count) \ 257 do { \ 258 profiler_number_##label++; /* do this first*/ \ 259 profiler_count_##label += count; \ 260 } while (0) 261 262 // if we need to force the allocation 263 # define AUTO_BASE_PROFILER_FORCE_ALLOCATION(label) \ 264 do { \ 265 if (!AutoCount_##label) { \ 266 /* Ignore that we could call this twice in theory, and that we leak \ 267 * them \ 268 */ \ 269 AutoCount_##label.reset( \ 270 new ::mozilla::baseprofiler::BaseProfilerCount( \ 271 #label, &profiler_count_##label, &profiler_number_##label, \ 272 profiler_category_##label, profiler_description_##label)); \ 273 } \ 274 } while (0) 275 276 } // namespace baseprofiler 277 } // namespace mozilla 278 279 #endif // !MOZ_GECKO_PROFILER 280 281 #endif // BaseProfilerCounts_h