Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/GeckoProfiler.h
Line
Count
Source (jump to first uncovered line)
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 "label stack" frames.
15
16
#ifndef GeckoProfiler_h
17
#define GeckoProfiler_h
18
19
#ifndef MOZ_GECKO_PROFILER
20
21
// This file can be #included unconditionally. However, everything within this
22
// file must be guarded by a #ifdef MOZ_GECKO_PROFILER, *except* for the
23
// following macros, which encapsulate the most common operations and thus
24
// avoid the need for many #ifdefs.
25
26
#define AUTO_PROFILER_INIT
27
28
#define PROFILER_REGISTER_THREAD(name)
29
#define PROFILER_UNREGISTER_THREAD()
30
#define AUTO_PROFILER_REGISTER_THREAD(name)
31
32
#define AUTO_PROFILER_THREAD_SLEEP
33
#define AUTO_PROFILER_THREAD_WAKE
34
35
#define PROFILER_JS_INTERRUPT_CALLBACK()
36
37
#define PROFILER_SET_JS_CONTEXT(cx)
38
#define PROFILER_CLEAR_JS_CONTEXT()
39
40
#define AUTO_PROFILER_LABEL(label, category)
41
#define AUTO_PROFILER_LABEL_DYNAMIC_CSTR(label, category, cStr)
42
#define AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(label, category, nsCStr)
43
#define AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(label, category, nsStr)
44
#define AUTO_PROFILER_LABEL_FAST(label, category, ctx)
45
46
#define PROFILER_ADD_MARKER(markerName)
47
#define PROFILER_ADD_NETWORK_MARKER(uri, pri, channel, type, start, end, count, timings, redirect)
48
49
#define PROFILER_TRACING(category, markerName, kind)
50
#define AUTO_PROFILER_TRACING(category, markerName)
51
52
#else // !MOZ_GECKO_PROFILER
53
54
#include <functional>
55
#include <signal.h>
56
#include <stdarg.h>
57
#include <stdint.h>
58
#include <stdlib.h>
59
60
#include "mozilla/Assertions.h"
61
#include "mozilla/Attributes.h"
62
#include "mozilla/GuardObjects.h"
63
#include "mozilla/Maybe.h"
64
#include "mozilla/Sprintf.h"
65
#include "mozilla/ThreadLocal.h"
66
#include "mozilla/TimeStamp.h"
67
#include "mozilla/UniquePtr.h"
68
#include "mozilla/net/TimingStruct.h"
69
#include "js/ProfilingStack.h"
70
#include "js/RootingAPI.h"
71
#include "js/TypeDecls.h"
72
#include "nscore.h"
73
#include "nsIURI.h"
74
75
// Make sure that we can use std::min here without the Windows headers messing
76
// with us.
77
#ifdef min
78
# undef min
79
#endif
80
81
class ProfilerBacktrace;
82
class ProfilerMarkerPayload;
83
class SpliceableJSONWriter;
84
85
namespace mozilla {
86
class MallocAllocPolicy;
87
template <class T, size_t MinInlineCapacity, class AllocPolicy> class Vector;
88
class TimeStamp;
89
} // namespace mozilla
90
91
// Macros used by the AUTO_PROFILER_* macros below.
92
272
#define PROFILER_RAII_PASTE(id, line) id ## line
93
272
#define PROFILER_RAII_EXPAND(id, line) PROFILER_RAII_PASTE(id, line)
94
272
#define PROFILER_RAII PROFILER_RAII_EXPAND(raiiObject, __LINE__)
95
96
//---------------------------------------------------------------------------
97
// Profiler features
98
//---------------------------------------------------------------------------
99
100
// Higher-order macro containing all the feature info in one place. Define
101
// |macro| appropriately to extract the relevant parts. Note that the number
102
// values are used internally only and so can be changed without consequence.
103
// Any changes to this list should also be applied to the feature list in
104
// browser/components/extensions/schemas/geckoProfiler.json.
105
#define PROFILER_FOR_EACH_FEATURE(macro) \
106
  /* Profile Java code (Android only). */ \
107
0
  macro(0, "java", Java) \
108
0
  \
109
0
  /* Get the JS engine to expose the JS stack to the profiler */ \
110
0
  macro(1, "js", JS) \
111
0
  \
112
0
  /* Include the C++ leaf node if not stackwalking. */ \
113
0
  /* The DevTools profiler doesn't want the native addresses. */ \
114
0
  macro(2, "leaf", Leaf) \
115
0
  \
116
0
  /* Add main thread I/O to the profile. */ \
117
0
  macro(3, "mainthreadio", MainThreadIO) \
118
0
  \
