1*1208bc7eSAndroid Build Coastguard Worker #ifndef JEMALLOC_INTERNAL_LOG_H
2*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_INTERNAL_LOG_H
3*1208bc7eSAndroid Build Coastguard Worker
4*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/atomic.h"
5*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/malloc_io.h"
6*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/mutex.h"
7*1208bc7eSAndroid Build Coastguard Worker
8*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_LOG
9*1208bc7eSAndroid Build Coastguard Worker # define JEMALLOC_LOG_VAR_BUFSIZE 1000
10*1208bc7eSAndroid Build Coastguard Worker #else
11*1208bc7eSAndroid Build Coastguard Worker # define JEMALLOC_LOG_VAR_BUFSIZE 1
12*1208bc7eSAndroid Build Coastguard Worker #endif
13*1208bc7eSAndroid Build Coastguard Worker
14*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_LOG_BUFSIZE 4096
15*1208bc7eSAndroid Build Coastguard Worker
16*1208bc7eSAndroid Build Coastguard Worker /*
17*1208bc7eSAndroid Build Coastguard Worker * The log malloc_conf option is a '|'-delimited list of log_var name segments
18*1208bc7eSAndroid Build Coastguard Worker * which should be logged. The names are themselves hierarchical, with '.' as
19*1208bc7eSAndroid Build Coastguard Worker * the delimiter (a "segment" is just a prefix in the log namespace). So, if
20*1208bc7eSAndroid Build Coastguard Worker * you have:
21*1208bc7eSAndroid Build Coastguard Worker *
22*1208bc7eSAndroid Build Coastguard Worker * log("arena", "log msg for arena"); // 1
23*1208bc7eSAndroid Build Coastguard Worker * log("arena.a", "log msg for arena.a"); // 2
24*1208bc7eSAndroid Build Coastguard Worker * log("arena.b", "log msg for arena.b"); // 3
25*1208bc7eSAndroid Build Coastguard Worker * log("arena.a.a", "log msg for arena.a.a"); // 4
26*1208bc7eSAndroid Build Coastguard Worker * log("extent.a", "log msg for extent.a"); // 5
27*1208bc7eSAndroid Build Coastguard Worker * log("extent.b", "log msg for extent.b"); // 6
28*1208bc7eSAndroid Build Coastguard Worker *
29*1208bc7eSAndroid Build Coastguard Worker * And your malloc_conf option is "log=arena.a|extent", then lines 2, 4, 5, and
30*1208bc7eSAndroid Build Coastguard Worker * 6 will print at runtime. You can enable logging from all log vars by
31*1208bc7eSAndroid Build Coastguard Worker * writing "log=.".
32*1208bc7eSAndroid Build Coastguard Worker *
33*1208bc7eSAndroid Build Coastguard Worker * None of this should be regarded as a stable API for right now. It's intended
34*1208bc7eSAndroid Build Coastguard Worker * as a debugging interface, to let us keep around some of our printf-debugging
35*1208bc7eSAndroid Build Coastguard Worker * statements.
36*1208bc7eSAndroid Build Coastguard Worker */
37*1208bc7eSAndroid Build Coastguard Worker
38*1208bc7eSAndroid Build Coastguard Worker extern char log_var_names[JEMALLOC_LOG_VAR_BUFSIZE];
39*1208bc7eSAndroid Build Coastguard Worker extern atomic_b_t log_init_done;
40*1208bc7eSAndroid Build Coastguard Worker
41*1208bc7eSAndroid Build Coastguard Worker typedef struct log_var_s log_var_t;
42*1208bc7eSAndroid Build Coastguard Worker struct log_var_s {
43*1208bc7eSAndroid Build Coastguard Worker /*
44*1208bc7eSAndroid Build Coastguard Worker * Lowest bit is "inited", second lowest is "enabled". Putting them in
45*1208bc7eSAndroid Build Coastguard Worker * a single word lets us avoid any fences on weak architectures.
46*1208bc7eSAndroid Build Coastguard Worker */
47*1208bc7eSAndroid Build Coastguard Worker atomic_u_t state;
48*1208bc7eSAndroid Build Coastguard Worker const char *name;
49*1208bc7eSAndroid Build Coastguard Worker };
50*1208bc7eSAndroid Build Coastguard Worker
51*1208bc7eSAndroid Build Coastguard Worker #define LOG_NOT_INITIALIZED 0U
52*1208bc7eSAndroid Build Coastguard Worker #define LOG_INITIALIZED_NOT_ENABLED 1U
53*1208bc7eSAndroid Build Coastguard Worker #define LOG_ENABLED 2U
54*1208bc7eSAndroid Build Coastguard Worker
55*1208bc7eSAndroid Build Coastguard Worker #define LOG_VAR_INIT(name_str) {ATOMIC_INIT(LOG_NOT_INITIALIZED), name_str}
56*1208bc7eSAndroid Build Coastguard Worker
57*1208bc7eSAndroid Build Coastguard Worker /*
58*1208bc7eSAndroid Build Coastguard Worker * Returns the value we should assume for state (which is not necessarily
59*1208bc7eSAndroid Build Coastguard Worker * accurate; if logging is done before logging has finished initializing, then
60*1208bc7eSAndroid Build Coastguard Worker * we default to doing the safe thing by logging everything).
61*1208bc7eSAndroid Build Coastguard Worker */
62*1208bc7eSAndroid Build Coastguard Worker unsigned log_var_update_state(log_var_t *log_var);
63*1208bc7eSAndroid Build Coastguard Worker
64*1208bc7eSAndroid Build Coastguard Worker /* We factor out the metadata management to allow us to test more easily. */
65*1208bc7eSAndroid Build Coastguard Worker #define log_do_begin(log_var) \
66*1208bc7eSAndroid Build Coastguard Worker if (config_log) { \
67*1208bc7eSAndroid Build Coastguard Worker unsigned log_state = atomic_load_u(&(log_var).state, \
68*1208bc7eSAndroid Build Coastguard Worker ATOMIC_RELAXED); \
69*1208bc7eSAndroid Build Coastguard Worker if (unlikely(log_state == LOG_NOT_INITIALIZED)) { \
70*1208bc7eSAndroid Build Coastguard Worker log_state = log_var_update_state(&(log_var)); \
71*1208bc7eSAndroid Build Coastguard Worker assert(log_state != LOG_NOT_INITIALIZED); \
72*1208bc7eSAndroid Build Coastguard Worker } \
73*1208bc7eSAndroid Build Coastguard Worker if (log_state == LOG_ENABLED) { \
74*1208bc7eSAndroid Build Coastguard Worker {
75*1208bc7eSAndroid Build Coastguard Worker /* User code executes here. */
76*1208bc7eSAndroid Build Coastguard Worker #define log_do_end(log_var) \
77*1208bc7eSAndroid Build Coastguard Worker } \
78*1208bc7eSAndroid Build Coastguard Worker } \
79*1208bc7eSAndroid Build Coastguard Worker }
80*1208bc7eSAndroid Build Coastguard Worker
81*1208bc7eSAndroid Build Coastguard Worker /*
82*1208bc7eSAndroid Build Coastguard Worker * MSVC has some preprocessor bugs in its expansion of __VA_ARGS__ during
83*1208bc7eSAndroid Build Coastguard Worker * preprocessing. To work around this, we take all potential extra arguments in
84*1208bc7eSAndroid Build Coastguard Worker * a var-args functions. Since a varargs macro needs at least one argument in
85*1208bc7eSAndroid Build Coastguard Worker * the "...", we accept the format string there, and require that the first
86*1208bc7eSAndroid Build Coastguard Worker * argument in this "..." is a const char *.
87*1208bc7eSAndroid Build Coastguard Worker */
88*1208bc7eSAndroid Build Coastguard Worker static inline void
log_impl_varargs(const char * name,...)89*1208bc7eSAndroid Build Coastguard Worker log_impl_varargs(const char *name, ...) {
90*1208bc7eSAndroid Build Coastguard Worker char buf[JEMALLOC_LOG_BUFSIZE];
91*1208bc7eSAndroid Build Coastguard Worker va_list ap;
92*1208bc7eSAndroid Build Coastguard Worker
93*1208bc7eSAndroid Build Coastguard Worker va_start(ap, name);
94*1208bc7eSAndroid Build Coastguard Worker const char *format = va_arg(ap, const char *);
95*1208bc7eSAndroid Build Coastguard Worker size_t dst_offset = 0;
96*1208bc7eSAndroid Build Coastguard Worker dst_offset += malloc_snprintf(buf, JEMALLOC_LOG_BUFSIZE, "%s: ", name);
97*1208bc7eSAndroid Build Coastguard Worker dst_offset += malloc_vsnprintf(buf + dst_offset,
98*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_LOG_BUFSIZE - dst_offset, format, ap);
99*1208bc7eSAndroid Build Coastguard Worker dst_offset += malloc_snprintf(buf + dst_offset,
100*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_LOG_BUFSIZE - dst_offset, "\n");
101*1208bc7eSAndroid Build Coastguard Worker va_end(ap);
102*1208bc7eSAndroid Build Coastguard Worker
103*1208bc7eSAndroid Build Coastguard Worker malloc_write(buf);
104*1208bc7eSAndroid Build Coastguard Worker }
105*1208bc7eSAndroid Build Coastguard Worker
106*1208bc7eSAndroid Build Coastguard Worker /* Call as log("log.var.str", "format_string %d", arg_for_format_string); */
107*1208bc7eSAndroid Build Coastguard Worker #define LOG(log_var_str, ...) \
108*1208bc7eSAndroid Build Coastguard Worker do { \
109*1208bc7eSAndroid Build Coastguard Worker static log_var_t log_var = LOG_VAR_INIT(log_var_str); \
110*1208bc7eSAndroid Build Coastguard Worker log_do_begin(log_var) \
111*1208bc7eSAndroid Build Coastguard Worker log_impl_varargs((log_var).name, __VA_ARGS__); \
112*1208bc7eSAndroid Build Coastguard Worker log_do_end(log_var) \
113*1208bc7eSAndroid Build Coastguard Worker } while (0)
114*1208bc7eSAndroid Build Coastguard Worker
115*1208bc7eSAndroid Build Coastguard Worker #endif /* JEMALLOC_INTERNAL_LOG_H */
116