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