119
0
  /* Add memory measurements (e.g. RSS). */ \
120
0
  macro(4, "memory", Memory) \
121
0
  \
122
0
  /* Do not include user-identifiable information. */ \
123
0
  macro(5, "privacy", Privacy) \
124
0
  \
125
0
  /* Collect thread responsiveness information. */ \
126
0
  macro(6, "responsiveness", Responsiveness) \
127
0
  \
128
0
  /* Take a snapshot of the window on every composition. */ \
129
0
  macro(7, "screenshots", Screenshots) \
130
0
  \
131
0
  /* Disable parallel traversal in styling. */ \
132
0
  macro(8, "seqstyle", SequentialStyle) \
133
0
  \
134
0
  /* Walk the C++ stack. Not available on all platforms. */ \
135
0
  macro(9, "stackwalk", StackWalk) \
136
0
  \
137
0
  /* Start profiling with feature TaskTracer. */ \
138
0
  macro(10, "tasktracer", TaskTracer) \
139
0
  \
140
0
  /* Profile the registered secondary threads. */ \
141
0
  macro(11, "threads", Threads) \
142
0
  \
143
0
  /* Have the JavaScript engine track JIT optimizations. */ \
144
0
  macro(12, "trackopts", TrackOptimizations)
145
146
struct ProfilerFeature
147
{
148
  #define DECLARE(n_, str_, Name_) \
149
    static const uint32_t Name_ = (1u << n_); \
150
0
    static bool Has##Name_(uint32_t aFeatures) { return aFeatures & Name_; } \
Unexecuted instantiation: ProfilerFeature::HasJava(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasJS(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasLeaf(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasMainThreadIO(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasMemory(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasPrivacy(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasResponsiveness(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasScreenshots(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasSequentialStyle(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasStackWalk(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasTaskTracer(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasThreads(unsigned int)
Unexecuted instantiation: ProfilerFeature::HasTrackOptimizations(unsigned int)
151
0
    static void Set##Name_(uint32_t& aFeatures) { aFeatures |= Name_; } \
Unexecuted instantiation: ProfilerFeature::SetJava(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetJS(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetLeaf(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetMainThreadIO(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetMemory(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetPrivacy(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetResponsiveness(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetScreenshots(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetSequentialStyle(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetStackWalk(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetTaskTracer(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetThreads(unsigned int&)
Unexecuted instantiation: ProfilerFeature::SetTrackOptimizations(unsigned int&)
152
0
    static void Clear##Name_(uint32_t& aFeatures) { aFeatures &= ~Name_; }
Unexecuted instantiation: ProfilerFeature::ClearJava(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearJS(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearLeaf(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearMainThreadIO(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearMemory(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearPrivacy(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearResponsiveness(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearScreenshots(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearSequentialStyle(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearStackWalk(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearTaskTracer(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearThreads(unsigned int&)
Unexecuted instantiation: ProfilerFeature::ClearTrackOptimizations(unsigned int&)
153
154
  // Define a bitfield constant, a getter, and two setters for each feature.
155
  PROFILER_FOR_EACH_FEATURE(DECLARE)
156
157
  #undef DECLARE
158
};
159
160
namespace mozilla {
161
namespace profiler {
162
namespace detail {
163
164
// RacyFeatures is only defined in this header file so that its methods can
165
// be inlined into profiler_is_active(). Please do not use anything from the
166
// detail namespace outside the profiler.
167
168
// Within the profiler's code, the preferred way to check profiler activeness
169
// and features is via ActivePS(). However, that requires locking gPSMutex.
170
// There are some hot operations where absolute precision isn't required, so we
171
// duplicate the activeness/feature state in a lock-free manner in this class.
172
class RacyFeatures
173
{
174
public:
175
  static void SetActive(uint32_t aFeatures)
176
0
  {
177
0
    sActiveAndFeatures = Active | aFeatures;
178
0
  }
179
180
0
  static void SetInactive() { sActiveAndFeatures = 0; }
181
182
352
  static bool IsActive() { return uint32_t(sActiveAndFeatures) & Active; }
183
184
  static bool IsActiveWithFeature(uint32_t aFeature)
185
0
  {
186
0
    uint32_t af = sActiveAndFeatures;  // copy it first
187
0
    return (af & Active) && (af & aFeature);
188
0
  }
189
190
  static bool IsActiveWithoutPrivacy()
191
3
  {
192
3
    uint32_t af = sActiveAndFeatures;  // copy it first
193
3
    return (af & Active) && !(af & ProfilerFeature::Privacy);
194
3
  }
195
196
private:
197
  static const uint32_t Active = 1u << 31;
198
199
  // Ensure Active doesn't overlap with any of the feature bits.
200
  #define NO_OVERLAP(n_, str_, Name_) \
201
    static_assert(ProfilerFeature::Name_ != Active, "bad Active value");
202
203
  PROFILER_FOR_EACH_FEATURE(NO_OVERLAP);
204
205
  #undef NO_OVERLAP
206
207
  // We combine the active bit with the feature bits so they can be read or
208
  // written in a single atomic operation. Accesses to this atomic are not
209
  // recorded by web replay as they may occur at non-deterministic points.
210
  static mozilla::Atomic<uint32_t, mozilla::MemoryOrdering::Relaxed,
211
                         recordreplay::Behavior::DontPreserve> sActiveAndFeatures;
212
};
213
214
} // namespace detail
215
} // namespace profiler
216
} // namespace mozilla
217
218
//---------------------------------------------------------------------------
219
// Start and stop the profiler
220
//---------------------------------------------------------------------------
221
222
#if !defined(ARCH_ARMV6)
223
3
# define PROFILER_DEFAULT_ENTRIES 1000000
224
#else
225
# define PROFILER_DEFAULT_ENTRIES 100000
226
#endif
227
228
3
#define PROFILER_DEFAULT_INTERVAL 1
229
230
// Initialize the profiler. If MOZ_PROFILER_STARTUP is set the profiler will
231
// also be started. This call must happen before any other profiler calls
232
// (except profiler_start(), which will call profiler_init() if it hasn't
233
// already run).
234
void profiler_init(void* stackTop);
235
236
#define AUTO_PROFILER_INIT \
237
3
  mozilla::AutoProfilerInit PROFILER_RAII
238
239
// Clean up the profiler module, stopping it if required. This function may
240
// also save a shutdown profile if requested. No profiler calls should happen
241
// after this point and all profiling stack labels should have been popped.
242
void profiler_shutdown();
243
244
// Start the profiler -- initializing it first if necessary -- with the
245
// selected options. Stops and restarts the profiler if it is already active.
246
// After starting the profiler is "active". The samples will be recorded in a
247
// circular buffer.
248
//   "aEntries" is the number of entries in the profiler's circular buffer.
249
//   "aInterval" the sampling interval, measured in millseconds.
250
//   "aFeatures" is the feature set. Features unsupported by this
251
//               platform/configuration are ignored.
252
//   "aFilters" is the list of thread filters. Threads that do not match any
253
//              of the filters are not profiled. A filter matches a thread if
254
//              (a) the thread name contains the filter as a case-insensitive
255
//                  substring, or
256
//              (b) the filter is of the form "pid:<n>" where n is the process
257
//                  id of the process that the thread is running in.
258
void profiler_start(uint32_t aEntries, double aInterval, uint32_t aFeatures,
259
                    const char** aFilters, uint32_t aFilterCount);
260
261
// Stop the profiler and discard the profile without saving it. A no-op if the
262
// profiler is inactive. After stopping the profiler is "inactive".
263
void profiler_stop();
264
265
// If the profiler is inactive, start it. If it's already active, restart it if
266
// the requested settings differ from the current settings. Both the check and
267
// the state change are performed while the profiler state is locked.
268
// The only difference to profiler_start is that the current buffer contents are
269
// not discarded if the profiler is already running with the requested settings.
270
void profiler_ensure_started(uint32_t aEntries, double aInterval,
271
                             uint32_t aFeatures, const char** aFilters,
272
                             uint32_t aFilterCount);
273
274
//---------------------------------------------------------------------------
275
// Control the profiler
276
//---------------------------------------------------------------------------
277
278
// Register/unregister threads with the profiler. Both functions operate the
279
// same whether the profiler is active or inactive.
280
#define PROFILER_REGISTER_THREAD(name) \
281
13
  do { char stackTop; profiler_register_thread(name, &stackTop); } while (0)
282
#define PROFILER_UNREGISTER_THREAD() \
283
13
  profiler_unregister_thread()
284
ProfilingStack* profiler_register_thread(const char* name, void* guessStackTop);
285
void profiler_unregister_thread();
286
287
// Register and unregister a thread within a scope.
288
#define AUTO_PROFILER_REGISTER_THREAD(name) \
289
9
  mozilla::AutoProfilerRegisterThread PROFILER_RAII(name)
290
291
// Pause and resume the profiler. No-ops if the profiler is inactive. While
292
// paused the profile will not take any samples and will not record any data
293
// into its buffers. The profiler remains fully initialized in this state.
294
// Timeline markers will still be stored. This feature will keep JavaScript
295
// profiling enabled, thus allowing toggling the profiler without invalidating
296
// the JIT.
297
void profiler_pause();
298
void profiler_resume();
299
300
// These functions tell the profiler that a thread went to sleep so that we can
301
// avoid sampling it while it's sleeping. Calling profiler_thread_sleep()
302
// twice without an intervening profiler_thread_wake() is an error. All three
303
// functions operate the same whether the profiler is active or inactive.
304
void profiler_thread_sleep();
305
void profiler_thread_wake();
306
307
// Mark a thread as asleep/awake within a scope.
308
#define AUTO_PROFILER_THREAD_SLEEP \
309
210
  mozilla::AutoProfilerThreadSleep PROFILER_RAII
310
#define AUTO_PROFILER_THREAD_WAKE \
311
  mozilla::AutoProfilerThreadWake PROFILER_RAII
312
313
// Called by the JSRuntime's operation callback. This is used to start profiling
314
// on auxiliary threads. Operates the same whether the profiler is active or
315
// not.
316
0
#define PROFILER_JS_INTERRUPT_CALLBACK() profiler_js_interrupt_callback()
317
void profiler_js_interrupt_callback();
318
319
// Set and clear the current thread's JSContext.
320
3
#define PROFILER_SET_JS_CONTEXT(cx) profiler_set_js_context(cx)
321
0
#define PROFILER_CLEAR_JS_CONTEXT() profiler_clear_js_context()
322
void profiler_set_js_context(JSContext* aCx);
323
void profiler_clear_js_context();
324
325
//---------------------------------------------------------------------------
326
// Get information from the profiler
327
//---------------------------------------------------------------------------
328
329
// Is the profiler active? Note: the return value of this function can become
330
// immediately out-of-date. E.g. the profile might be active but then
331
// profiler_stop() is called immediately afterward. One common and reasonable
332
// pattern of usage is the following:
333
//
334
//   if (profiler_is_active()) {
335
//     ExpensiveData expensiveData = CreateExpensiveData();
336
//     PROFILER_OPERATION(expensiveData);
337
//   }
338
//
339
// where PROFILER_OPERATION is a no-op if the profiler is inactive. In this
340
// case the profiler_is_active() check is just an optimization -- it prevents
341
// us calling CreateExpensiveData() unnecessarily in most cases, but the
342
// expensive data will end up being created but not used if another thread
343
// stops the profiler between the CreateExpensiveData() and PROFILER_OPERATION
344
// calls.
345
inline bool profiler_is_active()
346
352
{
347
352
  return mozilla::profiler::detail::RacyFeatures::IsActive();
348
352
}
349
350
// Is the profiler active and paused? Returns false if the profiler is inactive.
351
bool profiler_is_paused();
352
353
// Is the current thread sleeping?
354
bool profiler_thread_is_sleeping();
355
356
// Get all the features supported by the profiler that are accepted by
357
// profiler_start(). The result is the same whether the profiler is active or
358
// not.
359
uint32_t profiler_get_available_features();
360
361
// Check if a profiler feature (specified via the ProfilerFeature type) is
362
// active. Returns false if the profiler is inactive. Note: the return value
363
// can become immediately out-of-date, much like the return value of
364
// profiler_is_active().
365
bool profiler_feature_active(uint32_t aFeature);
366
367
// Get the params used to start the profiler. Returns 0 and an empty vector
368
// (via outparams) if the profile is inactive. It's possible that the features
369
// returned may be slightly different to those requested due to required
370
// adjustments.
371
void profiler_get_start_params(int* aEntrySize, double* aInterval,
372
                               uint32_t* aFeatures,
373
                               mozilla::Vector<const char*, 0,
374
                                               mozilla::MallocAllocPolicy>*
375
                                 aFilters);
376
377
// The number of milliseconds since the process started. Operates the same
378
// whether the profiler is active or inactive.
379
double profiler_time();
380
381
// Get the current thread's ID.
382
int profiler_current_thread_id();
383
384
// An object of this class is passed to profiler_suspend_and_sample_thread().
385
// For each stack frame, one of the Collect methods will be called.
386
class ProfilerStackCollector
387
{
388
public:
389
  // Some collectors need to worry about possibly overwriting previous
390
  // generations of data. If that's not an issue, this can return Nothing,
391
  // which is the default behaviour.
392
0
  virtual mozilla::Maybe<uint64_t> SamplePositionInBuffer() { return mozilla::Nothing(); }
393
0
  virtual mozilla::Maybe<uint64_t> BufferRangeStart() { return mozilla::Nothing(); }
394
395
  // This method will be called once if the thread being suspended is the main
396
  // thread. Default behaviour is to do nothing.
397
0
  virtual void SetIsMainThread() {}
398
399
  // WARNING: The target thread is suspended when the Collect methods are
400
  // called. Do not try to allocate or acquire any locks, or you could
401
  // deadlock. The target thread will have resumed by the time this function
402
  // returns.
403
404
  virtual void CollectNativeLeafAddr(void* aAddr) = 0;
405
406
  virtual void CollectJitReturnAddr(void* aAddr) = 0;
407
408
  virtual void CollectWasmFrame(const char* aLabel) = 0;
409
410
  virtual void CollectProfilingStackFrame(const js::ProfilingStackFrame& aFrame) = 0;
411
};
412
413
// This method suspends the thread identified by aThreadId, samples its
414
// profiling stack, JS stack, and (optionally) native stack, passing the collected
415
// frames into aCollector. aFeatures dictates which compiler features are used.
416
// |Privacy| and |Leaf| are the only relevant ones.
417
void profiler_suspend_and_sample_thread(int aThreadId, uint32_t aFeatures,
418
                                        ProfilerStackCollector& aCollector,
419
                                        bool aSampleNative = true);
420
421
struct ProfilerBacktraceDestructor
422
{
423
  void operator()(ProfilerBacktrace*);
424
};
425
426
using UniqueProfilerBacktrace =
427
  mozilla::UniquePtr<ProfilerBacktrace, ProfilerBacktraceDestructor>;
428
429
// Immediately capture the current thread's call stack and return it. A no-op
430
// if the profiler is inactive or in privacy mode.
431
UniqueProfilerBacktrace profiler_get_backtrace();
432
433
struct ProfilerBufferInfo
434
{
435
  uint64_t mRangeStart;
436
  uint64_t mRangeEnd;
437
  uint32_t mEntryCount;
438
};
439
440
// Get information about the current buffer status.
441
// Returns Nothing() if the profiler is inactive.
442
//
443
// This information may be useful to a user-interface displaying the current
444
// status of the profiler, allowing the user to get a sense for how fast the
445
// buffer is being written to, and how much data is visible.
446
mozilla::Maybe<ProfilerBufferInfo> profiler_get_buffer_info();
447
448
//---------------------------------------------------------------------------
449
// Put profiling data into the profiler (labels and markers)
450
//---------------------------------------------------------------------------
451
452
// Insert an RAII object in this scope to enter a label stack frame. Any
453
// samples collected in this scope will contain this label in their stack.
454
// The label argument must be a static C string. It is usually of the
455
// form "ClassName::FunctionName". (Ideally we'd use the compiler to provide
456
// that for us, but __func__ gives us the function name without the class
457
// name.) If the label applies to only part of a function, you can qualify it
458
// like this: "ClassName::FunctionName:PartName".
459
//
460
// Use AUTO_PROFILER_LABEL_DYNAMIC_* if you want to add additional / dynamic
461
// information to the label stack frame.
462
#define AUTO_PROFILER_LABEL(label, category) \
463
40
  mozilla::AutoProfilerLabel PROFILER_RAII(label, nullptr, __LINE__, \
464
40
                                           js::ProfilingStackFrame::Category::category)
465
466
// Similar to AUTO_PROFILER_LABEL, but with an additional string. The inserted
467
// RAII object stores the cStr pointer in a field; it does not copy the string.
468
//
469
// WARNING: This means that the string you pass to this macro needs to live at
470
// least until the end of the current scope. Be careful using this macro with
471
// ns[C]String; the other AUTO_PROFILER_LABEL_DYNAMIC_* macros below are
472
// preferred because they avoid this problem.
473
//
474
// If the profiler samples the current thread and walks the label stack while
475
// this RAII object is on the stack, it will copy the supplied string into the
476
// profile buffer. So there's one string copy operation, and it happens at
477
// sample time.
478
//
479
// Compare this to the plain AUTO_PROFILER_LABEL macro, which only accepts
480
// literal strings: When the label stack frames generated by
481
// AUTO_PROFILER_LABEL are sampled, no string copy needs to be made because the
482
// profile buffer can just store the raw pointers to the literal strings.
483
// Consequently, AUTO_PROFILER_LABEL frames take up considerably less space in
484
// the profile buffer than AUTO_PROFILER_LABEL_DYNAMIC_* frames.
485
#define AUTO_PROFILER_LABEL_DYNAMIC_CSTR(label, category, cStr) \
486
12
  mozilla::AutoProfilerLabel \
487
12
    PROFILER_RAII(label, cStr, __LINE__, js::ProfilingStackFrame::Category::category)
488
489
// Similar to AUTO_PROFILER_LABEL_DYNAMIC_CSTR, but takes an nsACString.
490
//
491
// Note: The use of the Maybe<>s ensures the scopes for the dynamic string and
492
// the AutoProfilerLabel are appropriate, while also not incurring the runtime
493
// cost of the string assignment unless the profiler is active. Therefore,
494
// unlike AUTO_PROFILER_LABEL and AUTO_PROFILER_LABEL_DYNAMIC_CSTR, this macro
495
// doesn't push/pop a label when the profiler is inactive.
496
#define AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(label, category, nsCStr) \
497
18
  mozilla::Maybe<nsAutoCString> autoCStr; \
498
18
  mozilla::Maybe<AutoProfilerLabel> raiiObjectNsCString; \
499
18
  if (profiler_is_active()) { \
500
0
    autoCStr.emplace(nsCStr); \
501
0
    raiiObjectNsCString.emplace(label, autoCStr->get(), __LINE__, \
502
0
                                js::ProfilingStackFrame::Category::category); \
503
0
  }
504
505
// Similar to AUTO_PROFILER_LABEL_DYNAMIC_CSTR, but takes an nsString that is
506
// is lossily converted to an ASCII string.
507
//
508
// Note: The use of the Maybe<>s ensures the scopes for the converted dynamic
509
// string and the AutoProfilerLabel are appropriate, while also not incurring
510
// the runtime cost of the string conversion unless the profiler is active.
511
// Therefore, unlike AUTO_PROFILER_LABEL and AUTO_PROFILER_LABEL_DYNAMIC_CSTR,
512
// this macro doesn't push/pop a label when the profiler is inactive.
513
#define AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(label, category, nsStr) \
514
0
  mozilla::Maybe<NS_LossyConvertUTF16toASCII> asciiStr; \
515
0
  mozilla::Maybe<AutoProfilerLabel> raiiObjectLossyNsString; \
516
0
  if (profiler_is_active()) { \
517
0
    asciiStr.emplace(nsStr); \
518
0
    raiiObjectLossyNsString.emplace(label, asciiStr->get(), __LINE__, \
519
0
                                    js::ProfilingStackFrame::Category::category); \
520
0
  }
521
522
// Similar to AUTO_PROFILER_LABEL, but accepting a JSContext* parameter, and a
523
// no-op if the profiler is disabled.
524
// Used to annotate functions for which overhead in the range of nanoseconds is
525
// noticeable. It avoids overhead from the TLS lookup because it can get the
526
// ProfilingStack from the JS context, and avoids almost all overhead in the case
527
// where the profiler is disabled.
528
#define AUTO_PROFILER_LABEL_FAST(label, category, ctx) \
529
14
  mozilla::AutoProfilerLabel PROFILER_RAII(ctx, label, nullptr, __LINE__, \
530
14
                                           js::ProfilingStackFrame::Category::category)
531
532
// Insert a marker in the profile timeline. This is useful to delimit something
533
// important happening such as the first paint. Unlike labels, which are only
534
// recorded in the profile buffer if a sample is collected while the label is
535
// on the label stack, markers will always be recorded in the profile buffer.
536
// aMarkerName is copied, so the caller does not need to ensure it lives for a
537
// certain length of time. A no-op if the profiler is inactive or in privacy
538
// mode.
539
#define PROFILER_ADD_MARKER(markerName) \
540
3
  profiler_add_marker(markerName)
541
void profiler_add_marker(const char* aMarkerName);
542
void profiler_add_marker(const char* aMarkerName,
543
                         mozilla::UniquePtr<ProfilerMarkerPayload> aPayload);
544
545
// Insert a marker in the profile timeline for a specified thread.
546
void profiler_add_marker_for_thread(int aThreadId,
547
                                    const char* aMarkerName,
548
                                    mozilla::UniquePtr<ProfilerMarkerPayload> aPayload);
549
550
enum class NetworkLoadType {
551
  LOAD_START,
552
  LOAD_STOP,
553
  LOAD_REDIRECT
554
};
555
556
#define PROFILER_ADD_NETWORK_MARKER(uri, pri, channel, type, start, end, count, timings, redirect) \
557
0
  profiler_add_network_marker(uri, pri, channel, type, start, end, count, timings, redirect)
558
559
void profiler_add_network_marker(nsIURI* aURI,
560
                                 int32_t aPriority,
561
                                 uint64_t aChannelId,
562
                                 NetworkLoadType aType,
563
                                 mozilla::TimeStamp aStart,
564
                                 mozilla::TimeStamp aEnd,
565
                                 int64_t aCount,
566
                                 const mozilla::net::TimingStruct* aTimings = nullptr,
567
                                 nsIURI* aRedirectURI = nullptr);
568
569
570
enum TracingKind {
571
  TRACING_EVENT,
572
  TRACING_INTERVAL_START,
573
  TRACING_INTERVAL_END,
574
};
575
576
// Adds a tracing marker to the profile. A no-op if the profiler is inactive or
577
// in privacy mode.
578
#define PROFILER_TRACING(category, markerName, kind) \
579
0
  profiler_tracing(category, markerName, kind)
580
void profiler_tracing(const char* aCategory, const char* aMarkerName,
581
                      TracingKind aKind);
582
void profiler_tracing(const char* aCategory, const char* aMarkerName,
583
                      TracingKind aKind, UniqueProfilerBacktrace aCause);
584
585
// Adds a START/END pair of tracing markers.
586
#define AUTO_PROFILER_TRACING(category, markerName) \
587
0
  mozilla::AutoProfilerTracing PROFILER_RAII(category, markerName)
588
589
//---------------------------------------------------------------------------
590
// Output profiles
591
//---------------------------------------------------------------------------
592
593
// Get the profile encoded as a JSON string. A no-op (returning nullptr) if the
594
// profiler is inactive.
595
// If aIsShuttingDown is true, the current time is included as the process
596
// shutdown time in the JSON's "meta" object.
597
mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0,
598
                                                bool aIsShuttingDown = false);
599
600
// Write the profile for this process (excluding subprocesses) into aWriter.
601
// Returns false if the profiler is inactive.
602
bool profiler_stream_json_for_this_process(SpliceableJSONWriter& aWriter,
603
                                           double aSinceTime = 0,
604
                                           bool aIsShuttingDown = false);
605
606
// Get the profile and write it into a file. A no-op if the profile is
607
// inactive.
608
//
609
// This function is 'extern "C"' so that it is easily callable from a debugger
610
// in a build without debugging information (a workaround for
611
// http://llvm.org/bugs/show_bug.cgi?id=22211).
612
extern "C" {
613
void profiler_save_profile_to_file(const char* aFilename);
614
}
615
616
//---------------------------------------------------------------------------
617
// RAII classes
618
//---------------------------------------------------------------------------
619
620
namespace mozilla {
621
622
class MOZ_RAII AutoProfilerInit
623
{
624
public:
625
  explicit AutoProfilerInit(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
626
3
  {
627
3
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
628
3
    profiler_init(this);
629
3
  }
630
631
0
  ~AutoProfilerInit() { profiler_shutdown(); }
632
633
private:
634
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
635
};
636
637
// Convenience class to register and unregister a thread with the profiler.
638
// Needs to be the first object on the stack of the thread.
639
class MOZ_RAII AutoProfilerRegisterThread final
640
{
641
public:
642
  explicit AutoProfilerRegisterThread(const char* aName
643
                                      MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
644
9
  {
645
9
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
646
9
    profiler_register_thread(aName, this);
647
9
  }
648
649
0
  ~AutoProfilerRegisterThread() { profiler_unregister_thread(); }
650
651
private:
652
  AutoProfilerRegisterThread(const AutoProfilerRegisterThread&) = delete;
653
  AutoProfilerRegisterThread& operator=(const AutoProfilerRegisterThread&) =
654
    delete;
655
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
656
};
657
658
class MOZ_RAII AutoProfilerThreadSleep
659
{
660
public:
661
  explicit AutoProfilerThreadSleep(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
662
210
  {
663
210
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
664
210
    profiler_thread_sleep();
665
210
  }
666
667
200
  ~AutoProfilerThreadSleep() { profiler_thread_wake(); }
668
669
private:
670
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
671
};
672
673
// Temporarily wake up the profiling of a thread while servicing events such as
674
// Asynchronous Procedure Calls (APCs).
675
class MOZ_RAII AutoProfilerThreadWake
676
{
677
public:
678
  explicit AutoProfilerThreadWake(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
679
    : mIssuedWake(profiler_thread_is_sleeping())
680
0
  {
681
0
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
682
0
    if (mIssuedWake) {
683
0
      profiler_thread_wake();
684
0
    }
685
0
  }
686
687
  ~AutoProfilerThreadWake()
688
0
  {
689
0
    if (mIssuedWake) {
690
0
      MOZ_ASSERT(!profiler_thread_is_sleeping());
691
0
      profiler_thread_sleep();
692
0
    }
693
0
  }
694
695
private:
696
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
697
  bool mIssuedWake;
698
};
699
700
// This class creates a non-owning ProfilingStack reference. Objects of this class
701
// are stack-allocated, and so exist within a thread, and are thus bounded by
702
// the lifetime of the thread, which ensures that the references held can't be
703
// used after the ProfilingStack is destroyed.
704
class MOZ_RAII AutoProfilerLabel
705
{
706
public:
707
  // This is the AUTO_PROFILER_LABEL and AUTO_PROFILER_LABEL_DYNAMIC variant.
708
  AutoProfilerLabel(const char* aLabel, const char* aDynamicString,
709
                    uint32_t aLine, js::ProfilingStackFrame::Category aCategory
710
                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
711
1.62M
  {
712
1.62M
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
713
1.62M
714
1.62M
    // Get the ProfilingStack from TLS.
715
1.62M
    Push(sProfilingStack.get(), aLabel, aDynamicString, aLine, aCategory);
716
1.62M
  }
717
718
  // This is the AUTO_PROFILER_LABEL_FAST variant. It's guarded on
719
  // profiler_is_active() and retrieves the ProfilingStack from the JSContext.
720
  AutoProfilerLabel(JSContext* aJSContext,
721
                    const char* aLabel, const char* aDynamicString,
722
                    uint32_t aLine, js::ProfilingStackFrame::Category aCategory
723
                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
724
14
  {
725
14
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
726
14
    if (profiler_is_active()) {
727
0
      Push(js::GetContextProfilingStack(aJSContext),
728
0
           aLabel, aDynamicString, aLine, aCategory);
729
14
    } else {
730
14
      mProfilingStack = nullptr;
731
14
    }
732
14
  }
733
734
  void Push(ProfilingStack* aProfilingStack,
735
            const char* aLabel, const char* aDynamicString,
736
            uint32_t aLine, js::ProfilingStackFrame::Category aCategory)
737
1.62M
  {
738
1.62M
    // This function runs both on and off the main thread.
739
1.62M
740
1.62M
    mProfilingStack = aProfilingStack;
741
1.62M
    if (mProfilingStack) {
742
1.62M
      mProfilingStack->pushLabelFrame(aLabel, aDynamicString, this, aLine,
743
1.62M
                                   aCategory);
744
1.62M
    }
745
1.62M
  }
746
747
  ~AutoProfilerLabel()
748
1.62M
  {
749
1.62M
    // This function runs both on and off the main thread.
750
1.62M
751
1.62M
    if (mProfilingStack) {
752
1.62M
      mProfilingStack->pop();
753
1.62M
    }
754
1.62M
  }
755
756
private:
757
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
758
759
  // We save a ProfilingStack pointer in the ctor so we don't have to redo the TLS
760
  // lookup in the dtor.
761
  ProfilingStack* mProfilingStack;
762
763
public:
764
  // See the comment on the definition in platform.cpp for details about this.
765
  static MOZ_THREAD_LOCAL(ProfilingStack*) sProfilingStack;
766
};
767
768
class MOZ_RAII AutoProfilerTracing
769
{
770
public:
771
  AutoProfilerTracing(const char* aCategory, const char* aMarkerName
772
                      MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
773
    : mCategory(aCategory)
774
    , mMarkerName(aMarkerName)
775
0
  {
776
0
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
777
0
    profiler_tracing(mCategory, mMarkerName, TRACING_INTERVAL_START);
778
0
  }
779
780
  AutoProfilerTracing(const char* aCategory, const char* aMarkerName,
781
                      UniqueProfilerBacktrace aBacktrace
782
                      MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
783
    : mCategory(aCategory)
784
    , mMarkerName(aMarkerName)
785
0
  {
786
0
    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
787
0
    profiler_tracing(mCategory, mMarkerName, TRACING_INTERVAL_START,
788
0
                     std::move(aBacktrace));
789
0
  }
790
791
  ~AutoProfilerTracing()
792
0
  {
793
0
    profiler_tracing(mCategory, mMarkerName, TRACING_INTERVAL_END);
794
0
  }
795
796
protected:
797
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
798
  const char* mCategory;
799
  const char* mMarkerName;
800
};
801
802
// Set MOZ_PROFILER_STARTUP* environment variables that will be inherited into
803
// a child process that is about to be launched, in order to make that child
804
// process start with the same profiler settings as in the current process.
805
class MOZ_RAII AutoSetProfilerEnvVarsForChildProcess
806
{
807
public:
808
  explicit AutoSetProfilerEnvVarsForChildProcess(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
809
  ~AutoSetProfilerEnvVarsForChildProcess();
810
811
private:
812
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
813
  char mSetEntries[64];
814
  char mSetInterval[64];
815
  char mSetFeaturesBitfield[64];
816
  char mSetFilters[1024];
817
};
818
819
} // namespace mozilla
820
821
#endif // !MOZ_GECKO_PROFILER
822
823
#endif  // GeckoProfiler_h