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