blob: a414bb9f120df6fa7acb96b77666259fb8f7222f [file] [log] [blame]
Jason Evans6109fe02010-02-10 10:37:56 -08001#define JEMALLOC_PROF_C_
Jason Evans376b1522010-02-11 14:45:59 -08002#include "jemalloc/internal/jemalloc_internal.h"
Jason Evans6109fe02010-02-10 10:37:56 -08003#ifdef JEMALLOC_PROF
4/******************************************************************************/
5
Jason Evansb27805b2010-02-10 18:15:53 -08006#ifdef JEMALLOC_PROF_LIBGCC
7#include <unwind.h>
8#endif
9
Jason Evans6109fe02010-02-10 10:37:56 -080010#ifdef JEMALLOC_PROF_LIBUNWIND
11#define UNW_LOCAL_ONLY
12#include <libunwind.h>
13#endif
14
Jason Evansb9477e72010-03-01 20:15:26 -080015#include <math.h>
16
Jason Evans6109fe02010-02-10 10:37:56 -080017/******************************************************************************/
18/* Data. */
19
20bool opt_prof = false;
Jason Evansf18c9822010-03-31 18:43:24 -070021bool opt_prof_active = true;
Jason Evansb9477e72010-03-01 20:15:26 -080022size_t opt_lg_prof_bt_max = LG_PROF_BT_MAX_DEFAULT;
23size_t opt_lg_prof_sample = LG_PROF_SAMPLE_DEFAULT;
Jason Evansa02fc082010-03-31 17:35:51 -070024ssize_t opt_lg_prof_interval = LG_PROF_INTERVAL_DEFAULT;
Jason Evans6109fe02010-02-10 10:37:56 -080025bool opt_prof_udump = false;
26bool opt_prof_leak = false;
27
Jason Evansd34f9e72010-02-11 13:19:21 -080028uint64_t prof_interval;
Jason Evans0b270a92010-03-31 16:45:04 -070029bool prof_promote;
Jason Evansd34f9e72010-02-11 13:19:21 -080030
Jason Evans6109fe02010-02-10 10:37:56 -080031/*
32 * Global hash of (prof_bt_t *)-->(prof_ctx_t *). This is the master data
33 * structure that knows about all backtraces ever captured.
34 */
35static ckh_t bt2ctx;
36static malloc_mutex_t bt2ctx_mtx;
37
38/*
39 * Thread-specific hash of (prof_bt_t *)-->(prof_thr_cnt_t *). Each thread
40 * keeps a cache of backtraces, with associated thread-specific prof_thr_cnt_t
41 * objects. Other threads may read the prof_thr_cnt_t contents, but no others
42 * will ever write them.
43 *
44 * Upon thread exit, the thread must merge all the prof_thr_cnt_t counter data
45 * into the associated prof_ctx_t objects, and unlink/free the prof_thr_cnt_t
46 * objects.
47 */
Jason Evans2dbecf12010-09-05 10:35:13 -070048#ifndef NO_TLS
Jason Evans6109fe02010-02-10 10:37:56 -080049static __thread ckh_t *bt2cnt_tls JEMALLOC_ATTR(tls_model("initial-exec"));
Jason Evans2dbecf12010-09-05 10:35:13 -070050# define BT2CNT_GET() bt2cnt_tls
51# define BT2CNT_SET(v) do { \
52 bt2cnt_tls = (v); \
53 pthread_setspecific(bt2cnt_tsd, (void *)(v)); \
54} while (0)
55#else
56# define BT2CNT_GET() ((ckh_t *)pthread_getspecific(bt2cnt_tsd))
57# define BT2CNT_SET(v) do { \
58 pthread_setspecific(bt2cnt_tsd, (void *)(v)); \
59} while (0)
60#endif
Jason Evans6109fe02010-02-10 10:37:56 -080061
62/*
Jason Evans50651562010-04-13 16:13:54 -070063 * Same contents as b2cnt_tls, but initialized such that the TSD destructor is
Jason Evans6109fe02010-02-10 10:37:56 -080064 * called when a thread exits, so that bt2cnt_tls contents can be merged,
65 * unlinked, and deallocated.
66 */
67static pthread_key_t bt2cnt_tsd;
68
69/* (1U << opt_lg_prof_bt_max). */
70static unsigned prof_bt_max;
71
Jason Evans2dbecf12010-09-05 10:35:13 -070072typedef struct prof_sample_state_s prof_sample_state_t;
73struct prof_sample_state_s {
74 uint64_t prn_state;
75 uint64_t threshold;
76 uint64_t accum;
77};
78
79#ifndef NO_TLS
80static __thread prof_sample_state_t prof_sample_state_tls
Jason Evansb9477e72010-03-01 20:15:26 -080081 JEMALLOC_ATTR(tls_model("initial-exec"));
Jason Evans2dbecf12010-09-05 10:35:13 -070082# define PROF_SAMPLE_STATE_GET(r) do { \
83 r = &prof_sample_state_tls; \
84} while (0)
85#else
86static pthread_key_t prof_sample_state_tsd;
87/* Used only if an OOM error occurs in PROF_SAMPLE_STATE_GET(). */
88prof_sample_state_t prof_sample_state_oom;
89# define PROF_SAMPLE_STATE_GET(r) do { \
90 r = (prof_sample_state_t *)pthread_getspecific( \
91 prof_sample_state_tsd); \
92 if (r == NULL) { \
Jason Evans8e3c3c62010-09-17 15:46:18 -070093 r = ipalloc(sizeof(prof_sample_state_t), CACHELINE); \
Jason Evans2dbecf12010-09-05 10:35:13 -070094 if (r == NULL) { \
95 malloc_write("<jemalloc>: Error in heap " \
96 "profiler: out of memory; subsequent heap " \
97 "profiles may be inaccurate\n"); \
98 if (opt_abort) \
99 abort(); \
100 /* Failure is not an option... */ \
101 r = &prof_sample_state_oom; \
102 } \
103 pthread_setspecific(prof_sample_state_tsd, (void *)r); \
104 } \
105} while (0)
106# define ARENA_GET() ((arena_t *)pthread_getspecific(arenas_tsd))
107# define ARENA_SET(v) do { \
108 pthread_setspecific(arenas_tsd, (void *)(v)); \
109} while (0)
110#endif
Jason Evansb9477e72010-03-01 20:15:26 -0800111
Jason Evans6109fe02010-02-10 10:37:56 -0800112static malloc_mutex_t prof_dump_seq_mtx;
113static uint64_t prof_dump_seq;
114static uint64_t prof_dump_iseq;
115static uint64_t prof_dump_mseq;
116static uint64_t prof_dump_useq;
117
118/*
119 * This buffer is rather large for stack allocation, so use a single buffer for
120 * all profile dumps. The buffer is implicitly protected by bt2ctx_mtx, since
121 * it must be locked anyway during dumping.
122 */
123static char prof_dump_buf[PROF_DUMP_BUF_SIZE];
124static unsigned prof_dump_buf_end;
125static int prof_dump_fd;
126
127/* Do not dump any profiles until bootstrapping is complete. */
128static bool prof_booted = false;
129
130static malloc_mutex_t enq_mtx;
131static bool enq;
Jason Evansd34f9e72010-02-11 13:19:21 -0800132static bool enq_idump;
Jason Evans6109fe02010-02-10 10:37:56 -0800133static bool enq_udump;
134
135/******************************************************************************/
136/* Function prototypes for non-inline static functions. */
137
138static prof_bt_t *bt_dup(prof_bt_t *bt);
139static void bt_init(prof_bt_t *bt, void **vec);
Jason Evansb27805b2010-02-10 18:15:53 -0800140#ifdef JEMALLOC_PROF_LIBGCC
141static _Unwind_Reason_Code prof_unwind_init_callback(
142 struct _Unwind_Context *context, void *arg);
143static _Unwind_Reason_Code prof_unwind_callback(
144 struct _Unwind_Context *context, void *arg);
145#endif
146static void prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max);
Jason Evans6109fe02010-02-10 10:37:56 -0800147static prof_thr_cnt_t *prof_lookup(prof_bt_t *bt);
Jason Evans50651562010-04-13 16:13:54 -0700148static void prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
Jason Evans22ca8552010-03-02 11:57:30 -0800149static bool prof_flush(bool propagate_err);
150static bool prof_write(const char *s, bool propagate_err);
Jason Evans6109fe02010-02-10 10:37:56 -0800151static void prof_ctx_merge(prof_ctx_t *ctx, prof_cnt_t *cnt_all,
152 size_t *leak_nctx);
Jason Evans22ca8552010-03-02 11:57:30 -0800153static bool prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt,
154 bool propagate_err);
155static bool prof_dump_maps(bool propagate_err);
156static bool prof_dump(const char *filename, bool leakcheck,
157 bool propagate_err);
Jason Evans6109fe02010-02-10 10:37:56 -0800158static void prof_dump_filename(char *filename, char v, int64_t vseq);
159static void prof_fdump(void);
160static void prof_bt_hash(const void *key, unsigned minbits, size_t *hash1,
161 size_t *hash2);
162static bool prof_bt_keycomp(const void *k1, const void *k2);
163static void bt2cnt_thread_cleanup(void *arg);
Jason Evans2dbecf12010-09-05 10:35:13 -0700164#ifdef NO_TLS
165static void prof_sample_state_thread_cleanup(void *arg);
166#endif
Jason Evans6109fe02010-02-10 10:37:56 -0800167
168/******************************************************************************/
169
170static void
171bt_init(prof_bt_t *bt, void **vec)
172{
173
174 bt->vec = vec;
175 bt->len = 0;
176}
177
178static prof_bt_t *
179bt_dup(prof_bt_t *bt)
180{
181 prof_bt_t *ret;
182
183 /*
184 * Create a single allocation that has space for vec immediately
185 * following the prof_bt_t structure. The backtraces that get
186 * stored in the backtrace caches are copied from stack-allocated
187 * temporary variables, so size is known at creation time. Making this
188 * a contiguous object improves cache locality.
189 */
190 ret = (prof_bt_t *)imalloc(QUANTUM_CEILING(sizeof(prof_bt_t)) +
191 (bt->len * sizeof(void *)));
192 if (ret == NULL)
193 return (NULL);
194 ret->vec = (void **)((uintptr_t)ret +
195 QUANTUM_CEILING(sizeof(prof_bt_t)));
196 memcpy(ret->vec, bt->vec, bt->len * sizeof(void *));
197 ret->len = bt->len;
198
199 return (ret);
200}
201
202static inline void
203prof_enter(void)
204{
205
206 malloc_mutex_lock(&enq_mtx);
207 enq = true;
208 malloc_mutex_unlock(&enq_mtx);
209
210 malloc_mutex_lock(&bt2ctx_mtx);
211}
212
213static inline void
214prof_leave(void)
215{
Jason Evansd34f9e72010-02-11 13:19:21 -0800216 bool idump, udump;
Jason Evans6109fe02010-02-10 10:37:56 -0800217
218 malloc_mutex_unlock(&bt2ctx_mtx);
219
220 malloc_mutex_lock(&enq_mtx);
221 enq = false;
Jason Evansd34f9e72010-02-11 13:19:21 -0800222 idump = enq_idump;
223 enq_idump = false;
Jason Evans6109fe02010-02-10 10:37:56 -0800224 udump = enq_udump;
225 enq_udump = false;
226 malloc_mutex_unlock(&enq_mtx);
227
Jason Evansd34f9e72010-02-11 13:19:21 -0800228 if (idump)
229 prof_idump();
Jason Evans6109fe02010-02-10 10:37:56 -0800230 if (udump)
231 prof_udump();
232}
233
Jason Evansb27805b2010-02-10 18:15:53 -0800234#ifdef JEMALLOC_PROF_LIBGCC
235static _Unwind_Reason_Code
236prof_unwind_init_callback(struct _Unwind_Context *context, void *arg)
237{
238
239 return (_URC_NO_REASON);
240}
241
242static _Unwind_Reason_Code
243prof_unwind_callback(struct _Unwind_Context *context, void *arg)
244{
245 prof_unwind_data_t *data = (prof_unwind_data_t *)arg;
246
247 if (data->nignore > 0)
248 data->nignore--;
249 else {
250 data->bt->vec[data->bt->len] = (void *)_Unwind_GetIP(context);
251 data->bt->len++;
252 if (data->bt->len == data->max)
253 return (_URC_END_OF_STACK);
254 }
255
256 return (_URC_NO_REASON);
257}
258
259static void
260prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
261{
262 prof_unwind_data_t data = {bt, nignore, max};
263
264 _Unwind_Backtrace(prof_unwind_callback, &data);
265}
266#elif defined(JEMALLOC_PROF_LIBUNWIND)
267static void
Jason Evans6109fe02010-02-10 10:37:56 -0800268prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
269{
270 unw_context_t uc;
271 unw_cursor_t cursor;
272 unsigned i;
273 int err;
274
275 assert(bt->len == 0);
276 assert(bt->vec != NULL);
277 assert(max <= (1U << opt_lg_prof_bt_max));
278
279 unw_getcontext(&uc);
280 unw_init_local(&cursor, &uc);
281
282 /* Throw away (nignore+1) stack frames, if that many exist. */
283 for (i = 0; i < nignore + 1; i++) {
284 err = unw_step(&cursor);
285 if (err <= 0)
Jason Evansb27805b2010-02-10 18:15:53 -0800286 return;
Jason Evans6109fe02010-02-10 10:37:56 -0800287 }
288
289 /*
Jason Evansb43b7752010-06-04 15:10:43 -0700290 * Iterate over stack frames until there are no more, or until no space
291 * remains in bt.
Jason Evans6109fe02010-02-10 10:37:56 -0800292 */
293 for (i = 0; i < max; i++) {
294 unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *)&bt->vec[i]);
Jason Evansb43b7752010-06-04 15:10:43 -0700295 bt->len++;
Jason Evans6109fe02010-02-10 10:37:56 -0800296 err = unw_step(&cursor);
Jason Evansb43b7752010-06-04 15:10:43 -0700297 if (err <= 0)
Jason Evans6109fe02010-02-10 10:37:56 -0800298 break;
Jason Evans6109fe02010-02-10 10:37:56 -0800299 }
Jason Evans6109fe02010-02-10 10:37:56 -0800300}
301#else
Jason Evansb27805b2010-02-10 18:15:53 -0800302static void
Jason Evans6109fe02010-02-10 10:37:56 -0800303prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
304{
305#define NIGNORE 3
306#define BT_FRAME(i) \
307 if ((i) < NIGNORE + max) { \
308 void *p; \
309 if (__builtin_frame_address(i) == 0) \
Jason Evansb27805b2010-02-10 18:15:53 -0800310 return; \
Jason Evans6109fe02010-02-10 10:37:56 -0800311 p = __builtin_return_address(i); \
312 if (p == NULL) \
Jason Evansb27805b2010-02-10 18:15:53 -0800313 return; \
Jason Evans6109fe02010-02-10 10:37:56 -0800314 if (i >= NIGNORE) { \
315 bt->vec[(i) - NIGNORE] = p; \
316 bt->len = (i) - NIGNORE + 1; \
317 } \
318 } else \
Jason Evansb27805b2010-02-10 18:15:53 -0800319 return;
Jason Evans6109fe02010-02-10 10:37:56 -0800320
321 assert(max <= (1U << opt_lg_prof_bt_max));
322
323 /*
324 * Ignore the first three frames, since they are:
325 *
326 * 0: prof_backtrace()
327 * 1: prof_alloc_prep()
328 * 2: malloc(), calloc(), etc.
329 */
330#if 1
331 assert(nignore + 1 == NIGNORE);
332#else
333 BT_FRAME(0)
334 BT_FRAME(1)
335 BT_FRAME(2)
336#endif
337 BT_FRAME(3)
338 BT_FRAME(4)
339 BT_FRAME(5)
340 BT_FRAME(6)
341 BT_FRAME(7)
342 BT_FRAME(8)
343 BT_FRAME(9)
344
345 BT_FRAME(10)
346 BT_FRAME(11)
347 BT_FRAME(12)
348 BT_FRAME(13)
349 BT_FRAME(14)
350 BT_FRAME(15)
351 BT_FRAME(16)
352 BT_FRAME(17)
353 BT_FRAME(18)
354 BT_FRAME(19)
355
356 BT_FRAME(20)
357 BT_FRAME(21)
358 BT_FRAME(22)
359 BT_FRAME(23)
360 BT_FRAME(24)
361 BT_FRAME(25)
362 BT_FRAME(26)
363 BT_FRAME(27)
364 BT_FRAME(28)
365 BT_FRAME(29)
366
367 BT_FRAME(30)
368 BT_FRAME(31)
369 BT_FRAME(32)
370 BT_FRAME(33)
371 BT_FRAME(34)
372 BT_FRAME(35)
373 BT_FRAME(36)
374 BT_FRAME(37)
375 BT_FRAME(38)
376 BT_FRAME(39)
377
378 BT_FRAME(40)
379 BT_FRAME(41)
380 BT_FRAME(42)
381 BT_FRAME(43)
382 BT_FRAME(44)
383 BT_FRAME(45)
384 BT_FRAME(46)
385 BT_FRAME(47)
386 BT_FRAME(48)
387 BT_FRAME(49)
388
389 BT_FRAME(50)
390 BT_FRAME(51)
391 BT_FRAME(52)
392 BT_FRAME(53)
393 BT_FRAME(54)
394 BT_FRAME(55)
395 BT_FRAME(56)
396 BT_FRAME(57)
397 BT_FRAME(58)
398 BT_FRAME(59)
399
400 BT_FRAME(60)
401 BT_FRAME(61)
402 BT_FRAME(62)
403 BT_FRAME(63)
404 BT_FRAME(64)
405 BT_FRAME(65)
406 BT_FRAME(66)
407 BT_FRAME(67)
408 BT_FRAME(68)
409 BT_FRAME(69)
410
411 BT_FRAME(70)
412 BT_FRAME(71)
413 BT_FRAME(72)
414 BT_FRAME(73)
415 BT_FRAME(74)
416 BT_FRAME(75)
417 BT_FRAME(76)
418 BT_FRAME(77)
419 BT_FRAME(78)
420 BT_FRAME(79)
421
422 BT_FRAME(80)
423 BT_FRAME(81)
424 BT_FRAME(82)
425 BT_FRAME(83)
426 BT_FRAME(84)
427 BT_FRAME(85)
428 BT_FRAME(86)
429 BT_FRAME(87)
430 BT_FRAME(88)
431 BT_FRAME(89)
432
433 BT_FRAME(90)
434 BT_FRAME(91)
435 BT_FRAME(92)
436 BT_FRAME(93)
437 BT_FRAME(94)
438 BT_FRAME(95)
439 BT_FRAME(96)
440 BT_FRAME(97)
441 BT_FRAME(98)
442 BT_FRAME(99)
443
444 BT_FRAME(100)
445 BT_FRAME(101)
446 BT_FRAME(102)
447 BT_FRAME(103)
448 BT_FRAME(104)
449 BT_FRAME(105)
450 BT_FRAME(106)
451 BT_FRAME(107)
452 BT_FRAME(108)
453 BT_FRAME(109)
454
455 BT_FRAME(110)
456 BT_FRAME(111)
457 BT_FRAME(112)
458 BT_FRAME(113)
459 BT_FRAME(114)
460 BT_FRAME(115)
461 BT_FRAME(116)
462 BT_FRAME(117)
463 BT_FRAME(118)
464 BT_FRAME(119)
465
466 BT_FRAME(120)
467 BT_FRAME(121)
468 BT_FRAME(122)
469 BT_FRAME(123)
470 BT_FRAME(124)
471 BT_FRAME(125)
472 BT_FRAME(126)
473 BT_FRAME(127)
474
475 /* Extras to compensate for NIGNORE. */
476 BT_FRAME(128)
477 BT_FRAME(129)
478 BT_FRAME(130)
Jason Evans6109fe02010-02-10 10:37:56 -0800479#undef BT_FRAME
Jason Evans6109fe02010-02-10 10:37:56 -0800480}
481#endif
482
483static prof_thr_cnt_t *
484prof_lookup(prof_bt_t *bt)
485{
486 prof_thr_cnt_t *ret;
Jason Evans2dbecf12010-09-05 10:35:13 -0700487 ckh_t *bt2cnt = BT2CNT_GET();
Jason Evans6109fe02010-02-10 10:37:56 -0800488
489 if (bt2cnt == NULL) {
490 /* Initialize an empty cache for this thread. */
491 bt2cnt = (ckh_t *)imalloc(sizeof(ckh_t));
492 if (bt2cnt == NULL)
493 return (NULL);
494 if (ckh_new(bt2cnt, PROF_CKH_MINITEMS, prof_bt_hash,
495 prof_bt_keycomp)) {
496 idalloc(bt2cnt);
497 return (NULL);
498 }
Jason Evans2dbecf12010-09-05 10:35:13 -0700499
500 BT2CNT_SET(bt2cnt);
Jason Evans6109fe02010-02-10 10:37:56 -0800501 }
502
503 if (ckh_search(bt2cnt, bt, NULL, (void **)&ret)) {
504 prof_bt_t *btkey;
505 prof_ctx_t *ctx;
506
507 /*
508 * This thread's cache lacks bt. Look for it in the global
509 * cache.
510 */
511 prof_enter();
512 if (ckh_search(&bt2ctx, bt, (void **)&btkey, (void **)&ctx)) {
513
514 /* bt has never been seen before. Insert it. */
515 ctx = (prof_ctx_t *)imalloc(sizeof(prof_ctx_t));
516 if (ctx == NULL) {
517 prof_leave();
518 return (NULL);
519 }
520 btkey = bt_dup(bt);
521 if (btkey == NULL) {
522 prof_leave();
523 idalloc(ctx);
524 return (NULL);
525 }
Jason Evans50651562010-04-13 16:13:54 -0700526 ctx->bt = btkey;
Jason Evans6109fe02010-02-10 10:37:56 -0800527 if (malloc_mutex_init(&ctx->lock)) {
528 prof_leave();
529 idalloc(btkey);
530 idalloc(ctx);
531 return (NULL);
532 }
533 memset(&ctx->cnt_merged, 0, sizeof(prof_cnt_t));
534 ql_new(&ctx->cnts_ql);
535 if (ckh_insert(&bt2ctx, btkey, ctx)) {
536 /* OOM. */
537 prof_leave();
538 idalloc(btkey);
539 idalloc(ctx);
540 return (NULL);
541 }
542 }
543 prof_leave();
544
545 /* Link a prof_thd_cnt_t into ctx for this thread. */
546 ret = (prof_thr_cnt_t *)imalloc(sizeof(prof_thr_cnt_t));
547 if (ret == NULL)
548 return (NULL);
549 ql_elm_new(ret, link);
550 ret->ctx = ctx;
551 ret->epoch = 0;
552 memset(&ret->cnts, 0, sizeof(prof_cnt_t));
553 if (ckh_insert(bt2cnt, btkey, ret)) {
554 idalloc(ret);
555 return (NULL);
556 }
557 malloc_mutex_lock(&ctx->lock);
558 ql_tail_insert(&ctx->cnts_ql, ret, link);
559 malloc_mutex_unlock(&ctx->lock);
560 }
561
562 return (ret);
563}
564
Jason Evans9df02152010-03-03 11:53:11 -0800565static inline void
566prof_sample_threshold_update(void)
567{
568 uint64_t r;
569 double u;
Jason Evans2dbecf12010-09-05 10:35:13 -0700570 prof_sample_state_t *prof_sample_state;
Jason Evans9df02152010-03-03 11:53:11 -0800571
572 /*
573 * Compute prof_sample_threshold as a geometrically distributed random
574 * variable with mean (2^opt_lg_prof_sample).
575 */
Jason Evans2dbecf12010-09-05 10:35:13 -0700576 PROF_SAMPLE_STATE_GET(prof_sample_state);
577 prn64(r, 53, prof_sample_state->prn_state,
578 (uint64_t)1125899906842625LLU, 1058392653243283975);
Jason Evans9df02152010-03-03 11:53:11 -0800579 u = (double)r * (1.0/9007199254740992.0L);
Jason Evans2dbecf12010-09-05 10:35:13 -0700580 prof_sample_state->threshold = (uint64_t)(log(u) /
Jason Evans9df02152010-03-03 11:53:11 -0800581 log(1.0 - (1.0 / (double)((uint64_t)1U << opt_lg_prof_sample))))
582 + (uint64_t)1U;
583}
584
Jason Evans6109fe02010-02-10 10:37:56 -0800585prof_thr_cnt_t *
Jason Evansb9477e72010-03-01 20:15:26 -0800586prof_alloc_prep(size_t size)
Jason Evans6109fe02010-02-10 10:37:56 -0800587{
588 prof_thr_cnt_t *ret;
589 void *vec[prof_bt_max];
590 prof_bt_t bt;
591
Jason Evansf18c9822010-03-31 18:43:24 -0700592 if (opt_prof_active == false) {
593 /* Sampling is currently inactive, so avoid sampling. */
594 ret = (prof_thr_cnt_t *)(uintptr_t)1U;
595 } else if (opt_lg_prof_sample == 0) {
Jason Evans9df02152010-03-03 11:53:11 -0800596 /*
597 * Don't bother with sampling logic, since sampling interval is
598 * 1.
599 */
Jason Evansb9477e72010-03-01 20:15:26 -0800600 bt_init(&bt, vec);
601 prof_backtrace(&bt, 2, prof_bt_max);
602 ret = prof_lookup(&bt);
Jason Evans9df02152010-03-03 11:53:11 -0800603 } else {
Jason Evans2dbecf12010-09-05 10:35:13 -0700604 prof_sample_state_t *prof_sample_state;
605
606 PROF_SAMPLE_STATE_GET(prof_sample_state);
607 if (prof_sample_state->threshold == 0) {
Jason Evans9df02152010-03-03 11:53:11 -0800608 /*
609 * Initialize. Seed the prng differently for each
610 * thread.
611 */
Jason Evans2dbecf12010-09-05 10:35:13 -0700612 prof_sample_state->prn_state =
613 (uint64_t)(uintptr_t)&size;
Jason Evans9df02152010-03-03 11:53:11 -0800614 prof_sample_threshold_update();
615 }
616
617 /*
618 * Determine whether to capture a backtrace based on whether
619 * size is enough for prof_accum to reach
Jason Evans2dbecf12010-09-05 10:35:13 -0700620 * prof_sample_state->threshold. However, delay updating these
Jason Evans9df02152010-03-03 11:53:11 -0800621 * variables until prof_{m,re}alloc(), because we don't know
622 * for sure that the allocation will succeed.
623 *
624 * Use subtraction rather than addition to avoid potential
625 * integer overflow.
626 */
Jason Evans2dbecf12010-09-05 10:35:13 -0700627 if (size >= prof_sample_state->threshold -
628 prof_sample_state->accum) {
Jason Evans9df02152010-03-03 11:53:11 -0800629 bt_init(&bt, vec);
630 prof_backtrace(&bt, 2, prof_bt_max);
631 ret = prof_lookup(&bt);
632 } else
633 ret = (prof_thr_cnt_t *)(uintptr_t)1U;
634 }
Jason Evans6109fe02010-02-10 10:37:56 -0800635
636 return (ret);
637}
638
Jason Evans50651562010-04-13 16:13:54 -0700639prof_ctx_t *
640prof_ctx_get(const void *ptr)
Jason Evans6109fe02010-02-10 10:37:56 -0800641{
Jason Evans50651562010-04-13 16:13:54 -0700642 prof_ctx_t *ret;
Jason Evans6109fe02010-02-10 10:37:56 -0800643 arena_chunk_t *chunk;
644
645 assert(ptr != NULL);
646
647 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
648 if (chunk != ptr) {
649 /* Region. */
650 assert(chunk->arena->magic == ARENA_MAGIC);
651
Jason Evans50651562010-04-13 16:13:54 -0700652 ret = arena_prof_ctx_get(ptr);
Jason Evans6109fe02010-02-10 10:37:56 -0800653 } else
Jason Evans50651562010-04-13 16:13:54 -0700654 ret = huge_prof_ctx_get(ptr);
Jason Evans6109fe02010-02-10 10:37:56 -0800655
656 return (ret);
657}
658
659static void
Jason Evans50651562010-04-13 16:13:54 -0700660prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
Jason Evans6109fe02010-02-10 10:37:56 -0800661{
662 arena_chunk_t *chunk;
663
664 assert(ptr != NULL);
665
666 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
667 if (chunk != ptr) {
668 /* Region. */
669 assert(chunk->arena->magic == ARENA_MAGIC);
670
Jason Evans50651562010-04-13 16:13:54 -0700671 arena_prof_ctx_set(ptr, ctx);
Jason Evans6109fe02010-02-10 10:37:56 -0800672 } else
Jason Evans50651562010-04-13 16:13:54 -0700673 huge_prof_ctx_set(ptr, ctx);
Jason Evans6109fe02010-02-10 10:37:56 -0800674}
675
Jason Evansb9477e72010-03-01 20:15:26 -0800676static inline void
Jason Evansb9477e72010-03-01 20:15:26 -0800677prof_sample_accum_update(size_t size)
678{
Jason Evans2dbecf12010-09-05 10:35:13 -0700679 prof_sample_state_t *prof_sample_state;
Jason Evansb9477e72010-03-01 20:15:26 -0800680
Jason Evans7013d102010-05-11 18:17:02 -0700681 /* Sampling logic is unnecessary if the interval is 1. */
682 assert(opt_lg_prof_sample != 0);
Jason Evansb9477e72010-03-01 20:15:26 -0800683
Jason Evansb9477e72010-03-01 20:15:26 -0800684 /* Take care to avoid integer overflow. */
Jason Evans2dbecf12010-09-05 10:35:13 -0700685 PROF_SAMPLE_STATE_GET(prof_sample_state);
686 if (size >= prof_sample_state->threshold - prof_sample_state->accum) {
687 prof_sample_state->accum -= (prof_sample_state->threshold -
688 size);
Jason Evans9df02152010-03-03 11:53:11 -0800689 /* Compute new prof_sample_threshold. */
Jason Evansb9477e72010-03-01 20:15:26 -0800690 prof_sample_threshold_update();
Jason Evans2dbecf12010-09-05 10:35:13 -0700691 while (prof_sample_state->accum >=
692 prof_sample_state->threshold) {
693 prof_sample_state->accum -=
694 prof_sample_state->threshold;
Jason Evansb9477e72010-03-01 20:15:26 -0800695 prof_sample_threshold_update();
696 }
697 } else
Jason Evans2dbecf12010-09-05 10:35:13 -0700698 prof_sample_state->accum += size;
Jason Evansb9477e72010-03-01 20:15:26 -0800699}
700
Jason Evans6109fe02010-02-10 10:37:56 -0800701void
702prof_malloc(const void *ptr, prof_thr_cnt_t *cnt)
703{
Jason Evans7013d102010-05-11 18:17:02 -0700704 size_t size;
Jason Evans6109fe02010-02-10 10:37:56 -0800705
Jason Evansb9477e72010-03-01 20:15:26 -0800706 assert(ptr != NULL);
Jason Evans6109fe02010-02-10 10:37:56 -0800707
Jason Evans7013d102010-05-11 18:17:02 -0700708 if (opt_lg_prof_sample != 0) {
709 size = isalloc(ptr);
710 prof_sample_accum_update(size);
711 } else if ((uintptr_t)cnt > (uintptr_t)1U)
712 size = isalloc(ptr);
Jason Evansb9477e72010-03-01 20:15:26 -0800713
714 if ((uintptr_t)cnt > (uintptr_t)1U) {
Jason Evans38cda692010-04-14 11:24:45 -0700715 prof_ctx_set(ptr, cnt->ctx);
716
Jason Evansb9477e72010-03-01 20:15:26 -0800717 cnt->epoch++;
718 /*********/
719 mb_write();
720 /*********/
721 cnt->cnts.curobjs++;
722 cnt->cnts.curbytes += size;
723 cnt->cnts.accumobjs++;
724 cnt->cnts.accumbytes += size;
725 /*********/
726 mb_write();
727 /*********/
728 cnt->epoch++;
729 /*********/
730 mb_write();
731 /*********/
Jason Evans38cda692010-04-14 11:24:45 -0700732 } else
733 prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
Jason Evans6109fe02010-02-10 10:37:56 -0800734}
735
736void
737prof_realloc(const void *ptr, prof_thr_cnt_t *cnt, const void *old_ptr,
Jason Evans50651562010-04-13 16:13:54 -0700738 size_t old_size, prof_ctx_t *old_ctx)
Jason Evans6109fe02010-02-10 10:37:56 -0800739{
Jason Evans355b4382010-09-20 19:20:48 -0700740 size_t size
741#ifdef JEMALLOC_CC_SILENCE
742 = 0
743#endif
744 ;
Jason Evans50651562010-04-13 16:13:54 -0700745 prof_thr_cnt_t *told_cnt;
Jason Evans6109fe02010-02-10 10:37:56 -0800746
Jason Evans7013d102010-05-11 18:17:02 -0700747 assert(ptr != NULL || (uintptr_t)cnt <= (uintptr_t)1U);
748
749 if (ptr != NULL) {
750 if (opt_lg_prof_sample != 0) {
751 size = isalloc(ptr);
752 prof_sample_accum_update(size);
753 } else if ((uintptr_t)cnt > (uintptr_t)1U)
754 size = isalloc(ptr);
755 }
Jason Evans6109fe02010-02-10 10:37:56 -0800756
Jason Evans50651562010-04-13 16:13:54 -0700757 if ((uintptr_t)old_ctx > (uintptr_t)1U) {
758 told_cnt = prof_lookup(old_ctx->bt);
759 if (told_cnt == NULL) {
760 /*
761 * It's too late to propagate OOM for this realloc(),
762 * so operate directly on old_cnt->ctx->cnt_merged.
763 */
Jason Evans50651562010-04-13 16:13:54 -0700764 malloc_mutex_lock(&old_ctx->lock);
765 old_ctx->cnt_merged.curobjs--;
766 old_ctx->cnt_merged.curbytes -= old_size;
767 malloc_mutex_unlock(&old_ctx->lock);
768 told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
769 }
770 } else
771 told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
772
773 if ((uintptr_t)told_cnt > (uintptr_t)1U)
774 told_cnt->epoch++;
Jason Evans38cda692010-04-14 11:24:45 -0700775 if ((uintptr_t)cnt > (uintptr_t)1U) {
776 prof_ctx_set(ptr, cnt->ctx);
Jason Evans6109fe02010-02-10 10:37:56 -0800777 cnt->epoch++;
Jason Evans38cda692010-04-14 11:24:45 -0700778 } else
779 prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
Jason Evans6109fe02010-02-10 10:37:56 -0800780 /*********/
781 mb_write();
782 /*********/
Jason Evans50651562010-04-13 16:13:54 -0700783 if ((uintptr_t)told_cnt > (uintptr_t)1U) {
784 told_cnt->cnts.curobjs--;
785 told_cnt->cnts.curbytes -= old_size;
Jason Evans6109fe02010-02-10 10:37:56 -0800786 }
Jason Evansb9477e72010-03-01 20:15:26 -0800787 if ((uintptr_t)cnt > (uintptr_t)1U) {
Jason Evans6109fe02010-02-10 10:37:56 -0800788 cnt->cnts.curobjs++;
789 cnt->cnts.curbytes += size;
790 cnt->cnts.accumobjs++;
791 cnt->cnts.accumbytes += size;
792 }
793 /*********/
794 mb_write();
795 /*********/
Jason Evans50651562010-04-13 16:13:54 -0700796 if ((uintptr_t)told_cnt > (uintptr_t)1U)
797 told_cnt->epoch++;
Jason Evansb9477e72010-03-01 20:15:26 -0800798 if ((uintptr_t)cnt > (uintptr_t)1U)
Jason Evans6109fe02010-02-10 10:37:56 -0800799 cnt->epoch++;
800 /*********/
801 mb_write(); /* Not strictly necessary. */
802}
803
804void
805prof_free(const void *ptr)
806{
Jason Evans50651562010-04-13 16:13:54 -0700807 prof_ctx_t *ctx = prof_ctx_get(ptr);
Jason Evans6109fe02010-02-10 10:37:56 -0800808
Jason Evans50651562010-04-13 16:13:54 -0700809 if ((uintptr_t)ctx > (uintptr_t)1) {
Jason Evansb9477e72010-03-01 20:15:26 -0800810 size_t size = isalloc(ptr);
Jason Evans50651562010-04-13 16:13:54 -0700811 prof_thr_cnt_t *tcnt = prof_lookup(ctx->bt);
Jason Evansb9477e72010-03-01 20:15:26 -0800812
Jason Evans50651562010-04-13 16:13:54 -0700813 if (tcnt != NULL) {
814 tcnt->epoch++;
815 /*********/
816 mb_write();
817 /*********/
818 tcnt->cnts.curobjs--;
819 tcnt->cnts.curbytes -= size;
820 /*********/
821 mb_write();
822 /*********/
823 tcnt->epoch++;
824 /*********/
825 mb_write();
826 /*********/
827 } else {
828 /*
829 * OOM during free() cannot be propagated, so operate
830 * directly on cnt->ctx->cnt_merged.
831 */
Jason Evans50651562010-04-13 16:13:54 -0700832 malloc_mutex_lock(&ctx->lock);
833 ctx->cnt_merged.curobjs--;
834 ctx->cnt_merged.curbytes -= size;
835 malloc_mutex_unlock(&ctx->lock);
836 }
Jason Evansb9477e72010-03-01 20:15:26 -0800837 }
Jason Evans6109fe02010-02-10 10:37:56 -0800838}
839
Jason Evans22ca8552010-03-02 11:57:30 -0800840static bool
841prof_flush(bool propagate_err)
Jason Evans6109fe02010-02-10 10:37:56 -0800842{
Jason Evans22ca8552010-03-02 11:57:30 -0800843 bool ret = false;
Jason Evans6109fe02010-02-10 10:37:56 -0800844 ssize_t err;
845
846 err = write(prof_dump_fd, prof_dump_buf, prof_dump_buf_end);
847 if (err == -1) {
Jason Evans22ca8552010-03-02 11:57:30 -0800848 if (propagate_err == false) {
Jason Evans698805c2010-03-03 17:45:38 -0800849 malloc_write("<jemalloc>: write() failed during heap "
850 "profile flush\n");
Jason Evans22ca8552010-03-02 11:57:30 -0800851 if (opt_abort)
852 abort();
853 }
854 ret = true;
Jason Evans6109fe02010-02-10 10:37:56 -0800855 }
856 prof_dump_buf_end = 0;
Jason Evans22ca8552010-03-02 11:57:30 -0800857
858 return (ret);
Jason Evans6109fe02010-02-10 10:37:56 -0800859}
860
Jason Evans22ca8552010-03-02 11:57:30 -0800861static bool
862prof_write(const char *s, bool propagate_err)
Jason Evans6109fe02010-02-10 10:37:56 -0800863{
864 unsigned i, slen, n;
865
866 i = 0;
867 slen = strlen(s);
868 while (i < slen) {
869 /* Flush the buffer if it is full. */
870 if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE)
Jason Evans22ca8552010-03-02 11:57:30 -0800871 if (prof_flush(propagate_err) && propagate_err)
872 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -0800873
874 if (prof_dump_buf_end + slen <= PROF_DUMP_BUF_SIZE) {
875 /* Finish writing. */
876 n = slen - i;
877 } else {
878 /* Write as much of s as will fit. */
879 n = PROF_DUMP_BUF_SIZE - prof_dump_buf_end;
880 }
881 memcpy(&prof_dump_buf[prof_dump_buf_end], &s[i], n);
882 prof_dump_buf_end += n;
883 i += n;
884 }
Jason Evans22ca8552010-03-02 11:57:30 -0800885
886 return (false);
Jason Evans6109fe02010-02-10 10:37:56 -0800887}
888
889static void
890prof_ctx_merge(prof_ctx_t *ctx, prof_cnt_t *cnt_all, size_t *leak_nctx)
891{
892 prof_thr_cnt_t *thr_cnt;
893 prof_cnt_t tcnt;
894
895 malloc_mutex_lock(&ctx->lock);
896
897 memcpy(&ctx->cnt_dump, &ctx->cnt_merged, sizeof(prof_cnt_t));
898 ql_foreach(thr_cnt, &ctx->cnts_ql, link) {
899 volatile unsigned *epoch = &thr_cnt->epoch;
900
901 while (true) {
902 unsigned epoch0 = *epoch;
903
904 /* Make sure epoch is even. */
905 if (epoch0 & 1U)
906 continue;
907
908 memcpy(&tcnt, &thr_cnt->cnts, sizeof(prof_cnt_t));
909
910 /* Terminate if epoch didn't change while reading. */
911 if (*epoch == epoch0)
912 break;
913 }
914
915 ctx->cnt_dump.curobjs += tcnt.curobjs;
916 ctx->cnt_dump.curbytes += tcnt.curbytes;
917 ctx->cnt_dump.accumobjs += tcnt.accumobjs;
918 ctx->cnt_dump.accumbytes += tcnt.accumbytes;
919
920 if (tcnt.curobjs != 0)
921 (*leak_nctx)++;
922 }
923
924 /* Merge into cnt_all. */
925 cnt_all->curobjs += ctx->cnt_dump.curobjs;
926 cnt_all->curbytes += ctx->cnt_dump.curbytes;
927 cnt_all->accumobjs += ctx->cnt_dump.accumobjs;
928 cnt_all->accumbytes += ctx->cnt_dump.accumbytes;
929
930 malloc_mutex_unlock(&ctx->lock);
931}
932
Jason Evans22ca8552010-03-02 11:57:30 -0800933static bool
934prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt, bool propagate_err)
Jason Evans6109fe02010-02-10 10:37:56 -0800935{
936 char buf[UMAX2S_BUFSIZE];
937 unsigned i;
938
Jason Evans22ca8552010-03-02 11:57:30 -0800939 if (prof_write(umax2s(ctx->cnt_dump.curobjs, 10, buf), propagate_err)
940 || prof_write(": ", propagate_err)
941 || prof_write(umax2s(ctx->cnt_dump.curbytes, 10, buf),
942 propagate_err)
943 || prof_write(" [", propagate_err)
944 || prof_write(umax2s(ctx->cnt_dump.accumobjs, 10, buf),
945 propagate_err)
946 || prof_write(": ", propagate_err)
947 || prof_write(umax2s(ctx->cnt_dump.accumbytes, 10, buf),
948 propagate_err)
949 || prof_write("] @", propagate_err))
950 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -0800951
952 for (i = 0; i < bt->len; i++) {
Jason Evans22ca8552010-03-02 11:57:30 -0800953 if (prof_write(" 0x", propagate_err)
954 || prof_write(umax2s((uintptr_t)bt->vec[i], 16, buf),
955 propagate_err))
956 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -0800957 }
958
Jason Evans22ca8552010-03-02 11:57:30 -0800959 if (prof_write("\n", propagate_err))
960 return (true);
961
962 return (false);
Jason Evans6109fe02010-02-10 10:37:56 -0800963}
964
Jason Evans22ca8552010-03-02 11:57:30 -0800965static bool
966prof_dump_maps(bool propagate_err)
Jason Evansc7177182010-02-11 09:25:56 -0800967{
968 int mfd;
969 char buf[UMAX2S_BUFSIZE];
970 char *s;
971 unsigned i, slen;
972 /* /proc/<pid>/maps\0 */
973 char mpath[6 + UMAX2S_BUFSIZE
974 + 5 + 1];
975
976 i = 0;
977
978 s = "/proc/";
979 slen = strlen(s);
980 memcpy(&mpath[i], s, slen);
981 i += slen;
982
983 s = umax2s(getpid(), 10, buf);
984 slen = strlen(s);
985 memcpy(&mpath[i], s, slen);
986 i += slen;
987
988 s = "/maps";
989 slen = strlen(s);
990 memcpy(&mpath[i], s, slen);
991 i += slen;
992
993 mpath[i] = '\0';
994
995 mfd = open(mpath, O_RDONLY);
996 if (mfd != -1) {
997 ssize_t nread;
998
Jason Evans22ca8552010-03-02 11:57:30 -0800999 if (prof_write("\nMAPPED_LIBRARIES:\n", propagate_err) &&
1000 propagate_err)
1001 return (true);
Jason Evansc7177182010-02-11 09:25:56 -08001002 nread = 0;
1003 do {
1004 prof_dump_buf_end += nread;
1005 if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE) {
1006 /* Make space in prof_dump_buf before read(). */
Jason Evans22ca8552010-03-02 11:57:30 -08001007 if (prof_flush(propagate_err) && propagate_err)
1008 return (true);
Jason Evansc7177182010-02-11 09:25:56 -08001009 }
1010 nread = read(mfd, &prof_dump_buf[prof_dump_buf_end],
1011 PROF_DUMP_BUF_SIZE - prof_dump_buf_end);
1012 } while (nread > 0);
Jason Evansd34f9e72010-02-11 13:19:21 -08001013 close(mfd);
Jason Evans22ca8552010-03-02 11:57:30 -08001014 } else
1015 return (true);
1016
1017 return (false);
Jason Evansc7177182010-02-11 09:25:56 -08001018}
1019
Jason Evans22ca8552010-03-02 11:57:30 -08001020static bool
1021prof_dump(const char *filename, bool leakcheck, bool propagate_err)
Jason Evans6109fe02010-02-10 10:37:56 -08001022{
1023 prof_cnt_t cnt_all;
1024 size_t tabind;
1025 prof_bt_t *bt;
1026 prof_ctx_t *ctx;
1027 char buf[UMAX2S_BUFSIZE];
1028 size_t leak_nctx;
1029
1030 prof_enter();
1031 prof_dump_fd = creat(filename, 0644);
1032 if (prof_dump_fd == -1) {
Jason Evans22ca8552010-03-02 11:57:30 -08001033 if (propagate_err == false) {
Jason Evans698805c2010-03-03 17:45:38 -08001034 malloc_write("<jemalloc>: creat(\"");
1035 malloc_write(filename);
1036 malloc_write("\", 0644) failed\n");
Jason Evans22ca8552010-03-02 11:57:30 -08001037 if (opt_abort)
1038 abort();
1039 }
Jason Evans22ca8552010-03-02 11:57:30 -08001040 goto ERROR;
Jason Evans6109fe02010-02-10 10:37:56 -08001041 }
1042
1043 /* Merge per thread profile stats, and sum them in cnt_all. */
1044 memset(&cnt_all, 0, sizeof(prof_cnt_t));
1045 leak_nctx = 0;
1046 for (tabind = 0; ckh_iter(&bt2ctx, &tabind, NULL, (void **)&ctx)
1047 == false;) {
1048 prof_ctx_merge(ctx, &cnt_all, &leak_nctx);
1049 }
1050
1051 /* Dump profile header. */
Jason Evans22ca8552010-03-02 11:57:30 -08001052 if (prof_write("heap profile: ", propagate_err)
1053 || prof_write(umax2s(cnt_all.curobjs, 10, buf), propagate_err)
1054 || prof_write(": ", propagate_err)
1055 || prof_write(umax2s(cnt_all.curbytes, 10, buf), propagate_err)
1056 || prof_write(" [", propagate_err)
1057 || prof_write(umax2s(cnt_all.accumobjs, 10, buf), propagate_err)
1058 || prof_write(": ", propagate_err)
1059 || prof_write(umax2s(cnt_all.accumbytes, 10, buf), propagate_err))
1060 goto ERROR;
1061
1062 if (opt_lg_prof_sample == 0) {
1063 if (prof_write("] @ heapprofile\n", propagate_err))
1064 goto ERROR;
1065 } else {
1066 if (prof_write("] @ heap_v2/", propagate_err)
1067 || prof_write(umax2s((uint64_t)1U << opt_lg_prof_sample, 10,
1068 buf), propagate_err)
1069 || prof_write("\n", propagate_err))
1070 goto ERROR;
Jason Evansb9477e72010-03-01 20:15:26 -08001071 }
Jason Evans6109fe02010-02-10 10:37:56 -08001072
1073 /* Dump per ctx profile stats. */
1074 for (tabind = 0; ckh_iter(&bt2ctx, &tabind, (void **)&bt, (void **)&ctx)
1075 == false;) {
Jason Evans22ca8552010-03-02 11:57:30 -08001076 if (prof_dump_ctx(ctx, bt, propagate_err))
1077 goto ERROR;
Jason Evans6109fe02010-02-10 10:37:56 -08001078 }
1079
Jason Evansc7177182010-02-11 09:25:56 -08001080 /* Dump /proc/<pid>/maps if possible. */
Jason Evans22ca8552010-03-02 11:57:30 -08001081 if (prof_dump_maps(propagate_err))
1082 goto ERROR;
Jason Evansc7177182010-02-11 09:25:56 -08001083
Jason Evans22ca8552010-03-02 11:57:30 -08001084 if (prof_flush(propagate_err))
1085 goto ERROR;
Jason Evans6109fe02010-02-10 10:37:56 -08001086 close(prof_dump_fd);
1087 prof_leave();
1088
1089 if (leakcheck && cnt_all.curbytes != 0) {
Jason Evans698805c2010-03-03 17:45:38 -08001090 malloc_write("<jemalloc>: Leak summary: ");
1091 malloc_write(umax2s(cnt_all.curbytes, 10, buf));
1092 malloc_write((cnt_all.curbytes != 1) ? " bytes, " : " byte, ");
1093 malloc_write(umax2s(cnt_all.curobjs, 10, buf));
1094 malloc_write((cnt_all.curobjs != 1) ? " objects, " :
1095 " object, ");
1096 malloc_write(umax2s(leak_nctx, 10, buf));
1097 malloc_write((leak_nctx != 1) ? " contexts\n" : " context\n");
1098 malloc_write("<jemalloc>: Run pprof on \"");
1099 malloc_write(filename);
1100 malloc_write("\" for leak detail\n");
Jason Evans6109fe02010-02-10 10:37:56 -08001101 }
Jason Evans22ca8552010-03-02 11:57:30 -08001102
1103 return (false);
1104ERROR:
1105 prof_leave();
1106 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -08001107}
1108
Jason Evansb01a6c22010-02-11 10:25:36 -08001109#define DUMP_FILENAME_BUFSIZE (PATH_MAX+ UMAX2S_BUFSIZE \
1110 + 1 \
1111 + UMAX2S_BUFSIZE \
1112 + 2 \
1113 + UMAX2S_BUFSIZE \
1114 + 5 + 1)
Jason Evans6109fe02010-02-10 10:37:56 -08001115static void
1116prof_dump_filename(char *filename, char v, int64_t vseq)
1117{
1118 char buf[UMAX2S_BUFSIZE];
1119 char *s;
1120 unsigned i, slen;
1121
Jason Evansb01a6c22010-02-11 10:25:36 -08001122 /*
1123 * Construct a filename of the form:
1124 *
1125 * <prefix>.<pid>.<seq>.v<vseq>.heap\0
1126 * or
1127 * jeprof.<pid>.<seq>.v<vseq>.heap\0
1128 */
1129
Jason Evans6109fe02010-02-10 10:37:56 -08001130 i = 0;
1131
Jason Evansb01a6c22010-02-11 10:25:36 -08001132 /*
1133 * Use JEMALLOC_PROF_PREFIX if it's set, and if it is short enough to
1134 * avoid overflowing DUMP_FILENAME_BUFSIZE. The result may exceed
1135 * PATH_MAX, but creat(2) will catch that problem.
1136 */
1137 if ((s = getenv("JEMALLOC_PROF_PREFIX")) != NULL
1138 && strlen(s) + (DUMP_FILENAME_BUFSIZE - PATH_MAX) <= PATH_MAX) {
1139 slen = strlen(s);
1140 memcpy(&filename[i], s, slen);
1141 i += slen;
1142
1143 s = ".";
1144 } else
1145 s = "jeprof.";
Jason Evans6109fe02010-02-10 10:37:56 -08001146 slen = strlen(s);
1147 memcpy(&filename[i], s, slen);
1148 i += slen;
1149
1150 s = umax2s(getpid(), 10, buf);
1151 slen = strlen(s);
1152 memcpy(&filename[i], s, slen);
1153 i += slen;
1154
1155 s = ".";
1156 slen = strlen(s);
1157 memcpy(&filename[i], s, slen);
1158 i += slen;
1159
1160 s = umax2s(prof_dump_seq, 10, buf);
1161 prof_dump_seq++;
1162 slen = strlen(s);
1163 memcpy(&filename[i], s, slen);
1164 i += slen;
1165
1166 s = ".";
1167 slen = strlen(s);
1168 memcpy(&filename[i], s, slen);
1169 i += slen;
1170
1171 filename[i] = v;
1172 i++;
1173
1174 if (vseq != 0xffffffffffffffffLLU) {
1175 s = umax2s(vseq, 10, buf);
1176 slen = strlen(s);
1177 memcpy(&filename[i], s, slen);
1178 i += slen;
1179 }
1180
1181 s = ".heap";
1182 slen = strlen(s);
1183 memcpy(&filename[i], s, slen);
1184 i += slen;
1185
1186 filename[i] = '\0';
1187}
1188
1189static void
1190prof_fdump(void)
1191{
1192 char filename[DUMP_FILENAME_BUFSIZE];
1193
1194 if (prof_booted == false)
1195 return;
1196
1197 malloc_mutex_lock(&prof_dump_seq_mtx);
1198 prof_dump_filename(filename, 'f', 0xffffffffffffffffLLU);
1199 malloc_mutex_unlock(&prof_dump_seq_mtx);
Jason Evans22ca8552010-03-02 11:57:30 -08001200 prof_dump(filename, opt_prof_leak, false);
Jason Evans6109fe02010-02-10 10:37:56 -08001201}
1202
1203void
1204prof_idump(void)
1205{
1206 char filename[DUMP_FILENAME_BUFSIZE];
1207
1208 if (prof_booted == false)
1209 return;
Jason Evansd34f9e72010-02-11 13:19:21 -08001210 malloc_mutex_lock(&enq_mtx);
1211 if (enq) {
1212 enq_idump = true;
1213 malloc_mutex_unlock(&enq_mtx);
1214 return;
1215 }
1216 malloc_mutex_unlock(&enq_mtx);
Jason Evans6109fe02010-02-10 10:37:56 -08001217
1218 malloc_mutex_lock(&prof_dump_seq_mtx);
1219 prof_dump_filename(filename, 'i', prof_dump_iseq);
1220 prof_dump_iseq++;
1221 malloc_mutex_unlock(&prof_dump_seq_mtx);
Jason Evans22ca8552010-03-02 11:57:30 -08001222 prof_dump(filename, false, false);
Jason Evans6109fe02010-02-10 10:37:56 -08001223}
1224
Jason Evans22ca8552010-03-02 11:57:30 -08001225bool
1226prof_mdump(const char *filename)
Jason Evans6109fe02010-02-10 10:37:56 -08001227{
Jason Evans22ca8552010-03-02 11:57:30 -08001228 char filename_buf[DUMP_FILENAME_BUFSIZE];
Jason Evans6109fe02010-02-10 10:37:56 -08001229
Jason Evans22ca8552010-03-02 11:57:30 -08001230 if (opt_prof == false || prof_booted == false)
1231 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -08001232
Jason Evans22ca8552010-03-02 11:57:30 -08001233 if (filename == NULL) {
1234 /* No filename specified, so automatically generate one. */
1235 malloc_mutex_lock(&prof_dump_seq_mtx);
1236 prof_dump_filename(filename_buf, 'm', prof_dump_mseq);
1237 prof_dump_mseq++;
1238 malloc_mutex_unlock(&prof_dump_seq_mtx);
1239 filename = filename_buf;
1240 }
1241 return (prof_dump(filename, false, true));
Jason Evans6109fe02010-02-10 10:37:56 -08001242}
1243
1244void
1245prof_udump(void)
1246{
1247 char filename[DUMP_FILENAME_BUFSIZE];
1248
1249 if (prof_booted == false)
1250 return;
1251 malloc_mutex_lock(&enq_mtx);
1252 if (enq) {
1253 enq_udump = true;
1254 malloc_mutex_unlock(&enq_mtx);
1255 return;
1256 }
1257 malloc_mutex_unlock(&enq_mtx);
1258
1259 malloc_mutex_lock(&prof_dump_seq_mtx);
1260 prof_dump_filename(filename, 'u', prof_dump_useq);
1261 prof_dump_useq++;
1262 malloc_mutex_unlock(&prof_dump_seq_mtx);
Jason Evans22ca8552010-03-02 11:57:30 -08001263 prof_dump(filename, false, false);
Jason Evans6109fe02010-02-10 10:37:56 -08001264}
1265
1266static void
1267prof_bt_hash(const void *key, unsigned minbits, size_t *hash1, size_t *hash2)
1268{
1269 size_t ret1, ret2;
1270 uint64_t h;
1271 prof_bt_t *bt = (prof_bt_t *)key;
1272
1273 assert(minbits <= 32 || (SIZEOF_PTR == 8 && minbits <= 64));
1274 assert(hash1 != NULL);
1275 assert(hash2 != NULL);
1276
1277 h = hash(bt->vec, bt->len * sizeof(void *), 0x94122f335b332aeaLLU);
1278 if (minbits <= 32) {
1279 /*
1280 * Avoid doing multiple hashes, since a single hash provides
1281 * enough bits.
1282 */
1283 ret1 = h & ZU(0xffffffffU);
1284 ret2 = h >> 32;
1285 } else {
1286 ret1 = h;
1287 ret2 = hash(bt->vec, bt->len * sizeof(void *),
1288 0x8432a476666bbc13U);
1289 }
1290
1291 *hash1 = ret1;
1292 *hash2 = ret2;
1293}
1294
1295static bool
1296prof_bt_keycomp(const void *k1, const void *k2)
1297{
1298 const prof_bt_t *bt1 = (prof_bt_t *)k1;
1299 const prof_bt_t *bt2 = (prof_bt_t *)k2;
1300
1301 if (bt1->len != bt2->len)
1302 return (false);
1303 return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0);
1304}
1305
1306static void
1307bt2cnt_thread_cleanup(void *arg)
1308{
1309 ckh_t *bt2cnt;
1310
Jason Evans2dbecf12010-09-05 10:35:13 -07001311 bt2cnt = BT2CNT_GET();
Jason Evans6109fe02010-02-10 10:37:56 -08001312 if (bt2cnt != NULL) {
1313 ql_head(prof_thr_cnt_t) cnts_ql;
1314 size_t tabind;
1315 prof_thr_cnt_t *cnt;
1316
1317 /* Iteratively merge cnt's into the global stats. */
1318 ql_new(&cnts_ql);
1319 tabind = 0;
1320 while (ckh_iter(bt2cnt, &tabind, NULL, (void **)&cnt) ==
1321 false) {
1322 prof_ctx_t *ctx = cnt->ctx;
1323 /* Merge stats and detach from ctx. */
1324 malloc_mutex_lock(&ctx->lock);
1325 ctx->cnt_merged.curobjs += cnt->cnts.curobjs;
1326 ctx->cnt_merged.curbytes += cnt->cnts.curbytes;
1327 ctx->cnt_merged.accumobjs += cnt->cnts.accumobjs;
1328 ctx->cnt_merged.accumbytes += cnt->cnts.accumbytes;
1329 ql_remove(&ctx->cnts_ql, cnt, link);
1330 malloc_mutex_unlock(&ctx->lock);
1331
1332 /*
1333 * Stash cnt for deletion after finishing with
1334 * ckh_iter().
1335 */
1336 ql_tail_insert(&cnts_ql, cnt, link);
1337 }
1338
1339 /*
1340 * Delete the hash table now that cnts_ql has a list of all
1341 * cnt's.
1342 */
1343 ckh_delete(bt2cnt);
1344 idalloc(bt2cnt);
Jason Evans2dbecf12010-09-05 10:35:13 -07001345 BT2CNT_SET(NULL);
Jason Evans6109fe02010-02-10 10:37:56 -08001346
1347 /* Delete cnt's. */
1348 while ((cnt = ql_last(&cnts_ql, link)) != NULL) {
1349 ql_remove(&cnts_ql, cnt, link);
1350 idalloc(cnt);
1351 }
1352 }
1353}
1354
Jason Evans2dbecf12010-09-05 10:35:13 -07001355#ifdef NO_TLS
1356static void
1357prof_sample_state_thread_cleanup(void *arg)
1358{
1359 prof_sample_state_t *prof_sample_state = (prof_sample_state_t *)arg;
1360
1361 if (prof_sample_state != &prof_sample_state_oom)
1362 idalloc(prof_sample_state);
1363}
1364#endif
1365
Jason Evans6109fe02010-02-10 10:37:56 -08001366void
1367prof_boot0(void)
1368{
1369
1370 /*
Jason Evans0b270a92010-03-31 16:45:04 -07001371 * opt_prof and prof_promote must be in their final state before any
1372 * arenas are initialized, so this function must be executed early.
Jason Evans6109fe02010-02-10 10:37:56 -08001373 */
1374
1375 if (opt_prof_leak && opt_prof == false) {
1376 /*
1377 * Enable opt_prof, but in such a way that profiles are never
1378 * automatically dumped.
1379 */
1380 opt_prof = true;
1381 opt_prof_udump = false;
1382 prof_interval = 0;
Jason Evansa02fc082010-03-31 17:35:51 -07001383 } else if (opt_prof) {
1384 if (opt_lg_prof_interval >= 0) {
1385 prof_interval = (((uint64_t)1U) <<
1386 opt_lg_prof_interval);
1387 } else
1388 prof_interval = 0;
1389 }
Jason Evans0b270a92010-03-31 16:45:04 -07001390
1391 prof_promote = (opt_prof && opt_lg_prof_sample > PAGE_SHIFT);
Jason Evans6109fe02010-02-10 10:37:56 -08001392}
1393
1394bool
1395prof_boot1(void)
1396{
1397
1398 if (opt_prof) {
Jason Evans6109fe02010-02-10 10:37:56 -08001399 if (ckh_new(&bt2ctx, PROF_CKH_MINITEMS, prof_bt_hash,
1400 prof_bt_keycomp))
1401 return (true);
1402 if (malloc_mutex_init(&bt2ctx_mtx))
1403 return (true);
1404 if (pthread_key_create(&bt2cnt_tsd, bt2cnt_thread_cleanup)
1405 != 0) {
Jason Evans698805c2010-03-03 17:45:38 -08001406 malloc_write(
1407 "<jemalloc>: Error in pthread_key_create()\n");
Jason Evans6109fe02010-02-10 10:37:56 -08001408 abort();
1409 }
Jason Evans2dbecf12010-09-05 10:35:13 -07001410#ifdef NO_TLS
1411 if (pthread_key_create(&prof_sample_state_tsd,
1412 prof_sample_state_thread_cleanup) != 0) {
1413 malloc_write(
1414 "<jemalloc>: Error in pthread_key_create()\n");
1415 abort();
1416 }
1417#endif
Jason Evans6109fe02010-02-10 10:37:56 -08001418
1419 prof_bt_max = (1U << opt_lg_prof_bt_max);
1420 if (malloc_mutex_init(&prof_dump_seq_mtx))
1421 return (true);
1422
1423 if (malloc_mutex_init(&enq_mtx))
1424 return (true);
1425 enq = false;
Jason Evansd34f9e72010-02-11 13:19:21 -08001426 enq_idump = false;
Jason Evans6109fe02010-02-10 10:37:56 -08001427 enq_udump = false;
1428
1429 if (atexit(prof_fdump) != 0) {
Jason Evans698805c2010-03-03 17:45:38 -08001430 malloc_write("<jemalloc>: Error in atexit()\n");
Jason Evans6109fe02010-02-10 10:37:56 -08001431 if (opt_abort)
1432 abort();
1433 }
1434 }
1435
Jason Evansb27805b2010-02-10 18:15:53 -08001436#ifdef JEMALLOC_PROF_LIBGCC
1437 /*
1438 * Cause the backtracing machinery to allocate its internal state
1439 * before enabling profiling.
1440 */
1441 _Unwind_Backtrace(prof_unwind_init_callback, NULL);
1442#endif
1443
Jason Evans6109fe02010-02-10 10:37:56 -08001444 prof_booted = true;
1445
1446 return (false);
1447}
1448
Jason Evans6109fe02010-02-10 10:37:56 -08001449/******************************************************************************/
1450#endif /* JEMALLOC_PROF */