author Ehsan Akhgari <>
Sun, 07 May 2017 16:38:50 -0400
changeset 356994 aefe9ec739e13e1d1a660017e4ef92268e60cb15
parent 356721 bc25cff90b6ede8d18edfa2d4539c3fc2df3486a
child 356997 284d41dc240f0dea28af10a52327d0e6a99f62cd
permissions -rw-r--r--
Bug 1362814 - Part 0: Remove an unneeded inclusion from GeckoProfiler.h

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at */

// The Gecko Profiler is an always-on profiler that takes fast and low overhead
// samples of the program execution using only userspace functionality for
// portability. The goal of this module is to provide performance data in a
// generic cross-platform way without requiring custom tools or kernel support.
// Samples are collected to form a timeline with optional timeline event
// (markers) used for filtering. Both "periodic" (in response to a timer) and
// "synchronous" (in response to an explicit sampling request via the API)
// samples are supported.
// The profiler collects samples that include native stacks and
// platform-independent "pseudostacks".

#ifndef GeckoProfiler_h
#define GeckoProfiler_h

#include <stdint.h>
#include <stdarg.h>

#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "js/TypeDecls.h"
#include "mozilla/GuardObjects.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
#include "nsString.h"

class SpliceableJSONWriter;

namespace mozilla {
class TimeStamp;

namespace dom {
class Promise;
} // namespace dom

} // namespace mozilla

class nsIProfilerStartParams;

enum TracingKind {

class ProfilerBacktrace;

struct ProfilerBacktraceDestructor
  void operator()(ProfilerBacktrace*);
using UniqueProfilerBacktrace =
  mozilla::UniquePtr<ProfilerBacktrace, ProfilerBacktraceDestructor>;

#if !defined(MOZ_GECKO_PROFILER)

// Use these for functions below that must be visible whether the profiler is
// enabled or not. When the profiler is disabled they are static inline
// functions (with a simple return value if they are non-void) that should be
// optimized away during compilation.
#define PROFILER_FUNC(decl, rv)  static inline decl { return rv; }
#define PROFILER_FUNC_VOID(decl) static inline void decl {}

// Insert an RAII object in this scope to enter a pseudo stack frame. Any
// samples collected in this scope will contain this label in their pseudo
// stack. The name_space and info arguments must be string literals.
// Use PROFILER_LABEL_DYNAMIC if you want to add additional / dynamic
// information to the pseudo stack frame.
#define PROFILER_LABEL(name_space, info, category) do {} while (0)

// Similar to PROFILER_LABEL, PROFILER_LABEL_FUNC will push/pop the enclosing
// functon name as the pseudostack label.
#define PROFILER_LABEL_FUNC(category) do {} while (0)

// Enter a pseudo stack frame in this scope and associate it with an
// additional string.
// This macro generates an RAII object. This RAII object stores the str
// pointer in a field; it does not copy the string. This means that the string
// you pass to this macro needs to live at least until the end of the current
// scope.
// If the profiler samples the current thread and walks the pseudo stack while
// this RAII object is on the stack, it will copy the supplied string into the
// profile buffer. So there's one string copy operation, and it happens at
// sample time.
// Compare this to the plain PROFILER_LABEL macro, which only accepts literal
// strings: When the pseudo stack frames generated by PROFILER_LABEL are
// sampled, no string copy needs to be made because the profile buffer can
// just store the raw pointers to the literal strings. Consequently,
// PROFILER_LABEL frames take up considerably less space in the profile buffer
#define PROFILER_LABEL_DYNAMIC(name_space, info, category, str) do {} while (0)

// Insert a marker in the profile timeline. This is useful to delimit something
// important happening such as the first paint. Unlike profiler_label that are
// only recorded if a sample is collected while it is active, marker will always
// be collected.
#define PROFILER_MARKER(info) do {} while (0)
#define PROFILER_MARKER_PAYLOAD(info, payload) \
  do { \
    mozilla::UniquePtr<ProfilerMarkerPayload> payloadDeletor(payload); \
  } while (0)

#else   // defined(MOZ_GECKO_PROFILER)

// Higher-order macro containing all the feature info in one place. Define
// |macro| appropriately to extract the relevant parts. Note that the number
// values are used internally only and so can be changed without consequence.
  /* Dump the display list with the textures. */ \
  macro(0, "displaylistdump", DisplayListDump) \
  /* GPU Profiling (may not be supported by the GL). */ \
  macro(1, "gpu", GPU) \
  /* Profile Java code (Android only). */ \
  macro(2, "java", Java) \
  /* Get the JS engine to emit pseudostack entries in prologues/epilogues */ \
  macro(3, "js", JS) \
  /* Dump the layer tree with the textures. */ \
  macro(4, "layersdump", LayersDump) \
  /* Include the C++ leaf node if not stackwalking. */ \
  /* The DevTools profiler doesn't want the native addresses. */ \
  macro(5, "leaf", Leaf) \
  /* Add main thread I/O to the profile. */ \
  macro(6, "mainthreadio", MainThreadIO) \
  /* Add memory measurements (e.g. RSS). */ \
  macro(7, "memory", Memory) \
  /* Do not include user-identifiable information. */ \
  macro(8, "privacy", Privacy) \
  /* Restyle profiling. */ \
  macro(9, "restyle", Restyle) \
  /* Walk the C++ stack. Not available on all platforms. */ \
  macro(10, "stackwalk", StackWalk) \
  /* Start profiling with feature TaskTracer. */ \
  macro(11, "tasktracer", TaskTracer) \
  /* Profile the registered secondary threads. */ \
  macro(12, "threads", Threads)

struct ProfilerFeature
  #define DECLARE(n_, str_, Name_) \
    static const uint32_t Name_ = (1u << n_); \
    static bool Has##Name_(uint32_t aFeatures) { return aFeatures & Name_; } \
    static void Set##Name_(uint32_t& aFeatures) { aFeatures |= Name_; } \
    static void Clear##Name_(uint32_t& aFeatures) { aFeatures &= ~Name_; }

