Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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);
extern MOZ_EXPORT void uprofiler_simple_event_marker_with_stack(
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);
void (*simple_event_marker_with_stack)(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 */
}
static void simple_event_marker_with_stack_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) (typeof(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
#define FETCH(func) \
uprofiler.func = UPROFILER_GET_SYM(handle, uprofiler_##func); \
if (!uprofiler.func) { \
UPROFILER_PRINT_ERROR(uprofiler_##func); \
uprofiler.func = func##_noop; \
}
#define UPROFILER_VISIT() \
FETCH(register_thread) \
FETCH(unregister_thread) \
FETCH(simple_event_marker) \
FETCH(simple_event_marker_with_stack)
// 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.simple_event_marker_with_stack = simple_event_with_stack_noop; \
} \
UPROFILER_VISIT()
#endif // MICRO_GECKO_PROFILER