141 lines
5.4 KiB
C
141 lines
5.4 KiB
C
/* -*- 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
|