  // Define a bitfield constant, a getter, and two setters for each feature.

  #undef DECLARE

#if defined(__GNUC__) || defined(_MSC_VER)
  // From C99, supported by some C++ compilers. Just the raw function name.
# define PROFILER_FUNCTION_NAME __func__

#define PROFILER_FUNC(decl, rv)  decl;
#define PROFILER_FUNC_VOID(decl) void decl;

// we want the class and function name but can't easily get that using preprocessor macros
// __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters

#define PROFILER_LABEL(name_space, info, category) \
  PROFILER_PLATFORM_TRACING(name_space "::" info) \
  mozilla::SamplerStackFrameRAII \
  PROFILER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, category, \

#define PROFILER_LABEL_FUNC(category) \
  mozilla::SamplerStackFrameRAII \

#define PROFILER_LABEL_DYNAMIC(name_space, info, category, str) \
  PROFILER_PLATFORM_TRACING(name_space "::" info) \
  mozilla::SamplerStackFrameDynamicRAII \
  PROFILER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, category, \
                                            __LINE__, str)

#define PROFILER_MARKER(info) profiler_add_marker(info)
#define PROFILER_MARKER_PAYLOAD(info, payload) \
  profiler_add_marker(info, payload)

#endif  // defined(MOZ_GECKO_PROFILER)

// These functions are defined whether the profiler is enabled or not.

// Adds a tracing marker to the PseudoStack. A no-op if the profiler is
// inactive or in privacy mode.
PROFILER_FUNC_VOID(profiler_tracing(const char* aCategory, const char* aInfo,
                                    TracingKind aKind = TRACING_EVENT))
PROFILER_FUNC_VOID(profiler_tracing(const char* aCategory, const char* aInfo,
                                    UniqueProfilerBacktrace aCause,
                                    TracingKind aKind = TRACING_EVENT))

// Initialize the profiler. If MOZ_PROFILER_STARTUP is set the profiler will be
// started. This call must happen before any other profiler calls (except
// profiler_start(), which will call profiler_init() if it hasn't already run).
PROFILER_FUNC_VOID(profiler_init(void* stackTop))

