summaryrefslogtreecommitdiffstats
path: root/tools/profiler/public/MicroGeckoProfiler.h
blob: 7b735e1eec0b335d5236b97fc06806408cbc7074 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* -*- 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 http://mozilla.org/MPL/2.0/. */

// This contains things related to the Gecko profiler, for use in third_party
// code. It is very minimal and is designed to be used by patching over
// upstream code.
// Only use the C ABI and guard C++ code with #ifdefs, don't pull anything from
// Gecko, it must be possible to include the header file into any C++ codebase.

#ifndef MICRO_GECKO_PROFILER
#define MICRO_GECKO_PROFILER

#ifdef __cplusplus
extern "C" {
#endif

#include <mozilla/Types.h>
#include <stdio.h>

#ifdef _WIN32
#  include <libloaderapi.h>
#else
#  include <dlfcn.h>
#endif

extern MOZ_EXPORT void uprofiler_register_thread(const char* aName,
                                                 void* aGuessStackTop);

extern MOZ_EXPORT void uprofiler_unregister_thread();

extern MOZ_EXPORT void uprofiler_simple_event_marker(
    const char* name, char phase, int num_args, const char** arg_names,
    const unsigned char* arg_types, const unsigned long long* arg_values);
#ifdef __cplusplus
}

struct AutoRegisterProfiler {
  AutoRegisterProfiler(const char* name, char* stacktop) {
    if (getenv("MOZ_UPROFILER_LOG_THREAD_CREATION")) {
      printf("### UProfiler: new thread: '%s'\n", name);
    }
    uprofiler_register_thread(name, stacktop);
  }
  ~AutoRegisterProfiler() { uprofiler_unregister_thread(); }
};
#endif  // __cplusplus

void uprofiler_simple_event_marker(const char* name, char phase, int num_args,
                                   const char** arg_names,
                                   const unsigned char* arg_types,
                                   const unsigned long long* arg_values);

struct UprofilerFuncPtrs {
  void (*register_thread)(const char* aName, void* aGuessStackTop);
  void (*unregister_thread)();
  void (*simple_event_marker)(const char* name, char phase, int num_args,
                              const char** arg_names,
                              const unsigned char* arg_types,
                              const unsigned long long* arg_values);
};

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"

static void register_thread_noop(const char* aName, void* aGuessStackTop) {
  /* no-op */
}
static void unregister_thread_noop() { /* no-op */
}
static void simple_event_marker_noop(const char* name, char phase, int num_args,
                                     const char** arg_names,
                                     const unsigned char* arg_types,
                                     const unsigned long long* arg_values) {
  /* no-op */
}

#pragma GCC diagnostic pop

#if defined(_WIN32)
#  define UPROFILER_OPENLIB() GetModuleHandle(NULL)
#else
#  define UPROFILER_OPENLIB() dlopen(NULL, RTLD_NOW)
#endif

#if defined(_WIN32)
#  define UPROFILER_GET_SYM(handle, sym) GetProcAddress(handle, sym)
#else
#  define UPROFILER_GET_SYM(handle, sym) dlsym(handle, sym)
#endif

#if defined(_WIN32)
#  define UPROFILER_PRINT_ERROR(func) fprintf(stderr, "%s error\n", #func);
#else
#  define UPROFILER_PRINT_ERROR(func) \
    fprintf(stderr, "%s error: %s\n", #func, dlerror());
#endif

// Assumes that a variable of type UprofilerFuncPtrs, named uprofiler
// is accessible in the scope
#define UPROFILER_GET_FUNCTIONS()                                 \
  void* handle = UPROFILER_OPENLIB();                             \
  if (!handle) {                                                  \
    UPROFILER_PRINT_ERROR(UPROFILER_OPENLIB);                     \
    uprofiler.register_thread = register_thread_noop;             \
    uprofiler.unregister_thread = unregister_thread_noop;         \
    uprofiler.simple_event_marker = simple_event_marker_noop;     \
  }                                                               \
  uprofiler.register_thread =                                     \
      UPROFILER_GET_SYM(handle, "uprofiler_register_thread");     \
  if (!uprofiler.register_thread) {                               \
    UPROFILER_PRINT_ERROR(uprofiler_unregister_thread);           \
    uprofiler.register_thread = register_thread_noop;             \
  }                                                               \
  uprofiler.unregister_thread =                                   \
      UPROFILER_GET_SYM(handle, "uprofiler_unregister_thread");   \
  if (!uprofiler.unregister_thread) {                             \
    UPROFILER_PRINT_ERROR(uprofiler_unregister_thread);           \
    uprofiler.unregister_thread = unregister_thread_noop;         \
  }                                                               \
  uprofiler.simple_event_marker =                                 \
      UPROFILER_GET_SYM(handle, "uprofiler_simple_event_marker"); \
  if (!uprofiler.simple_event_marker) {                           \
    UPROFILER_PRINT_ERROR(uprofiler_simple_event_marker);         \
    uprofiler.simple_event_marker = simple_event_marker_noop;     \
  }

#endif  // MICRO_GECKO_PROFILER