Line data Source code
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 : // 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.
11 : //
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 "pseudostacks".
15 :
16 : #ifndef GeckoProfiler_h
17 : #define GeckoProfiler_h
18 :
19 : #include <functional>
20 : #include <signal.h>
21 : #include <stdarg.h>
22 : #include <stdint.h>
23 : #include <stdlib.h>
24 :
25 : #include "mozilla/Assertions.h"
26 : #include "mozilla/Attributes.h"
27 : #include "mozilla/GuardObjects.h"
28 : #include "mozilla/Sprintf.h"
29 : #include "mozilla/ThreadLocal.h"
30 : #include "mozilla/UniquePtr.h"
31 : #include "js/TypeDecls.h"
32 : #include "js/ProfilingStack.h"
33 : #include "nscore.h"
34 :
35 : // Make sure that we can use std::min here without the Windows headers messing
36 : // with us.
37 : #ifdef min
38 : # undef min
39 : #endif
40 :
41 : class ProfilerBacktrace;
42 : class ProfilerMarkerPayload;
43 : class SpliceableJSONWriter;
44 :
45 : namespace mozilla {
46 : class MallocAllocPolicy;
47 : template <class T, size_t MinInlineCapacity, class AllocPolicy> class Vector;
48 : } // namespace mozilla
49 :
50 : // When the profiler is disabled functions declared with these macros are
51 : // static inline functions (with a trivial return value if they are non-void)
52 : // that will be optimized away during compilation.
53 : #ifdef MOZ_GECKO_PROFILER
54 : # define PROFILER_FUNC(decl, rv) decl;
55 : # define PROFILER_FUNC_VOID(decl) void decl;
56 : #else
57 : # define PROFILER_FUNC(decl, rv) static inline decl { return rv; }
58 : # define PROFILER_FUNC_VOID(decl) static inline void decl {}
59 : #endif
60 :
61 : //---------------------------------------------------------------------------
62 : // Profiler features
63 : //---------------------------------------------------------------------------
64 :
65 : // Higher-order macro containing all the feature info in one place. Define
66 : // |macro| appropriately to extract the relevant parts. Note that the number
67 : // values are used internally only and so can be changed without consequence.
68 : // Any changes to this list should also be applied to the feature list in
69 : // browser/components/extensions/schemas/geckoProfiler.json.
70 : #define PROFILER_FOR_EACH_FEATURE(macro) \
71 : /* Dump the display list with the textures. */ \
72 : macro(0, "displaylistdump", DisplayListDump) \
73 : \
74 : /* GPU Profiling (may not be supported by the GL). */ \
75 : macro(1, "gpu", GPU) \
76 : \
77 : /* Profile Java code (Android only). */ \
78 : macro(2, "java", Java) \
79 : \
80 : /* Get the JS engine to emit pseudostack entries in prologues/epilogues */ \
81 : macro(3, "js", JS) \
82 : \
83 : /* Dump the layer tree with the textures. */ \
84 : macro(4, "layersdump", LayersDump) \
85 : \
86 : /* Include the C++ leaf node if not stackwalking. */ \
87 : /* The DevTools profiler doesn't want the native addresses. */ \
88 : macro(5, "leaf", Leaf) \
89 : \
90 : /* Add main thread I/O to the profile. */ \
91 : macro(6, "mainthreadio", MainThreadIO) \
92 : \
93 : /* Add memory measurements (e.g. RSS). */ \
94 : macro(7, "memory", Memory) \
95 : \
96 : /* Do not include user-identifiable information. */ \
97 : macro(8, "privacy", Privacy) \
98 : \
99 : /* Restyle profiling. */ \
100 : macro(9, "restyle", Restyle) \
101 : \
102 : /* Walk the C++ stack. Not available on all platforms. */ \
103 : macro(10, "stackwalk", StackWalk) \
104 : \
105 : /* Start profiling with feature TaskTracer. */ \
106 : macro(11, "tasktracer", TaskTracer) \
107 : \
108 : /* Profile the registered secondary threads. */ \
109 : macro(12, "threads", Threads)
110 :
111 : struct ProfilerFeature
112 : {
113 : #define DECLARE(n_, str_, Name_) \
114 : static const uint32_t Name_ = (1u << n_); \
115 : static bool Has##Name_(uint32_t aFeatures) { return aFeatures & Name_; } \
116 : static void Set##Name_(uint32_t& aFeatures) { aFeatures |= Name_; } \
117 : static void Clear##Name_(uint32_t& aFeatures) { aFeatures &= ~Name_; }
118 :
119 : // Define a bitfield constant, a getter, and two setters for each feature.
120 0 : PROFILER_FOR_EACH_FEATURE(DECLARE)
121 :
122 : #undef DECLARE
123 : };
124 :
125 : //---------------------------------------------------------------------------
126 : // Start and stop the profiler
127 : //---------------------------------------------------------------------------
128 :
129 : #if !defined(ARCH_ARMV6)
130 : # define PROFILER_DEFAULT_ENTRIES 1000000
131 : #else
132 : # define PROFILER_DEFAULT_ENTRIES 100000
133 : #endif
134 :
135 : #define PROFILER_DEFAULT_INTERVAL 1
136 :
137 : // Initialize the profiler. If MOZ_PROFILER_STARTUP is set the profiler will
138 : // also be started. This call must happen before any other profiler calls
139 : // (except profiler_start(), which will call profiler_init() if it hasn't
140 : // already run).
141 : PROFILER_FUNC_VOID(profiler_init(void* stackTop))
142 :
143 : // Clean up the profiler module, stopping it if required. This function may
144 : // also save a shutdown profile if requested. No profiler calls should happen
145 : // after this point and all pseudo labels should have been popped.
146 : PROFILER_FUNC_VOID(profiler_shutdown())
147 :
148 : // Start the profiler -- initializing it first if necessary -- with the
149 : // selected options. Stops and restarts the profiler if it is already active.
150 : // After starting the profiler is "active". The samples will be recorded in a
151 : // circular buffer.
152 : // "aEntries" is the number of entries in the profiler's circular buffer.
153 : // "aInterval" the sampling interval, measured in millseconds.
154 : // "aFeatures" is the feature set. Features unsupported by this
155 : // platform/configuration are ignored.
156 : PROFILER_FUNC_VOID(profiler_start(int aEntries, double aInterval,
157 : uint32_t aFeatures,
158 : const char** aFilters, uint32_t aFilterCount))
159 :
160 : // Stop the profiler and discard the profile without saving it. A no-op if the
161 : // profiler is inactive. After stopping the profiler is "inactive".
162 : PROFILER_FUNC_VOID(profiler_stop())
163 :
164 : //---------------------------------------------------------------------------
165 : // Control the profiler
166 : //---------------------------------------------------------------------------
167 :
168 : // Register/unregister threads with the profiler. Both functions operate the
169 : // same whether the profiler is active or inactive.
170 : PROFILER_FUNC_VOID(profiler_register_thread(const char* name,
171 : void* guessStackTop))
172 : PROFILER_FUNC_VOID(profiler_unregister_thread())
173 :
174 : // Pause and resume the profiler. No-ops if the profiler is inactive. While
175 : // paused the profile will not take any samples and will not record any data
176 : // into its buffers. The profiler remains fully initialized in this state.
177 : // Timeline markers will still be stored. This feature will keep JavaScript
178 : // profiling enabled, thus allowing toggling the profiler without invalidating
179 : // the JIT.
180 : PROFILER_FUNC_VOID(profiler_pause())
181 : PROFILER_FUNC_VOID(profiler_resume())
182 :
183 : // These functions tell the profiler that a thread went to sleep so that we can
184 : // avoid sampling it while it's sleeping. Calling profiler_thread_sleep()
185 : // twice without an intervening profiler_thread_wake() is an error. All three
186 : // functions operate the same whether the profiler is active or inactive.
187 : PROFILER_FUNC_VOID(profiler_thread_sleep())
188 : PROFILER_FUNC_VOID(profiler_thread_wake())
189 :
190 : // Called by the JSRuntime's operation callback. This is used to start profiling
191 : // on auxiliary threads. Operates the same whether the profiler is active or
192 : // not.
193 : PROFILER_FUNC_VOID(profiler_js_interrupt_callback())
194 :
195 : // Set and clear the current thread's JSContext.
196 : PROFILER_FUNC_VOID(profiler_set_js_context(JSContext* aCx))
197 : PROFILER_FUNC_VOID(profiler_clear_js_context())
198 :
199 : //---------------------------------------------------------------------------
200 : // Get information from the profiler
201 : //---------------------------------------------------------------------------
202 :
203 : // Is the profiler active? Note: the return value of this function can become
204 : // immediately out-of-date. E.g. the profile might be active but then
205 : // profiler_stop() is called immediately afterward. One common and reasonable
206 : // pattern of usage is the following:
207 : //
208 : // if (profiler_is_active()) {
209 : // ExpensiveData expensiveData = CreateExpensiveData();
210 : // PROFILER_OPERATION(expensiveData);
211 : // }
212 : //
213 : // where PROFILER_OPERATION is a no-op if the profiler is inactive. In this
214 : // case the profiler_is_active() check is just an optimization -- it prevents
215 : // us calling CreateExpensiveData() unnecessarily in most cases, but the
216 : // expensive data will end up being created but not used if another thread
217 : // stops the profiler between the CreateExpensiveData() and PROFILER_OPERATION
218 : // calls.
219 : PROFILER_FUNC(bool profiler_is_active(), false)
220 :
221 : // Is the profiler active and paused? Returns false if the profiler is inactive.
222 : PROFILER_FUNC(bool profiler_is_paused(), false)
223 :
224 : // Is the current thread sleeping?
225 : PROFILER_FUNC(bool profiler_thread_is_sleeping(), false)
226 :
227 : // Get all the features supported by the profiler that are accepted by
228 : // profiler_start(). The result is the same whether the profiler is active or
229 : // not.
230 : PROFILER_FUNC(uint32_t profiler_get_available_features(), 0)
231 :
232 : // Check if a profiler feature (specified via the ProfilerFeature type) is
233 : // active. Returns false if the profiler is inactive. Note: the return value
234 : // can become immediately out-of-date, much like the return value of
235 : // profiler_is_active().
236 : PROFILER_FUNC(bool profiler_feature_active(uint32_t aFeature), false)
237 :
238 : // Get the params used to start the profiler. Returns 0 and an empty vector
239 : // (via outparams) if the profile is inactive. It's possible that the features
240 : // returned may be slightly different to those requested due to required
241 : // adjustments.
242 : PROFILER_FUNC_VOID(
243 : profiler_get_start_params(int* aEntrySize, double* aInterval,
244 : uint32_t* aFeatures,
245 : mozilla::Vector<const char*, 0,
246 : mozilla::MallocAllocPolicy>*
247 : aFilters))
248 :
249 : // The number of milliseconds since the process started. Operates the same
250 : // whether the profiler is active or inactive.
251 : PROFILER_FUNC(double profiler_time(), 0)
252 :
253 : // Get the current thread's ID.
254 : PROFILER_FUNC(int profiler_current_thread_id(), 0)
255 :
256 : // This is the function type of the callback passed to profiler_suspend_and_sample_thread.
257 : //
258 : // The callback is passed the following arguments:
259 : // void** aPCs The program counters for the target thread's stack.
260 : // size_t aCount The number of program counters in the aPCs array.
261 : // bool aIsMainThread Whether the target thread was the main thread.
262 : typedef void ProfilerStackCallback(void** aPCs, size_t aCount, bool aIsMainThread);
263 :
264 : // This method suspends the thread identified by aThreadId, optionally samples
265 : // it for its native stack, and then calls the callback.
266 : //
267 : // WARNING: The target thread is suspended during the callback. Do not try to
268 : // allocate or acquire any locks, or you could deadlock. The target thread will
269 : // have resumed by the time this function returns.
270 : PROFILER_FUNC_VOID(
271 : profiler_suspend_and_sample_thread(int aThreadId,
272 : const std::function<ProfilerStackCallback>& aCallback,
273 : bool aSampleNative = true))
274 :
275 : struct ProfilerBacktraceDestructor
276 : {
277 : #ifdef MOZ_GECKO_PROFILER
278 : void operator()(ProfilerBacktrace*);
279 : #else
280 : void operator()(ProfilerBacktrace*) {}
281 : #endif
282 : };
283 :
284 : using UniqueProfilerBacktrace =
285 : mozilla::UniquePtr<ProfilerBacktrace, ProfilerBacktraceDestructor>;
286 :
287 : // Immediately capture the current thread's call stack and return it. A no-op
288 : // if the profiler is inactive or in privacy mode.
289 : PROFILER_FUNC(UniqueProfilerBacktrace profiler_get_backtrace(), nullptr)
290 :
291 : PROFILER_FUNC_VOID(profiler_get_backtrace_noalloc(char* aOutput,
292 : size_t aOutputSize))
293 :
294 : // Get information about the current buffer status. A no-op when the profiler
295 : // is inactive. Do not call this function; call profiler_get_buffer_info()
296 : // instead.
297 : PROFILER_FUNC_VOID(profiler_get_buffer_info_helper(uint32_t* aCurrentPosition,
298 : uint32_t* aEntries,
299 : uint32_t* aGeneration))
300 :
301 : // Get information about the current buffer status. Returns (via outparams) the
302 : // current write position in the buffer, the total size of the buffer, and the
303 : // generation of the buffer. Returns zeroes if the profiler is inactive.
304 : //
305 : // This information may be useful to a user-interface displaying the current
306 : // status of the profiler, allowing the user to get a sense for how fast the
307 : // buffer is being written to, and how much data is visible.
308 0 : static inline void profiler_get_buffer_info(uint32_t* aCurrentPosition,
309 : uint32_t* aEntries,
310 : uint32_t* aGeneration)
311 : {
312 0 : *aCurrentPosition = 0;
313 0 : *aEntries = 0;
314 0 : *aGeneration = 0;
315 :
316 0 : profiler_get_buffer_info_helper(aCurrentPosition, aEntries, aGeneration);
317 0 : }
318 :
319 : // Get the current thread's PseudoStack.
320 : PROFILER_FUNC(PseudoStack* profiler_get_pseudo_stack(), nullptr)
321 :
322 : //---------------------------------------------------------------------------
323 : // Put profiling data into the profiler (labels and markers)
324 : //---------------------------------------------------------------------------
325 :
326 : #define PROFILER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line
327 : #define PROFILER_APPEND_LINE_NUMBER_EXPAND(id, line) \
328 : PROFILER_APPEND_LINE_NUMBER_PASTE(id, line)
329 : #define PROFILER_APPEND_LINE_NUMBER(id) \
330 : PROFILER_APPEND_LINE_NUMBER_EXPAND(id, __LINE__)
331 :
332 : // Insert an RAII object in this scope to enter a pseudo stack frame. Any
333 : // samples collected in this scope will contain this label in their pseudo
334 : // stack. The label argument must be a string literal. It is usually of the
335 : // form "ClassName::FunctionName". (Ideally we'd use the compiler to provide
336 : // that for us, but __func__ gives us the function name without the class
337 : // name.) If the label applies to only part of a function, you can qualify it
338 : // like this: "ClassName::FunctionName:PartName".
339 : //
340 : // Use AUTO_PROFILER_LABEL_DYNAMIC if you want to add additional / dynamic
341 : // information to the pseudo stack frame.
342 : #define AUTO_PROFILER_LABEL(label, category) \
343 : mozilla::AutoProfilerLabel \
344 : PROFILER_APPEND_LINE_NUMBER(profiler_raii)( \
345 : label, nullptr, __LINE__, js::ProfileEntry::Category::category)
346 :
347 : // Similar to AUTO_PROFILER_LABEL, but with an additional string. The inserted
348 : // RAII object stores the dynamicStr pointer in a field; it does not copy the
349 : // string. This means that the string you pass to this macro needs to live at
350 : // least until the end of the current scope.
351 : //
352 : // If the profiler samples the current thread and walks the pseudo stack while
353 : // this RAII object is on the stack, it will copy the supplied string into the
354 : // profile buffer. So there's one string copy operation, and it happens at
355 : // sample time.
356 : //
357 : // Compare this to the plain AUTO_PROFILER_LABEL macro, which only accepts
358 : // literal strings: When the pseudo stack frames generated by
359 : // AUTO_PROFILER_LABEL are sampled, no string copy needs to be made because the
360 : // profile buffer can just store the raw pointers to the literal strings.
361 : // Consequently, AUTO_PROFILER_LABEL frames take up considerably less space in
362 : // the profile buffer than AUTO_PROFILER_LABEL_DYNAMIC frames.
363 : #define AUTO_PROFILER_LABEL_DYNAMIC(label, category, dynamicStr) \
364 : mozilla::AutoProfilerLabel \
365 : PROFILER_APPEND_LINE_NUMBER(profiler_raii)( \
366 : label, dynamicStr, __LINE__, js::ProfileEntry::Category::category)
367 :
368 : // Insert a marker in the profile timeline. This is useful to delimit something
369 : // important happening such as the first paint. Unlike labels, which are only
370 : // recorded in the profile buffer if a sample is collected while the label is
371 : // on the pseudostack, markers will always be recorded in the profile buffer.
372 : // aMarkerName is copied, so the caller does not need to ensure it lives for a
373 : // certain length of time. A no-op if the profiler is inactive or in privacy
374 : // mode.
375 : PROFILER_FUNC_VOID(profiler_add_marker(const char* aMarkerName))
376 : PROFILER_FUNC_VOID(
377 : profiler_add_marker(const char* aMarkerName,
378 : mozilla::UniquePtr<ProfilerMarkerPayload> aPayload))
379 :
380 : enum TracingKind {
381 : TRACING_EVENT,
382 : TRACING_INTERVAL_START,
383 : TRACING_INTERVAL_END,
384 : };
385 :
386 :
387 : // Adds a tracing marker to the PseudoStack. A no-op if the profiler is
388 : // inactive or in privacy mode.
389 : PROFILER_FUNC_VOID(profiler_tracing(const char* aCategory,
390 : const char* aMarkerName,
391 : TracingKind aKind = TRACING_EVENT))
392 : PROFILER_FUNC_VOID(profiler_tracing(const char* aCategory,
393 : const char* aMarkerName,
394 : UniqueProfilerBacktrace aCause,
395 : TracingKind aKind = TRACING_EVENT))
396 :
397 : //---------------------------------------------------------------------------
398 : // Output profiles
399 : //---------------------------------------------------------------------------
400 :
401 : // Get the profile encoded as a JSON string. A no-op (returning nullptr) if the
402 : // profiler is inactive.
403 : PROFILER_FUNC(
404 : mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0),
405 : nullptr)
406 :
407 : // Write the profile for this process (excluding subprocesses) into aWriter.
408 : // Returns false if the profiler is inactive.
409 : PROFILER_FUNC(
410 : bool profiler_stream_json_for_this_process(SpliceableJSONWriter& aWriter,
411 : double aSinceTime = 0),
412 : false)
413 :
414 : // Get the profile and write it into a file. A no-op if the profile is
415 : // inactive.
416 : //
417 : // This function is 'extern "C"' so that it is easily callable from a debugger
418 : // in a build without debugging information (a workaround for
419 : // http://llvm.org/bugs/show_bug.cgi?id=22211).
420 : extern "C" {
421 : PROFILER_FUNC_VOID(profiler_save_profile_to_file(const char* aFilename))
422 : }
423 :
424 : //---------------------------------------------------------------------------
425 : // RAII classes
426 : //---------------------------------------------------------------------------
427 :
428 : namespace mozilla {
429 :
430 : class MOZ_RAII AutoProfilerInit
431 : {
432 : public:
433 3 : explicit AutoProfilerInit(void* stackTop
434 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
435 3 : {
436 3 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
437 3 : profiler_init(stackTop);
438 3 : }
439 :
440 0 : ~AutoProfilerInit() { profiler_shutdown(); }
441 :
442 : private:
443 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
444 : };
445 :
446 : // Convenience class to register and unregister a thread with the profiler.
447 : // Needs to be the first object on the stack of the thread.
448 : class MOZ_RAII AutoProfilerRegisterThread final
449 : {
450 : public:
451 15 : explicit AutoProfilerRegisterThread(const char* aName
452 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
453 15 : {
454 15 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
455 15 : profiler_register_thread(aName, this);
456 15 : }
457 :
458 0 : ~AutoProfilerRegisterThread() { profiler_unregister_thread(); }
459 :
460 : private:
461 : AutoProfilerRegisterThread(const AutoProfilerRegisterThread&) = delete;
462 : AutoProfilerRegisterThread& operator=(const AutoProfilerRegisterThread&) =
463 : delete;
464 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
465 : };
466 :
467 : class MOZ_RAII AutoProfilerThreadSleep
468 : {
469 : public:
470 1390 : explicit AutoProfilerThreadSleep(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
471 1390 : {
472 1390 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
473 1390 : profiler_thread_sleep();
474 1389 : }
475 :
476 1385 : ~AutoProfilerThreadSleep() { profiler_thread_wake(); }
477 :
478 : private:
479 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
480 : };
481 :
482 : // Temporarily wake up the profiling of a thread while servicing events such as
483 : // Asynchronous Procedure Calls (APCs).
484 : class MOZ_RAII AutoProfilerThreadWake
485 : {
486 : public:
487 : explicit AutoProfilerThreadWake(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
488 : : mIssuedWake(profiler_thread_is_sleeping())
489 : {
490 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
491 : if (mIssuedWake) {
492 : profiler_thread_wake();
493 : }
494 : }
495 :
496 : ~AutoProfilerThreadWake()
497 : {
498 : if (mIssuedWake) {
499 : MOZ_ASSERT(!profiler_thread_is_sleeping());
500 : profiler_thread_sleep();
501 : }
502 : }
503 :
504 : private:
505 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
506 : bool mIssuedWake;
507 : };
508 :
509 : // This class creates a non-owning PseudoStack reference. Objects of this class
510 : // are stack-allocated, and so exist within a thread, and are thus bounded by
511 : // the lifetime of the thread, which ensures that the references held can't be
512 : // used after the PseudoStack is destroyed.
513 : class MOZ_RAII AutoProfilerLabel
514 : {
515 : public:
516 12255 : AutoProfilerLabel(const char* aLabel, const char* aDynamicString,
517 : uint32_t aLine, js::ProfileEntry::Category aCategory
518 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
519 12255 : {
520 12255 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
521 :
522 : // This function runs both on and off the main thread.
523 :
524 : #ifdef MOZ_GECKO_PROFILER
525 12256 : mPseudoStack = sPseudoStack.get();
526 12256 : if (mPseudoStack) {
527 12256 : mPseudoStack->pushCppFrame(aLabel, aDynamicString, this, aLine,
528 12256 : js::ProfileEntry::Kind::CPP_NORMAL, aCategory);
529 : }
530 : #endif
531 12258 : }
532 :
533 12245 : ~AutoProfilerLabel()
534 12246 : {
535 : // This function runs both on and off the main thread.
536 :
537 : #ifdef MOZ_GECKO_PROFILER
538 12245 : if (mPseudoStack) {
539 12245 : mPseudoStack->pop();
540 : }
541 : #endif
542 12246 : }
543 :
544 : private:
545 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
546 :
547 : #ifdef MOZ_GECKO_PROFILER
548 : // We save a PseudoStack pointer in the ctor so we don't have to redo the TLS
549 : // lookup in the dtor.
550 : PseudoStack* mPseudoStack;
551 :
552 : public:
553 : // See the comment on the definition in platform.cpp for details about this.
554 : static MOZ_THREAD_LOCAL(PseudoStack*) sPseudoStack;
555 : #endif
556 : };
557 :
558 : class MOZ_RAII AutoProfilerTracing
559 : {
560 : public:
561 41 : AutoProfilerTracing(const char* aCategory, const char* aMarkerName,
562 : UniqueProfilerBacktrace aBacktrace
563 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
564 41 : : mCategory(aCategory)
565 41 : , mMarkerName(aMarkerName)
566 : {
567 41 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
568 82 : profiler_tracing(mCategory, mMarkerName, Move(aBacktrace),
569 41 : TRACING_INTERVAL_START);
570 41 : }
571 :
572 297 : AutoProfilerTracing(const char* aCategory, const char* aMarkerName
573 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
574 297 : : mCategory(aCategory)
575 297 : , mMarkerName(aMarkerName)
576 : {
577 297 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
578 297 : profiler_tracing(mCategory, mMarkerName, TRACING_INTERVAL_START);
579 297 : }
580 :
581 338 : ~AutoProfilerTracing()
582 338 : {
583 338 : profiler_tracing(mCategory, mMarkerName, TRACING_INTERVAL_END);
584 338 : }
585 :
586 : protected:
587 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
588 : const char* mCategory;
589 : const char* mMarkerName;
590 : };
591 :
592 : } // namespace mozilla
593 :
594 : #endif // GeckoProfiler_h
|