[SM91] Update to Spidermonkey 91.1.3 APIs
[0ad.git] / libraries / source / spidermonkey / include-win32-release / mozilla / BaseProfilerState.h
blobc1344c3b5d140d29a611b2433ae4479b40c4b2ba
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 // The Gecko Profiler is an always-on profiler that takes fast and low overhead
8 // samples of the program execution using only userspace functionality for
9 // portability. The goal of this module is to provide performance data in a
10 // generic cross-platform way without requiring custom tools or kernel support.
12 // Samples are collected to form a timeline with optional timeline event
13 // (markers) used for filtering. The samples include both native stacks and
14 // platform-independent "label stack" frames.
16 #ifndef BaseProfilerState_h
17 #define BaseProfilerState_h
19 // This header contains most functions that give information about the Base
20 // Profiler: Whether it is active or not, paused, the selected features, and
21 // some generic process and thread information.
22 // It is safe to include unconditionally, but uses of structs and functions must
23 // be guarded by `#ifdef MOZ_GECKO_PROFILER`.
25 #ifndef MOZ_GECKO_PROFILER
27 # define AUTO_PROFILER_STATS(name)
29 namespace mozilla {
31 namespace baseprofiler {
33 inline int profiler_main_thread_id() { return 0; }
35 } // namespace baseprofiler
36 } // namespace mozilla
38 #else // !MOZ_GECKO_PROFILER
40 # include "mozilla/Atomics.h"
41 # include "mozilla/Maybe.h"
43 # include <stdint.h>
44 # include <string>
46 namespace mozilla {
48 namespace baseprofiler {
50 // Uncomment the following line to display profiler runtime statistics at
51 // shutdown.
52 // # define PROFILER_RUNTIME_STATS
54 # ifdef PROFILER_RUNTIME_STATS
55 // This class gathers durations and displays some basic stats when destroyed.
56 // It is intended to be used as a static variable (see `AUTO_PROFILER_STATS`
57 // below), to display stats at the end of the program.
58 class StaticBaseProfilerStats {
59 public:
60 explicit StaticBaseProfilerStats(const char* aName) : mName(aName) {}
62 ~StaticBaseProfilerStats() {
63 // Using unsigned long long for computations and printfs.
64 using ULL = unsigned long long;
65 ULL n = static_cast<ULL>(mNumberDurations);
66 if (n != 0) {
67 ULL sumNs = static_cast<ULL>(mSumDurationsNs);
68 printf(
69 "[%d] Profiler stats `%s`: %llu ns / %llu = %llu ns, max %llu ns\n",
70 profiler_current_process_id(), mName, sumNs, n, sumNs / n,
71 static_cast<ULL>(mLongestDurationNs));
72 } else {
73 printf("[%d] Profiler stats `%s`: (nothing)\n",
74 profiler_current_process_id(), mName);
78 void AddDurationFrom(TimeStamp aStart) {
79 DurationNs duration = static_cast<DurationNs>(
80 (TimeStamp::NowUnfuzzed() - aStart).ToMicroseconds() * 1000 + 0.5);
81 mSumDurationsNs += duration;
82 ++mNumberDurations;
83 // Update mLongestDurationNs if this one is longer.
84 for (;;) {
85 DurationNs longest = mLongestDurationNs;
86 if (MOZ_LIKELY(longest >= duration)) {
87 // This duration is not the longest, nothing to do.
88 break;
90 if (MOZ_LIKELY(mLongestDurationNs.compareExchange(longest, duration))) {
91 // Successfully updated `mLongestDurationNs` with the new value.
92 break;
94 // Otherwise someone else just updated `mLongestDurationNs`, we need to
95 // try again by looping.
99 private:
100 using DurationNs = uint64_t;
101 using Count = uint32_t;
103 Atomic<DurationNs> mSumDurationsNs{0};
104 Atomic<DurationNs> mLongestDurationNs{0};
105 Atomic<Count> mNumberDurations{0};
106 const char* mName;
109 // RAII object that measure its scoped lifetime duration and reports it to a
110 // `StaticBaseProfilerStats`.
111 class MOZ_RAII AutoProfilerStats {
112 public:
113 explicit AutoProfilerStats(StaticBaseProfilerStats& aStats)
114 : mStats(aStats), mStart(TimeStamp::NowUnfuzzed()) {}
116 ~AutoProfilerStats() { mStats.AddDurationFrom(mStart); }
118 private:
119 StaticBaseProfilerStats& mStats;
120 TimeStamp mStart;
123 // Macro that should be used to collect basic statistics from measurements of
124 // block durations, from where this macro is, until the end of its enclosing
125 // scope. The name is used in the static variable name and when displaying stats
126 // at the end of the program; Another location could use the same name but their
127 // stats will not be combined, so use different name if these locations should
128 // be distinguished.
129 # define AUTO_PROFILER_STATS(name) \
130 static ::mozilla::baseprofiler::StaticBaseProfilerStats sStat##name( \
131 #name); \
132 ::mozilla::baseprofiler::AutoProfilerStats autoStat##name(sStat##name);
134 # else // PROFILER_RUNTIME_STATS
136 # define AUTO_PROFILER_STATS(name)
138 # endif // PROFILER_RUNTIME_STATS else
140 //---------------------------------------------------------------------------
141 // Profiler features
142 //---------------------------------------------------------------------------
144 // Higher-order macro containing all the feature info in one place. Define
145 // |MACRO| appropriately to extract the relevant parts. Note that the number
146 // values are used internally only and so can be changed without consequence.
147 // Any changes to this list should also be applied to the feature list in
148 // toolkit/components/extensions/schemas/geckoProfiler.json.
149 # define BASE_PROFILER_FOR_EACH_FEATURE(MACRO) \
150 MACRO(0, "java", Java, "Profile Java code, Android only") \
152 MACRO(1, "js", JS, \
153 "Get the JS engine to expose the JS stack to the profiler") \
155 /* The DevTools profiler doesn't want the native addresses. */ \
156 MACRO(2, "leaf", Leaf, "Include the C++ leaf node if not stackwalking") \
158 MACRO(3, "mainthreadio", MainThreadIO, "Add main thread file I/O") \
160 MACRO(4, "fileio", FileIO, \
161 "Add file I/O from all profiled threads, implies mainthreadio") \
163 MACRO(5, "fileioall", FileIOAll, \
164 "Add file I/O from all threads, implies fileio") \
166 MACRO(6, "noiostacks", NoIOStacks, \
167 "File I/O markers do not capture stacks, to reduce overhead") \
169 MACRO(7, "screenshots", Screenshots, \
170 "Take a snapshot of the window on every composition") \
172 MACRO(8, "seqstyle", SequentialStyle, \
173 "Disable parallel traversal in styling") \
175 MACRO(9, "stackwalk", StackWalk, \
176 "Walk the C++ stack, not available on all platforms") \
178 MACRO(10, "threads", Threads, "Profile the registered secondary threads") \
180 MACRO(11, "jstracer", JSTracer, "Enable tracing of the JavaScript engine") \
182 MACRO(12, "jsallocations", JSAllocations, \
183 "Have the JavaScript engine track allocations") \
185 MACRO(13, "nostacksampling", NoStackSampling, \
186 "Disable all stack sampling: Cancels \"js\", \"leaf\", " \
187 "\"stackwalk\" and labels") \
189 MACRO(14, "preferencereads", PreferenceReads, \
190 "Track when preferences are read") \
192 MACRO(15, "nativeallocations", NativeAllocations, \
193 "Collect the stacks from a smaller subset of all native " \
194 "allocations, biasing towards collecting larger allocations") \
196 MACRO(16, "ipcmessages", IPCMessages, \
197 "Have the IPC layer track cross-process messages") \
199 MACRO(17, "audiocallbacktracing", AudioCallbackTracing, \
200 "Audio callback tracing") \
202 MACRO(18, "cpu", CPUUtilization, "CPU utilization") \
204 MACRO(19, "notimerresolutionchange", NoTimerResolutionChange, \
205 "Do not adjust the timer resolution for fast sampling, so that " \
206 "other Firefox timers do not get affected")
208 struct ProfilerFeature {
209 # define DECLARE(n_, str_, Name_, desc_) \
210 static constexpr uint32_t Name_ = (1u << n_); \
211 static constexpr bool Has##Name_(uint32_t aFeatures) { \
212 return aFeatures & Name_; \
214 static constexpr void Set##Name_(uint32_t& aFeatures) { \
215 aFeatures |= Name_; \
217 static constexpr void Clear##Name_(uint32_t& aFeatures) { \
218 aFeatures &= ~Name_; \
221 // Define a bitfield constant, a getter, and two setters for each feature.
222 BASE_PROFILER_FOR_EACH_FEATURE(DECLARE)
224 # undef DECLARE
227 namespace detail {
229 // RacyFeatures is only defined in this header file so that its methods can
230 // be inlined into profiler_is_active(). Please do not use anything from the
231 // detail namespace outside the profiler.
233 // Within the profiler's code, the preferred way to check profiler activeness
234 // and features is via ActivePS(). However, that requires locking gPSMutex.
235 // There are some hot operations where absolute precision isn't required, so we
236 // duplicate the activeness/feature state in a lock-free manner in this class.
237 class RacyFeatures {
238 public:
239 MFBT_API static void SetActive(uint32_t aFeatures);
241 MFBT_API static void SetInactive();
243 MFBT_API static void SetPaused();
245 MFBT_API static void SetUnpaused();
247 MFBT_API static void SetSamplingPaused();
249 MFBT_API static void SetSamplingUnpaused();
251 MFBT_API static bool IsActive();
253 MFBT_API static bool IsActiveWithFeature(uint32_t aFeature);
255 // True if profiler is active, and not fully paused.
256 // Note that periodic sampling *could* be paused!
257 MFBT_API static bool IsActiveAndUnpaused();
259 // True if profiler is active, and sampling is not paused (though generic
260 // `SetPaused()` or specific `SetSamplingPaused()`).
261 MFBT_API static bool IsActiveAndSamplingUnpaused();
263 private:
264 static constexpr uint32_t Active = 1u << 31;
265 static constexpr uint32_t Paused = 1u << 30;
266 static constexpr uint32_t SamplingPaused = 1u << 29;
268 // Ensure Active/Paused don't overlap with any of the feature bits.
269 # define NO_OVERLAP(n_, str_, Name_, desc_) \
270 static_assert(ProfilerFeature::Name_ != SamplingPaused, \
271 "bad feature value");
273 BASE_PROFILER_FOR_EACH_FEATURE(NO_OVERLAP);
275 # undef NO_OVERLAP
277 // We combine the active bit with the feature bits so they can be read or
278 // written in a single atomic operation.
279 // TODO: Could this be MFBT_DATA for better inlining optimization?
280 static Atomic<uint32_t, MemoryOrdering::Relaxed> sActiveAndFeatures;
283 MFBT_API bool IsThreadBeingProfiled();
285 } // namespace detail
287 //---------------------------------------------------------------------------
288 // Get information from the profiler
289 //---------------------------------------------------------------------------
291 // Is the profiler active? Note: the return value of this function can become
292 // immediately out-of-date. E.g. the profile might be active but then
293 // profiler_stop() is called immediately afterward. One common and reasonable
294 // pattern of usage is the following:
296 // if (profiler_is_active()) {
297 // ExpensiveData expensiveData = CreateExpensiveData();
298 // PROFILER_OPERATION(expensiveData);
299 // }
301 // where PROFILER_OPERATION is a no-op if the profiler is inactive. In this
302 // case the profiler_is_active() check is just an optimization -- it prevents
303 // us calling CreateExpensiveData() unnecessarily in most cases, but the
304 // expensive data will end up being created but not used if another thread
305 // stops the profiler between the CreateExpensiveData() and PROFILER_OPERATION
306 // calls.
307 inline bool profiler_is_active() {
308 return baseprofiler::detail::RacyFeatures::IsActive();
311 // Same as profiler_is_active(), but with the same extra checks that determine
312 // if the profiler would currently store markers. So this should be used before
313 // doing some potentially-expensive work that's used in a marker. E.g.:
315 // if (profiler_can_accept_markers()) {
316 // BASE_PROFILER_MARKER(name, OTHER, SomeMarkerType, expensivePayload);
317 // }
318 inline bool profiler_can_accept_markers() {
319 return baseprofiler::detail::RacyFeatures::IsActiveAndUnpaused();
322 // Is the profiler active, and is the current thread being profiled?
323 // (Same caveats and recommented usage as profiler_is_active().)
324 inline bool profiler_thread_is_being_profiled() {
325 return profiler_is_active() && baseprofiler::detail::IsThreadBeingProfiled();
328 // Is the profiler active and paused? Returns false if the profiler is inactive.
329 MFBT_API bool profiler_is_paused();
331 // Is the profiler active and sampling is paused? Returns false if the profiler
332 // is inactive.
333 MFBT_API bool profiler_is_sampling_paused();
335 // Is the current thread sleeping?
336 MFBT_API bool profiler_thread_is_sleeping();
338 // Get all the features supported by the profiler that are accepted by
339 // profiler_start(). The result is the same whether the profiler is active or
340 // not.
341 MFBT_API uint32_t profiler_get_available_features();
343 // Check if a profiler feature (specified via the ProfilerFeature type) is
344 // active. Returns false if the profiler is inactive. Note: the return value
345 // can become immediately out-of-date, much like the return value of
346 // profiler_is_active().
347 MFBT_API bool profiler_feature_active(uint32_t aFeature);
349 // Get the current process's ID.
350 MFBT_API int profiler_current_process_id();
352 // Get the current thread's ID.
353 MFBT_API int profiler_current_thread_id();
355 // Statically initialized to 0, then set once from profiler_init(), which should
356 // be called from the main thread before any other use of the profiler.
357 extern MFBT_DATA int scProfilerMainThreadId;
359 inline int profiler_main_thread_id() { return scProfilerMainThreadId; }
361 inline bool profiler_is_main_thread() {
362 return profiler_current_thread_id() == profiler_main_thread_id();
365 // Returns true if any of the profiler mutexes are currently locked *on the
366 // current thread*. This may be used by re-entrant code that may call profiler
367 // functions while the same of a different profiler mutex is locked, which could
368 // deadlock.
369 bool profiler_is_locked_on_current_thread();
371 } // namespace baseprofiler
372 } // namespace mozilla
374 #endif // !MOZ_GECKO_PROFILER
376 #endif // BaseProfilerState_h