зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1774416 - Allow dynamically fetching uprofiler functions to profile libraries that can't access the Gecko profiler API. r=canaltinova
This is solving a particular problem for us in media land. libxul depends on libmoz{avcodec,format,util}, but not the opposite. We can't use the profiler functions (thread registration, markers, etc.) there. Unfortunately those libraries contain most of the interesting part for a few codecs, including their own thread pool, so we really want to register those threads and add markers to their innards so that we can figure out what's going on and how to use them in the most efficient way. Another problem is that those libraries are in C, and the markers API is in C++. The trick here is that when those libraries are being called into, the functions in MicroGeckoProfiler.h (that exposes a C API for the profiler) are available in the address space (it's never too early), so we can fetch them and start using them, without having libmoz{avcodec,format,util} link to libxul. This let us write temporary patches over vendored dependencies to diagnose locally, and/or carry small and easily rebaseable patches to register important threads that are otherwise invisible to the profiler. Differential Revision: https://phabricator.services.mozilla.com/D149543
This commit is contained in:
Родитель
01a5c02624
Коммит
1d31bafb33
|
@ -17,19 +17,26 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void uprofiler_register_thread(const char* aName, void* aGuessStackTop);
|
||||
void uprofiler_unregister_thread();
|
||||
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);
|
||||
#include <mozilla/Types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#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")) {
|
||||
|
@ -41,4 +48,82 @@ struct AutoRegisterProfiler {
|
|||
};
|
||||
#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
|
||||
|
|
Загрузка…
Ссылка в новой задаче