// Clean up the profiler module, stopping it if required. This function may
// also save a shutdown profile if requested. No profiler calls should happen
// after this point and all pseudo labels should have been popped.

// Start the profiler -- initializing it first if necessary -- with the
// selected options. Stops and restarts the profiler if it is already active.
// After starting the profiler is "active". The samples will be recorded in a
// circular buffer.
//   "aEntries" is the number of entries in the profiler's circular buffer.
//   "aInterval" the sampling interval, measured in millseconds.
//   "aFeatures" is the feature set. Features unsupported by this
//               platform/configuration are ignored.
PROFILER_FUNC_VOID(profiler_start(int aEntries, double aInterval,
                                  uint32_t aFeatures,
                                  const char** aFilters, uint32_t aFilterCount))

// Stop the profiler and discard the profile without saving it. A no-op if the
// profiler is inactive. After stopping the profiler is "inactive".

// Pause and resume the profiler. No-ops if the profiler is inactive. While
// paused the profile will not take any samples and will not record any data
// into its buffers. The profiler remains fully initialized in this state.
// Timeline markers will still be stored. This feature will keep JavaScript
// profiling enabled, thus allowing toggling the profiler without invalidating
// the JIT.

// Is the profiler active and paused? Returns false if the profiler is inactive.
PROFILER_FUNC(bool profiler_is_paused(), false)

// Immediately capture the current thread's call stack and return it. A no-op
// if the profiler is inactive or in privacy mode.
PROFILER_FUNC(UniqueProfilerBacktrace profiler_get_backtrace(), nullptr)

PROFILER_FUNC_VOID(profiler_get_backtrace_noalloc(char *output,
                                                  size_t outputSize))

// Free a ProfilerBacktrace returned by profiler_get_backtrace().
#if !defined(MOZ_GECKO_PROFILER)
inline void
ProfilerBacktraceDestructor::operator()(ProfilerBacktrace* aBacktrace) {}

// Is the profiler active? Note: the return value of this function can become
// immediately out-of-date. E.g. the profile might be active but then
// profiler_stop() is called immediately afterward. One common and reasonable
// pattern of usage is the following:
//   if (profiler_is_active()) {
//     ExpensiveData expensiveData = CreateExpensiveData();
//     PROFILER_OPERATION(expensiveData);
//   }
// where PROFILER_OPERATION is a no-op if the profiler is inactive. In this
// case the profiler_is_active() check is just an optimization -- it prevents
// us calling CreateExpensiveData() unnecessarily in most cases, but the
// expensive data will end up being created but not used if another thread
// stops the profiler between the CreateExpensiveData() and PROFILER_OPERATION
// calls.
PROFILER_FUNC(bool profiler_is_active(), false)

// Check if a profiler feature (specified via the ProfilerFeature type) is
// active. Returns false if the profiler is inactive.
PROFILER_FUNC(bool profiler_feature_active(uint32_t aFeature), false)

// Get the profile encoded as a JSON string. A no-op (returning nullptr) if the
// profiler is inactive.
PROFILER_FUNC(mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0),

