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