// Write the profile for this process (excluding subprocesses) into aWriter.
// Returns false if the profiler is inactive.
PROFILER_FUNC(bool profiler_stream_json_for_this_process(SpliceableJSONWriter& aWriter,
                                                         double aSinceTime = 0),

// Get the params used to start the profiler. Returns 0 and an empty vector
// (via outparams) if the profile is inactive. It's possible that the features
// returned may be slightly different to those requested due to requied
// adjustments.
PROFILER_FUNC_VOID(profiler_get_start_params(int* aEntrySize,
                                             double* aInterval,
                                             uint32_t* aFeatures,
                                             mozilla::Vector<const char*>* aFilters))

// Get the profile and write it into a file. A no-op if the profile is
// inactive.
// This function is 'extern "C"' so that it is easily callable from a debugger
// in a build without debugging information (a workaround for
extern "C" {
PROFILER_FUNC_VOID(profiler_save_profile_to_file(const char* aFilename))

// Get all the features supported by the profiler that are accepted by
// profiler_start(). The result is the same whether the profiler is active or
// not.
PROFILER_FUNC(uint32_t profiler_get_available_features(), 0)

// Get information about the current buffer status. A no-op when the profiler
// is inactive. Do not call this function; call profiler_get_buffer_info()
// instead.
PROFILER_FUNC_VOID(profiler_get_buffer_info_helper(uint32_t* aCurrentPosition,
                                                   uint32_t* aEntries,
                                                   uint32_t* aGeneration))

// Get information about the current buffer status. Returns (via outparams) the
// current write position in the buffer, the total size of the buffer, and the
// generation of the buffer. Returns zeroes if the profiler is inactive.
// This information may be useful to a user-interface displaying the current
// status of the profiler, allowing the user to get a sense for how fast the
// buffer is being written to, and how much data is visible.
static inline void profiler_get_buffer_info(uint32_t* aCurrentPosition,
                                            uint32_t* aEntries,
                                            uint32_t* aGeneration)
  *aCurrentPosition = 0;
  *aEntries = 0;
  *aGeneration = 0;

  profiler_get_buffer_info_helper(aCurrentPosition, aEntries, aGeneration);

// Register/unregister threads with the profiler. Both functions operate the
// same whether the profiler is active or inactive.
PROFILER_FUNC_VOID(profiler_register_thread(const char* name,
                                            void* guessStackTop))

// These functions tell the profiler that a thread went to sleep so that we can
// avoid sampling it while it's sleeping. Calling profiler_thread_sleep()
// twice without an intervening profiler_thread_wake() is an error. All three
// functions operate the same whether the profiler is active or inactive.
PROFILER_FUNC(bool profiler_thread_is_sleeping(), false)

// Call by the JSRuntime's operation callback. This is used to start profiling
// on auxiliary threads. Operates the same whether the profiler is active or
// not.

// The number of milliseconds since the process started. Operates the same
// whether the profiler is active or inactive.
PROFILER_FUNC(double profiler_time(), 0)

PROFILER_FUNC_VOID(profiler_log(const char *str))

// Gets the stack top of the current thread.
// The thread must have been previously registered with the profiler, otherwise
// this method will return nullptr.
PROFILER_FUNC(void* profiler_get_stack_top(), nullptr)

// End of the functions defined whether the profiler is enabled or not.


#include <stdlib.h>
#include <signal.h>
#include "js/ProfilingStack.h"
#include "mozilla/Sprintf.h"
#include "mozilla/ThreadLocal.h"
#include "nscore.h"
#include "nsIMemoryReporter.h"

// Make sure that we can use std::min here without the Windows headers messing with us.
#ifdef min
# undef min

class nsISupports;
class ProfilerMarkerPayload;
class PseudoStack;

// Returns a handle to pass on exit. This can check that we are popping the
// correct callstack. Operates the same whether the profiler is active or not.
void* profiler_call_enter(const char* aInfo,
                          js::ProfileEntry::Category aCategory,
                          void* aFrameAddress, bool aCopy, uint32_t aLine,
                          const char* aDynamicString = nullptr);
void profiler_call_exit(void* aHandle);

// Adds a marker to the PseudoStack. A no-op if the profiler is inactive or in
// privacy mode.
void profiler_add_marker(const char *aMarker,
                         ProfilerMarkerPayload *aPayload = nullptr);

#define PROFILER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line

// Uncomment this to turn on systrace or build with
// ac_add_options --enable-systace
# ifndef ATRACE_TAG
# endif
// We need HAVE_ANDROID_OS to be defined for Trace.h.
// If its not set we will set it temporary and remove it.
# endif
// Android source code will include <cutils/trace.h> before this. There is no
// HAVE_ANDROID_OS defined in Firefox OS build at that time. Enabled it globally
// will cause other build break. So atrace_begin and atrace_end are not defined.
// It will cause a build-break when we include <utils/Trace.h>. Use undef
// _LIBS_CUTILS_TRACE_H will force <cutils/trace.h> to define atrace_begin and
// atrace_end with defined HAVE_ANDROID_OS again. Then there is no build-break.
# include <utils/Trace.h>
    android::ScopedTrace \
# endif

// FIXME/bug 789667: memory constraints wouldn't much of a problem for this
// small a sample buffer size, except that serializing the profile data is
// extremely, unnecessarily memory intensive.


// In the case of profiler_get_backtrace we know that we only need enough space
// for a single backtrace.

// A 1ms sampling interval has been shown to be a large perf hit (10fps) on
// memory-constrained (low-end) platforms, and additionally to yield different
// results from the profiler. Where this is the important case, b2g, there are
// also many gecko processes which magnify these effects.

namespace mozilla {

class MOZ_RAII SamplerStackFrameRAII {
  // We only copy the strings at save time, so to take multiple parameters we'd
  // need to copy them then.
  SamplerStackFrameRAII(const char *aInfo,
    js::ProfileEntry::Category aCategory, uint32_t line
    mHandle = profiler_call_enter(aInfo, aCategory, this, false, line);
  ~SamplerStackFrameRAII() {
  void* mHandle;

class MOZ_RAII SamplerStackFrameDynamicRAII {
  SamplerStackFrameDynamicRAII(const char* aInfo,
    js::ProfileEntry::Category aCategory, uint32_t aLine,
    const char* aDynamicString)
    mHandle = profiler_call_enter(aInfo, aCategory, this, true, aLine,

  ~SamplerStackFrameDynamicRAII() {

  void* mHandle;

} // namespace mozilla

PseudoStack* profiler_get_pseudo_stack();

void profiler_set_js_context(JSContext* aCx);
void profiler_clear_js_context();

class GeckoProfilerReporter final : public nsIMemoryReporter

  GeckoProfilerReporter() {}

  CollectReports(nsIHandleReportCallback* aHandleReport,
                 nsISupports* aData, bool aAnonymize) override;

  ~GeckoProfilerReporter() {}

#endif  // defined(MOZ_GECKO_PROFILER)

namespace mozilla {

class MOZ_RAII GeckoProfilerInitRAII {
  explicit GeckoProfilerInitRAII(void* stackTop) {
  ~GeckoProfilerInitRAII() {

class MOZ_RAII GeckoProfilerThreadSleepRAII {
  GeckoProfilerThreadSleepRAII() {
  ~GeckoProfilerThreadSleepRAII() {

// Temporarily wake up the profiling of a thread while servicing events such as
// Asynchronous Procedure Calls (APCs).
class MOZ_RAII GeckoProfilerThreadWakeRAII {
    : mIssuedWake(profiler_thread_is_sleeping())
    if (mIssuedWake) {
  ~GeckoProfilerThreadWakeRAII() {
    if (mIssuedWake) {
  bool mIssuedWake;

class MOZ_RAII GeckoProfilerTracingRAII {
  GeckoProfilerTracingRAII(const char* aCategory, const char* aInfo,
                           UniqueProfilerBacktrace aBacktrace
    : mCategory(aCategory)
    , mInfo(aInfo)
    profiler_tracing(mCategory, mInfo, Move(aBacktrace), TRACING_INTERVAL_START);

  GeckoProfilerTracingRAII(const char* aCategory, const char* aInfo
    : mCategory(aCategory)
    , mInfo(aInfo)
    profiler_tracing(mCategory, mInfo, TRACING_INTERVAL_START);

  ~GeckoProfilerTracingRAII() {
    profiler_tracing(mCategory, mInfo, TRACING_INTERVAL_END);

  const char* mCategory;
  const char* mInfo;

// Convenience class to register and unregister a thread with the profiler.
// Needs to be the first object on the stack of the thread.
class MOZ_STACK_CLASS AutoProfilerRegister final
  explicit AutoProfilerRegister(const char* aName)
    profiler_register_thread(aName, this);
  AutoProfilerRegister(const AutoProfilerRegister&) = delete;
  AutoProfilerRegister& operator=(const AutoProfilerRegister&) = delete;

} // namespace mozilla

#endif  // GeckoProfiler_h