blob: 93904b8c9f39612a9c92ddb4c60d8cff3ff723d6 [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 */
48static __thread ckh_t *bt2cnt_tls JEMALLOC_ATTR(tls_model("initial-exec"));
49
50/*
Jason Evans50651562010-04-13 16:13:54 -070051 * Same contents as b2cnt_tls, but initialized such that the TSD destructor is
Jason Evans6109fe02010-02-10 10:37:56 -080052 * called when a thread exits, so that bt2cnt_tls contents can be merged,
53 * unlinked, and deallocated.
54 */
55static pthread_key_t bt2cnt_tsd;
56
57/* (1U << opt_lg_prof_bt_max). */
58static unsigned prof_bt_max;
59
Jason Evansb9477e72010-03-01 20:15:26 -080060static __thread uint64_t prof_sample_prn_state
61 JEMALLOC_ATTR(tls_model("initial-exec"));
62static __thread uint64_t prof_sample_threshold
63 JEMALLOC_ATTR(tls_model("initial-exec"));
64static __thread uint64_t prof_sample_accum
65 JEMALLOC_ATTR(tls_model("initial-exec"));
66
Jason Evans6109fe02010-02-10 10:37:56 -080067static malloc_mutex_t prof_dump_seq_mtx;
68static uint64_t prof_dump_seq;
69static uint64_t prof_dump_iseq;
70static uint64_t prof_dump_mseq;
71static uint64_t prof_dump_useq;
72
73/*
74 * This buffer is rather large for stack allocation, so use a single buffer for
75 * all profile dumps. The buffer is implicitly protected by bt2ctx_mtx, since
76 * it must be locked anyway during dumping.
77 */
78static char prof_dump_buf[PROF_DUMP_BUF_SIZE];
79static unsigned prof_dump_buf_end;
80static int prof_dump_fd;
81
82/* Do not dump any profiles until bootstrapping is complete. */
83static bool prof_booted = false;
84
85static malloc_mutex_t enq_mtx;
86static bool enq;
Jason Evansd34f9e72010-02-11 13:19:21 -080087static bool enq_idump;
Jason Evans6109fe02010-02-10 10:37:56 -080088static bool enq_udump;
89
90/******************************************************************************/
91/* Function prototypes for non-inline static functions. */
92
93static prof_bt_t *bt_dup(prof_bt_t *bt);
94static void bt_init(prof_bt_t *bt, void **vec);
Jason Evansb27805b2010-02-10 18:15:53 -080095#ifdef JEMALLOC_PROF_LIBGCC
96static _Unwind_Reason_Code prof_unwind_init_callback(
97 struct _Unwind_Context *context, void *arg);
98static _Unwind_Reason_Code prof_unwind_callback(
99 struct _Unwind_Context *context, void *arg);
100#endif
101static void prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max);
Jason Evans6109fe02010-02-10 10:37:56 -0800102static prof_thr_cnt_t *prof_lookup(prof_bt_t *bt);
Jason Evans50651562010-04-13 16:13:54 -0700103static void prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
Jason Evans22ca8552010-03-02 11:57:30 -0800104static bool prof_flush(bool propagate_err);
105static bool prof_write(const char *s, bool propagate_err);
Jason Evans6109fe02010-02-10 10:37:56 -0800106static void prof_ctx_merge(prof_ctx_t *ctx, prof_cnt_t *cnt_all,
107 size_t *leak_nctx);
Jason Evans22ca8552010-03-02 11:57:30 -0800108static bool prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt,
109 bool propagate_err);
110static bool prof_dump_maps(bool propagate_err);
111static bool prof_dump(const char *filename, bool leakcheck,
112 bool propagate_err);
Jason Evans6109fe02010-02-10 10:37:56 -0800113static void prof_dump_filename(char *filename, char v, int64_t vseq);
114static void prof_fdump(void);
115static void prof_bt_hash(const void *key, unsigned minbits, size_t *hash1,
116 size_t *hash2);
117static bool prof_bt_keycomp(const void *k1, const void *k2);
118static void bt2cnt_thread_cleanup(void *arg);
119
120/******************************************************************************/
121
122static void
123bt_init(prof_bt_t *bt, void **vec)
124{
125
126 bt->vec = vec;
127 bt->len = 0;
128}
129
130static prof_bt_t *
131bt_dup(prof_bt_t *bt)
132{
133 prof_bt_t *ret;
134
135 /*
136 * Create a single allocation that has space for vec immediately
137 * following the prof_bt_t structure. The backtraces that get
138 * stored in the backtrace caches are copied from stack-allocated
139 * temporary variables, so size is known at creation time. Making this
140 * a contiguous object improves cache locality.
141 */
142 ret = (prof_bt_t *)imalloc(QUANTUM_CEILING(sizeof(prof_bt_t)) +
143 (bt->len * sizeof(void *)));
144 if (ret == NULL)
145 return (NULL);
146 ret->vec = (void **)((uintptr_t)ret +
147 QUANTUM_CEILING(sizeof(prof_bt_t)));
148 memcpy(ret->vec, bt->vec, bt->len * sizeof(void *));
149 ret->len = bt->len;
150
151 return (ret);
152}
153
154static inline void
155prof_enter(void)
156{
157
158 malloc_mutex_lock(&enq_mtx);
159 enq = true;
160 malloc_mutex_unlock(&enq_mtx);
161
162 malloc_mutex_lock(&bt2ctx_mtx);
163}
164
165static inline void
166prof_leave(void)
167{
Jason Evansd34f9e72010-02-11 13:19:21 -0800168 bool idump, udump;
Jason Evans6109fe02010-02-10 10:37:56 -0800169
170 malloc_mutex_unlock(&bt2ctx_mtx);
171
172 malloc_mutex_lock(&enq_mtx);
173 enq = false;
Jason Evansd34f9e72010-02-11 13:19:21 -0800174 idump = enq_idump;
175 enq_idump = false;
Jason Evans6109fe02010-02-10 10:37:56 -0800176 udump = enq_udump;
177 enq_udump = false;
178 malloc_mutex_unlock(&enq_mtx);
179
Jason Evansd34f9e72010-02-11 13:19:21 -0800180 if (idump)
181 prof_idump();
Jason Evans6109fe02010-02-10 10:37:56 -0800182 if (udump)
183 prof_udump();
184}
185
Jason Evansb27805b2010-02-10 18:15:53 -0800186#ifdef JEMALLOC_PROF_LIBGCC
187static _Unwind_Reason_Code
188prof_unwind_init_callback(struct _Unwind_Context *context, void *arg)
189{
190
191 return (_URC_NO_REASON);
192}
193
194static _Unwind_Reason_Code
195prof_unwind_callback(struct _Unwind_Context *context, void *arg)
196{
197 prof_unwind_data_t *data = (prof_unwind_data_t *)arg;
198
199 if (data->nignore > 0)
200 data->nignore--;
201 else {
202 data->bt->vec[data->bt->len] = (void *)_Unwind_GetIP(context);
203 data->bt->len++;
204 if (data->bt->len == data->max)
205 return (_URC_END_OF_STACK);
206 }
207
208 return (_URC_NO_REASON);
209}
210
211static void
212prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
213{
214 prof_unwind_data_t data = {bt, nignore, max};
215
216 _Unwind_Backtrace(prof_unwind_callback, &data);
217}
218#elif defined(JEMALLOC_PROF_LIBUNWIND)
219static void
Jason Evans6109fe02010-02-10 10:37:56 -0800220prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
221{
222 unw_context_t uc;
223 unw_cursor_t cursor;
224 unsigned i;
225 int err;
226
227 assert(bt->len == 0);
228 assert(bt->vec != NULL);
229 assert(max <= (1U << opt_lg_prof_bt_max));
230
231 unw_getcontext(&uc);
232 unw_init_local(&cursor, &uc);
233
234 /* Throw away (nignore+1) stack frames, if that many exist. */
235 for (i = 0; i < nignore + 1; i++) {
236 err = unw_step(&cursor);
237 if (err <= 0)
Jason Evansb27805b2010-02-10 18:15:53 -0800238 return;
Jason Evans6109fe02010-02-10 10:37:56 -0800239 }
240
241 /*
242 * Iterate over stack frames until there are no more. Heap-allocate
243 * and iteratively grow a larger bt if necessary.
244 */
245 for (i = 0; i < max; i++) {
246 unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *)&bt->vec[i]);
247 err = unw_step(&cursor);
248 if (err <= 0) {
249 bt->len = i;
250 break;
251 }
252 }
Jason Evans6109fe02010-02-10 10:37:56 -0800253}
254#else
Jason Evansb27805b2010-02-10 18:15:53 -0800255static void
Jason Evans6109fe02010-02-10 10:37:56 -0800256prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
257{
258#define NIGNORE 3
259#define BT_FRAME(i) \
260 if ((i) < NIGNORE + max) { \
261 void *p; \
262 if (__builtin_frame_address(i) == 0) \
Jason Evansb27805b2010-02-10 18:15:53 -0800263 return; \
Jason Evans6109fe02010-02-10 10:37:56 -0800264 p = __builtin_return_address(i); \
265 if (p == NULL) \
Jason Evansb27805b2010-02-10 18:15:53 -0800266 return; \
Jason Evans6109fe02010-02-10 10:37:56 -0800267 if (i >= NIGNORE) { \
268 bt->vec[(i) - NIGNORE] = p; \
269 bt->len = (i) - NIGNORE + 1; \
270 } \
271 } else \
Jason Evansb27805b2010-02-10 18:15:53 -0800272 return;
Jason Evans6109fe02010-02-10 10:37:56 -0800273
274 assert(max <= (1U << opt_lg_prof_bt_max));
275
276 /*
277 * Ignore the first three frames, since they are:
278 *
279 * 0: prof_backtrace()
280 * 1: prof_alloc_prep()
281 * 2: malloc(), calloc(), etc.
282 */
283#if 1
284 assert(nignore + 1 == NIGNORE);
285#else
286 BT_FRAME(0)
287 BT_FRAME(1)
288 BT_FRAME(2)
289#endif
290 BT_FRAME(3)
291 BT_FRAME(4)
292 BT_FRAME(5)
293 BT_FRAME(6)
294 BT_FRAME(7)
295 BT_FRAME(8)
296 BT_FRAME(9)
297
298 BT_FRAME(10)
299 BT_FRAME(11)
300 BT_FRAME(12)
301 BT_FRAME(13)
302 BT_FRAME(14)
303 BT_FRAME(15)
304 BT_FRAME(16)
305 BT_FRAME(17)
306 BT_FRAME(18)
307 BT_FRAME(19)
308
309 BT_FRAME(20)
310 BT_FRAME(21)
311 BT_FRAME(22)
312 BT_FRAME(23)
313 BT_FRAME(24)
314 BT_FRAME(25)
315 BT_FRAME(26)
316 BT_FRAME(27)
317 BT_FRAME(28)
318 BT_FRAME(29)
319
320 BT_FRAME(30)
321 BT_FRAME(31)
322 BT_FRAME(32)
323 BT_FRAME(33)
324 BT_FRAME(34)
325 BT_FRAME(35)
326 BT_FRAME(36)
327 BT_FRAME(37)
328 BT_FRAME(38)
329 BT_FRAME(39)
330
331 BT_FRAME(40)
332 BT_FRAME(41)
333 BT_FRAME(42)
334 BT_FRAME(43)
335 BT_FRAME(44)
336 BT_FRAME(45)
337 BT_FRAME(46)
338 BT_FRAME(47)
339 BT_FRAME(48)
340 BT_FRAME(49)
341
342 BT_FRAME(50)
343 BT_FRAME(51)
344 BT_FRAME(52)
345 BT_FRAME(53)
346 BT_FRAME(54)
347 BT_FRAME(55)
348 BT_FRAME(56)
349 BT_FRAME(57)
350 BT_FRAME(58)
351 BT_FRAME(59)
352
353 BT_FRAME(60)
354 BT_FRAME(61)
355 BT_FRAME(62)
356 BT_FRAME(63)
357 BT_FRAME(64)
358 BT_FRAME(65)
359 BT_FRAME(66)
360 BT_FRAME(67)
361 BT_FRAME(68)
362 BT_FRAME(69)
363
364 BT_FRAME(70)
365 BT_FRAME(71)
366 BT_FRAME(72)
367 BT_FRAME(73)
368 BT_FRAME(74)
369 BT_FRAME(75)
370 BT_FRAME(76)
371 BT_FRAME(77)
372 BT_FRAME(78)
373 BT_FRAME(79)
374
375 BT_FRAME(80)
376 BT_FRAME(81)
377 BT_FRAME(82)
378 BT_FRAME(83)
379 BT_FRAME(84)
380 BT_FRAME(85)
381 BT_FRAME(86)
382 BT_FRAME(87)
383 BT_FRAME(88)
384 BT_FRAME(89)
385
386 BT_FRAME(90)
387 BT_FRAME(91)
388 BT_FRAME(92)
389 BT_FRAME(93)
390 BT_FRAME(94)
391 BT_FRAME(95)
392 BT_FRAME(96)
393 BT_FRAME(97)
394 BT_FRAME(98)
395 BT_FRAME(99)
396
397 BT_FRAME(100)
398 BT_FRAME(101)
399 BT_FRAME(102)
400 BT_FRAME(103)
401 BT_FRAME(104)
402 BT_FRAME(105)
403 BT_FRAME(106)
404 BT_FRAME(107)
405 BT_FRAME(108)
406 BT_FRAME(109)
407
408 BT_FRAME(110)
409 BT_FRAME(111)
410 BT_FRAME(112)
411 BT_FRAME(113)
412 BT_FRAME(114)
413 BT_FRAME(115)
414 BT_FRAME(116)
415 BT_FRAME(117)
416 BT_FRAME(118)
417 BT_FRAME(119)
418
419 BT_FRAME(120)
420 BT_FRAME(121)
421 BT_FRAME(122)
422 BT_FRAME(123)
423 BT_FRAME(124)
424 BT_FRAME(125)
425 BT_FRAME(126)
426 BT_FRAME(127)
427
428 /* Extras to compensate for NIGNORE. */
429 BT_FRAME(128)
430 BT_FRAME(129)
431 BT_FRAME(130)
Jason Evans6109fe02010-02-10 10:37:56 -0800432#undef BT_FRAME
Jason Evans6109fe02010-02-10 10:37:56 -0800433}
434#endif
435
436static prof_thr_cnt_t *
437prof_lookup(prof_bt_t *bt)
438{
439 prof_thr_cnt_t *ret;
440 ckh_t *bt2cnt = bt2cnt_tls;
441
442 if (bt2cnt == NULL) {
443 /* Initialize an empty cache for this thread. */
444 bt2cnt = (ckh_t *)imalloc(sizeof(ckh_t));
445 if (bt2cnt == NULL)
446 return (NULL);
447 if (ckh_new(bt2cnt, PROF_CKH_MINITEMS, prof_bt_hash,
448 prof_bt_keycomp)) {
449 idalloc(bt2cnt);
450 return (NULL);
451 }
452 bt2cnt_tls = bt2cnt;
Jason Evans50651562010-04-13 16:13:54 -0700453 pthread_setspecific(bt2cnt_tsd, bt2cnt);
Jason Evans6109fe02010-02-10 10:37:56 -0800454 }
455
456 if (ckh_search(bt2cnt, bt, NULL, (void **)&ret)) {
457 prof_bt_t *btkey;
458 prof_ctx_t *ctx;
459
460 /*
461 * This thread's cache lacks bt. Look for it in the global
462 * cache.
463 */
464 prof_enter();
465 if (ckh_search(&bt2ctx, bt, (void **)&btkey, (void **)&ctx)) {
466
467 /* bt has never been seen before. Insert it. */
468 ctx = (prof_ctx_t *)imalloc(sizeof(prof_ctx_t));
469 if (ctx == NULL) {
470 prof_leave();
471 return (NULL);
472 }
473 btkey = bt_dup(bt);
474 if (btkey == NULL) {
475 prof_leave();
476 idalloc(ctx);
477 return (NULL);
478 }
Jason Evans50651562010-04-13 16:13:54 -0700479 ctx->bt = btkey;
Jason Evans6109fe02010-02-10 10:37:56 -0800480 if (malloc_mutex_init(&ctx->lock)) {
481 prof_leave();
482 idalloc(btkey);
483 idalloc(ctx);
484 return (NULL);
485 }
486 memset(&ctx->cnt_merged, 0, sizeof(prof_cnt_t));
487 ql_new(&ctx->cnts_ql);
488 if (ckh_insert(&bt2ctx, btkey, ctx)) {
489 /* OOM. */
490 prof_leave();
491 idalloc(btkey);
492 idalloc(ctx);
493 return (NULL);
494 }
495 }
496 prof_leave();
497
498 /* Link a prof_thd_cnt_t into ctx for this thread. */
499 ret = (prof_thr_cnt_t *)imalloc(sizeof(prof_thr_cnt_t));
500 if (ret == NULL)
501 return (NULL);
502 ql_elm_new(ret, link);
503 ret->ctx = ctx;
504 ret->epoch = 0;
505 memset(&ret->cnts, 0, sizeof(prof_cnt_t));
506 if (ckh_insert(bt2cnt, btkey, ret)) {
507 idalloc(ret);
508 return (NULL);
509 }
510 malloc_mutex_lock(&ctx->lock);
511 ql_tail_insert(&ctx->cnts_ql, ret, link);
512 malloc_mutex_unlock(&ctx->lock);
513 }
514
515 return (ret);
516}
517
Jason Evans9df02152010-03-03 11:53:11 -0800518static inline void
519prof_sample_threshold_update(void)
520{
521 uint64_t r;
522 double u;
523
524 /*
525 * Compute prof_sample_threshold as a geometrically distributed random
526 * variable with mean (2^opt_lg_prof_sample).
527 */
528 prn64(r, 53, prof_sample_prn_state, (uint64_t)1125899906842625LLU,
529 1058392653243283975);
530 u = (double)r * (1.0/9007199254740992.0L);
531 prof_sample_threshold = (uint64_t)(log(u) /
532 log(1.0 - (1.0 / (double)((uint64_t)1U << opt_lg_prof_sample))))
533 + (uint64_t)1U;
534}
535
Jason Evans6109fe02010-02-10 10:37:56 -0800536prof_thr_cnt_t *
Jason Evansb9477e72010-03-01 20:15:26 -0800537prof_alloc_prep(size_t size)
Jason Evans6109fe02010-02-10 10:37:56 -0800538{
539 prof_thr_cnt_t *ret;
540 void *vec[prof_bt_max];
541 prof_bt_t bt;
542
Jason Evansf18c9822010-03-31 18:43:24 -0700543 if (opt_prof_active == false) {
544 /* Sampling is currently inactive, so avoid sampling. */
545 ret = (prof_thr_cnt_t *)(uintptr_t)1U;
546 } else if (opt_lg_prof_sample == 0) {
Jason Evans9df02152010-03-03 11:53:11 -0800547 /*
548 * Don't bother with sampling logic, since sampling interval is
549 * 1.
550 */
Jason Evansb9477e72010-03-01 20:15:26 -0800551 bt_init(&bt, vec);
552 prof_backtrace(&bt, 2, prof_bt_max);
553 ret = prof_lookup(&bt);
Jason Evans9df02152010-03-03 11:53:11 -0800554 } else {
555 if (prof_sample_threshold == 0) {
556 /*
557 * Initialize. Seed the prng differently for each
558 * thread.
559 */
560 prof_sample_prn_state = (uint64_t)(uintptr_t)&size;
561 prof_sample_threshold_update();
562 }
563
564 /*
565 * Determine whether to capture a backtrace based on whether
566 * size is enough for prof_accum to reach
567 * prof_sample_threshold. However, delay updating these
568 * variables until prof_{m,re}alloc(), because we don't know
569 * for sure that the allocation will succeed.
570 *
571 * Use subtraction rather than addition to avoid potential
572 * integer overflow.
573 */
574 if (size >= prof_sample_threshold - prof_sample_accum) {
575 bt_init(&bt, vec);
576 prof_backtrace(&bt, 2, prof_bt_max);
577 ret = prof_lookup(&bt);
578 } else
579 ret = (prof_thr_cnt_t *)(uintptr_t)1U;
580 }
Jason Evans6109fe02010-02-10 10:37:56 -0800581
582 return (ret);
583}
584
Jason Evans50651562010-04-13 16:13:54 -0700585prof_ctx_t *
586prof_ctx_get(const void *ptr)
Jason Evans6109fe02010-02-10 10:37:56 -0800587{
Jason Evans50651562010-04-13 16:13:54 -0700588 prof_ctx_t *ret;
Jason Evans6109fe02010-02-10 10:37:56 -0800589 arena_chunk_t *chunk;
590
591 assert(ptr != NULL);
592
593 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
594 if (chunk != ptr) {
595 /* Region. */
596 assert(chunk->arena->magic == ARENA_MAGIC);
597
Jason Evans50651562010-04-13 16:13:54 -0700598 ret = arena_prof_ctx_get(ptr);
Jason Evans6109fe02010-02-10 10:37:56 -0800599 } else
Jason Evans50651562010-04-13 16:13:54 -0700600 ret = huge_prof_ctx_get(ptr);
Jason Evans6109fe02010-02-10 10:37:56 -0800601
602 return (ret);
603}
604
605static void
Jason Evans50651562010-04-13 16:13:54 -0700606prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
Jason Evans6109fe02010-02-10 10:37:56 -0800607{
608 arena_chunk_t *chunk;
609
610 assert(ptr != NULL);
611
612 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
613 if (chunk != ptr) {
614 /* Region. */
615 assert(chunk->arena->magic == ARENA_MAGIC);
616
Jason Evans50651562010-04-13 16:13:54 -0700617 arena_prof_ctx_set(ptr, ctx);
Jason Evans6109fe02010-02-10 10:37:56 -0800618 } else
Jason Evans50651562010-04-13 16:13:54 -0700619 huge_prof_ctx_set(ptr, ctx);
Jason Evans6109fe02010-02-10 10:37:56 -0800620}
621
Jason Evansb9477e72010-03-01 20:15:26 -0800622static inline void
Jason Evansb9477e72010-03-01 20:15:26 -0800623prof_sample_accum_update(size_t size)
624{
625
626 if (opt_lg_prof_sample == 0) {
627 /*
628 * Don't bother with sampling logic, since sampling interval is
629 * 1.
630 */
631 return;
632 }
633
Jason Evansb9477e72010-03-01 20:15:26 -0800634 /* Take care to avoid integer overflow. */
635 if (size >= prof_sample_threshold - prof_sample_accum) {
636 prof_sample_accum -= (prof_sample_threshold - size);
Jason Evans9df02152010-03-03 11:53:11 -0800637 /* Compute new prof_sample_threshold. */
Jason Evansb9477e72010-03-01 20:15:26 -0800638 prof_sample_threshold_update();
639 while (prof_sample_accum >= prof_sample_threshold) {
640 prof_sample_accum -= prof_sample_threshold;
641 prof_sample_threshold_update();
642 }
643 } else
644 prof_sample_accum += size;
645}
646
Jason Evans6109fe02010-02-10 10:37:56 -0800647void
648prof_malloc(const void *ptr, prof_thr_cnt_t *cnt)
649{
650 size_t size = isalloc(ptr);
651
Jason Evansb9477e72010-03-01 20:15:26 -0800652 assert(ptr != NULL);
Jason Evans6109fe02010-02-10 10:37:56 -0800653
Jason Evansb9477e72010-03-01 20:15:26 -0800654 prof_sample_accum_update(size);
655
656 if ((uintptr_t)cnt > (uintptr_t)1U) {
Jason Evans38cda692010-04-14 11:24:45 -0700657 prof_ctx_set(ptr, cnt->ctx);
658
Jason Evansb9477e72010-03-01 20:15:26 -0800659 cnt->epoch++;
660 /*********/
661 mb_write();
662 /*********/
663 cnt->cnts.curobjs++;
664 cnt->cnts.curbytes += size;
665 cnt->cnts.accumobjs++;
666 cnt->cnts.accumbytes += size;
667 /*********/
668 mb_write();
669 /*********/
670 cnt->epoch++;
671 /*********/
672 mb_write();
673 /*********/
Jason Evans38cda692010-04-14 11:24:45 -0700674 } else
675 prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
Jason Evans6109fe02010-02-10 10:37:56 -0800676}
677
678void
679prof_realloc(const void *ptr, prof_thr_cnt_t *cnt, const void *old_ptr,
Jason Evans50651562010-04-13 16:13:54 -0700680 size_t old_size, prof_ctx_t *old_ctx)
Jason Evans6109fe02010-02-10 10:37:56 -0800681{
682 size_t size = isalloc(ptr);
Jason Evans50651562010-04-13 16:13:54 -0700683 prof_thr_cnt_t *told_cnt;
Jason Evans6109fe02010-02-10 10:37:56 -0800684
Jason Evans38cda692010-04-14 11:24:45 -0700685 if (ptr != NULL)
Jason Evansb9477e72010-03-01 20:15:26 -0800686 prof_sample_accum_update(size);
Jason Evans6109fe02010-02-10 10:37:56 -0800687
Jason Evans50651562010-04-13 16:13:54 -0700688 if ((uintptr_t)old_ctx > (uintptr_t)1U) {
689 told_cnt = prof_lookup(old_ctx->bt);
690 if (told_cnt == NULL) {
691 /*
692 * It's too late to propagate OOM for this realloc(),
693 * so operate directly on old_cnt->ctx->cnt_merged.
694 */
Jason Evans50651562010-04-13 16:13:54 -0700695 malloc_mutex_lock(&old_ctx->lock);
696 old_ctx->cnt_merged.curobjs--;
697 old_ctx->cnt_merged.curbytes -= old_size;
698 malloc_mutex_unlock(&old_ctx->lock);
699 told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
700 }
701 } else
702 told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
703
704 if ((uintptr_t)told_cnt > (uintptr_t)1U)
705 told_cnt->epoch++;
Jason Evans38cda692010-04-14 11:24:45 -0700706 if ((uintptr_t)cnt > (uintptr_t)1U) {
707 prof_ctx_set(ptr, cnt->ctx);
Jason Evans6109fe02010-02-10 10:37:56 -0800708 cnt->epoch++;
Jason Evans38cda692010-04-14 11:24:45 -0700709 } else
710 prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
Jason Evans6109fe02010-02-10 10:37:56 -0800711 /*********/
712 mb_write();
713 /*********/
Jason Evans50651562010-04-13 16:13:54 -0700714 if ((uintptr_t)told_cnt > (uintptr_t)1U) {
715 told_cnt->cnts.curobjs--;
716 told_cnt->cnts.curbytes -= old_size;
Jason Evans6109fe02010-02-10 10:37:56 -0800717 }
Jason Evansb9477e72010-03-01 20:15:26 -0800718 if ((uintptr_t)cnt > (uintptr_t)1U) {
Jason Evans6109fe02010-02-10 10:37:56 -0800719 cnt->cnts.curobjs++;
720 cnt->cnts.curbytes += size;
721 cnt->cnts.accumobjs++;
722 cnt->cnts.accumbytes += size;
723 }
724 /*********/
725 mb_write();
726 /*********/
Jason Evans50651562010-04-13 16:13:54 -0700727 if ((uintptr_t)told_cnt > (uintptr_t)1U)
728 told_cnt->epoch++;
Jason Evansb9477e72010-03-01 20:15:26 -0800729 if ((uintptr_t)cnt > (uintptr_t)1U)
Jason Evans6109fe02010-02-10 10:37:56 -0800730 cnt->epoch++;
731 /*********/
732 mb_write(); /* Not strictly necessary. */
733}
734
735void
736prof_free(const void *ptr)
737{
Jason Evans50651562010-04-13 16:13:54 -0700738 prof_ctx_t *ctx = prof_ctx_get(ptr);
Jason Evans6109fe02010-02-10 10:37:56 -0800739
Jason Evans50651562010-04-13 16:13:54 -0700740 if ((uintptr_t)ctx > (uintptr_t)1) {
Jason Evansb9477e72010-03-01 20:15:26 -0800741 size_t size = isalloc(ptr);
Jason Evans50651562010-04-13 16:13:54 -0700742 prof_thr_cnt_t *tcnt = prof_lookup(ctx->bt);
Jason Evansb9477e72010-03-01 20:15:26 -0800743
Jason Evans50651562010-04-13 16:13:54 -0700744 if (tcnt != NULL) {
745 tcnt->epoch++;
746 /*********/
747 mb_write();
748 /*********/
749 tcnt->cnts.curobjs--;
750 tcnt->cnts.curbytes -= size;
751 /*********/
752 mb_write();
753 /*********/
754 tcnt->epoch++;
755 /*********/
756 mb_write();
757 /*********/
758 } else {
759 /*
760 * OOM during free() cannot be propagated, so operate
761 * directly on cnt->ctx->cnt_merged.
762 */
Jason Evans50651562010-04-13 16:13:54 -0700763 malloc_mutex_lock(&ctx->lock);
764 ctx->cnt_merged.curobjs--;
765 ctx->cnt_merged.curbytes -= size;
766 malloc_mutex_unlock(&ctx->lock);
767 }
Jason Evansb9477e72010-03-01 20:15:26 -0800768 }
Jason Evans6109fe02010-02-10 10:37:56 -0800769}
770
Jason Evans22ca8552010-03-02 11:57:30 -0800771static bool
772prof_flush(bool propagate_err)
Jason Evans6109fe02010-02-10 10:37:56 -0800773{
Jason Evans22ca8552010-03-02 11:57:30 -0800774 bool ret = false;
Jason Evans6109fe02010-02-10 10:37:56 -0800775 ssize_t err;
776
777 err = write(prof_dump_fd, prof_dump_buf, prof_dump_buf_end);
778 if (err == -1) {
Jason Evans22ca8552010-03-02 11:57:30 -0800779 if (propagate_err == false) {
Jason Evans698805c2010-03-03 17:45:38 -0800780 malloc_write("<jemalloc>: write() failed during heap "
781 "profile flush\n");
Jason Evans22ca8552010-03-02 11:57:30 -0800782 if (opt_abort)
783 abort();
784 }
785 ret = true;
Jason Evans6109fe02010-02-10 10:37:56 -0800786 }
787 prof_dump_buf_end = 0;
Jason Evans22ca8552010-03-02 11:57:30 -0800788
789 return (ret);
Jason Evans6109fe02010-02-10 10:37:56 -0800790}
791
Jason Evans22ca8552010-03-02 11:57:30 -0800792static bool
793prof_write(const char *s, bool propagate_err)
Jason Evans6109fe02010-02-10 10:37:56 -0800794{
795 unsigned i, slen, n;
796
797 i = 0;
798 slen = strlen(s);
799 while (i < slen) {
800 /* Flush the buffer if it is full. */
801 if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE)
Jason Evans22ca8552010-03-02 11:57:30 -0800802 if (prof_flush(propagate_err) && propagate_err)
803 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -0800804
805 if (prof_dump_buf_end + slen <= PROF_DUMP_BUF_SIZE) {
806 /* Finish writing. */
807 n = slen - i;
808 } else {
809 /* Write as much of s as will fit. */
810 n = PROF_DUMP_BUF_SIZE - prof_dump_buf_end;
811 }
812 memcpy(&prof_dump_buf[prof_dump_buf_end], &s[i], n);
813 prof_dump_buf_end += n;
814 i += n;
815 }
Jason Evans22ca8552010-03-02 11:57:30 -0800816
817 return (false);
Jason Evans6109fe02010-02-10 10:37:56 -0800818}
819
820static void
821prof_ctx_merge(prof_ctx_t *ctx, prof_cnt_t *cnt_all, size_t *leak_nctx)
822{
823 prof_thr_cnt_t *thr_cnt;
824 prof_cnt_t tcnt;
825
826 malloc_mutex_lock(&ctx->lock);
827
828 memcpy(&ctx->cnt_dump, &ctx->cnt_merged, sizeof(prof_cnt_t));
829 ql_foreach(thr_cnt, &ctx->cnts_ql, link) {
830 volatile unsigned *epoch = &thr_cnt->epoch;
831
832 while (true) {
833 unsigned epoch0 = *epoch;
834
835 /* Make sure epoch is even. */
836 if (epoch0 & 1U)
837 continue;
838
839 memcpy(&tcnt, &thr_cnt->cnts, sizeof(prof_cnt_t));
840
841 /* Terminate if epoch didn't change while reading. */
842 if (*epoch == epoch0)
843 break;
844 }
845
846 ctx->cnt_dump.curobjs += tcnt.curobjs;
847 ctx->cnt_dump.curbytes += tcnt.curbytes;
848 ctx->cnt_dump.accumobjs += tcnt.accumobjs;
849 ctx->cnt_dump.accumbytes += tcnt.accumbytes;
850
851 if (tcnt.curobjs != 0)
852 (*leak_nctx)++;
853 }
854
855 /* Merge into cnt_all. */
856 cnt_all->curobjs += ctx->cnt_dump.curobjs;
857 cnt_all->curbytes += ctx->cnt_dump.curbytes;
858 cnt_all->accumobjs += ctx->cnt_dump.accumobjs;
859 cnt_all->accumbytes += ctx->cnt_dump.accumbytes;
860
861 malloc_mutex_unlock(&ctx->lock);
862}
863
Jason Evans22ca8552010-03-02 11:57:30 -0800864static bool
865prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt, bool propagate_err)
Jason Evans6109fe02010-02-10 10:37:56 -0800866{
867 char buf[UMAX2S_BUFSIZE];
868 unsigned i;
869
Jason Evans22ca8552010-03-02 11:57:30 -0800870 if (prof_write(umax2s(ctx->cnt_dump.curobjs, 10, buf), propagate_err)
871 || prof_write(": ", propagate_err)
872 || prof_write(umax2s(ctx->cnt_dump.curbytes, 10, buf),
873 propagate_err)
874 || prof_write(" [", propagate_err)
875 || prof_write(umax2s(ctx->cnt_dump.accumobjs, 10, buf),
876 propagate_err)
877 || prof_write(": ", propagate_err)
878 || prof_write(umax2s(ctx->cnt_dump.accumbytes, 10, buf),
879 propagate_err)
880 || prof_write("] @", propagate_err))
881 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -0800882
883 for (i = 0; i < bt->len; i++) {
Jason Evans22ca8552010-03-02 11:57:30 -0800884 if (prof_write(" 0x", propagate_err)
885 || prof_write(umax2s((uintptr_t)bt->vec[i], 16, buf),
886 propagate_err))
887 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -0800888 }
889
Jason Evans22ca8552010-03-02 11:57:30 -0800890 if (prof_write("\n", propagate_err))
891 return (true);
892
893 return (false);
Jason Evans6109fe02010-02-10 10:37:56 -0800894}
895
Jason Evans22ca8552010-03-02 11:57:30 -0800896static bool
897prof_dump_maps(bool propagate_err)
Jason Evansc7177182010-02-11 09:25:56 -0800898{
899 int mfd;
900 char buf[UMAX2S_BUFSIZE];
901 char *s;
902 unsigned i, slen;
903 /* /proc/<pid>/maps\0 */
904 char mpath[6 + UMAX2S_BUFSIZE
905 + 5 + 1];
906
907 i = 0;
908
909 s = "/proc/";
910 slen = strlen(s);
911 memcpy(&mpath[i], s, slen);
912 i += slen;
913
914 s = umax2s(getpid(), 10, buf);
915 slen = strlen(s);
916 memcpy(&mpath[i], s, slen);
917 i += slen;
918
919 s = "/maps";
920 slen = strlen(s);
921 memcpy(&mpath[i], s, slen);
922 i += slen;
923
924 mpath[i] = '\0';
925
926 mfd = open(mpath, O_RDONLY);
927 if (mfd != -1) {
928 ssize_t nread;
929
Jason Evans22ca8552010-03-02 11:57:30 -0800930 if (prof_write("\nMAPPED_LIBRARIES:\n", propagate_err) &&
931 propagate_err)
932 return (true);
Jason Evansc7177182010-02-11 09:25:56 -0800933 nread = 0;
934 do {
935 prof_dump_buf_end += nread;
936 if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE) {
937 /* Make space in prof_dump_buf before read(). */
Jason Evans22ca8552010-03-02 11:57:30 -0800938 if (prof_flush(propagate_err) && propagate_err)
939 return (true);
Jason Evansc7177182010-02-11 09:25:56 -0800940 }
941 nread = read(mfd, &prof_dump_buf[prof_dump_buf_end],
942 PROF_DUMP_BUF_SIZE - prof_dump_buf_end);
943 } while (nread > 0);
Jason Evansd34f9e72010-02-11 13:19:21 -0800944 close(mfd);
Jason Evans22ca8552010-03-02 11:57:30 -0800945 } else
946 return (true);
947
948 return (false);
Jason Evansc7177182010-02-11 09:25:56 -0800949}
950
Jason Evans22ca8552010-03-02 11:57:30 -0800951static bool
952prof_dump(const char *filename, bool leakcheck, bool propagate_err)
Jason Evans6109fe02010-02-10 10:37:56 -0800953{
954 prof_cnt_t cnt_all;
955 size_t tabind;
956 prof_bt_t *bt;
957 prof_ctx_t *ctx;
958 char buf[UMAX2S_BUFSIZE];
959 size_t leak_nctx;
960
961 prof_enter();
962 prof_dump_fd = creat(filename, 0644);
963 if (prof_dump_fd == -1) {
Jason Evans22ca8552010-03-02 11:57:30 -0800964 if (propagate_err == false) {
Jason Evans698805c2010-03-03 17:45:38 -0800965 malloc_write("<jemalloc>: creat(\"");
966 malloc_write(filename);
967 malloc_write("\", 0644) failed\n");
Jason Evans22ca8552010-03-02 11:57:30 -0800968 if (opt_abort)
969 abort();
970 }
Jason Evans22ca8552010-03-02 11:57:30 -0800971 goto ERROR;
Jason Evans6109fe02010-02-10 10:37:56 -0800972 }
973
974 /* Merge per thread profile stats, and sum them in cnt_all. */
975 memset(&cnt_all, 0, sizeof(prof_cnt_t));
976 leak_nctx = 0;
977 for (tabind = 0; ckh_iter(&bt2ctx, &tabind, NULL, (void **)&ctx)
978 == false;) {
979 prof_ctx_merge(ctx, &cnt_all, &leak_nctx);
980 }
981
982 /* Dump profile header. */
Jason Evans22ca8552010-03-02 11:57:30 -0800983 if (prof_write("heap profile: ", propagate_err)
984 || prof_write(umax2s(cnt_all.curobjs, 10, buf), propagate_err)
985 || prof_write(": ", propagate_err)
986 || prof_write(umax2s(cnt_all.curbytes, 10, buf), propagate_err)
987 || prof_write(" [", propagate_err)
988 || prof_write(umax2s(cnt_all.accumobjs, 10, buf), propagate_err)
989 || prof_write(": ", propagate_err)
990 || prof_write(umax2s(cnt_all.accumbytes, 10, buf), propagate_err))
991 goto ERROR;
992
993 if (opt_lg_prof_sample == 0) {
994 if (prof_write("] @ heapprofile\n", propagate_err))
995 goto ERROR;
996 } else {
997 if (prof_write("] @ heap_v2/", propagate_err)
998 || prof_write(umax2s((uint64_t)1U << opt_lg_prof_sample, 10,
999 buf), propagate_err)
1000 || prof_write("\n", propagate_err))
1001 goto ERROR;
Jason Evansb9477e72010-03-01 20:15:26 -08001002 }
Jason Evans6109fe02010-02-10 10:37:56 -08001003
1004 /* Dump per ctx profile stats. */
1005 for (tabind = 0; ckh_iter(&bt2ctx, &tabind, (void **)&bt, (void **)&ctx)
1006 == false;) {
Jason Evans22ca8552010-03-02 11:57:30 -08001007 if (prof_dump_ctx(ctx, bt, propagate_err))
1008 goto ERROR;
Jason Evans6109fe02010-02-10 10:37:56 -08001009 }
1010
Jason Evansc7177182010-02-11 09:25:56 -08001011 /* Dump /proc/<pid>/maps if possible. */
Jason Evans22ca8552010-03-02 11:57:30 -08001012 if (prof_dump_maps(propagate_err))
1013 goto ERROR;
Jason Evansc7177182010-02-11 09:25:56 -08001014
Jason Evans22ca8552010-03-02 11:57:30 -08001015 if (prof_flush(propagate_err))
1016 goto ERROR;
Jason Evans6109fe02010-02-10 10:37:56 -08001017 close(prof_dump_fd);
1018 prof_leave();
1019
1020 if (leakcheck && cnt_all.curbytes != 0) {
Jason Evans698805c2010-03-03 17:45:38 -08001021 malloc_write("<jemalloc>: Leak summary: ");
1022 malloc_write(umax2s(cnt_all.curbytes, 10, buf));
1023 malloc_write((cnt_all.curbytes != 1) ? " bytes, " : " byte, ");
1024 malloc_write(umax2s(cnt_all.curobjs, 10, buf));
1025 malloc_write((cnt_all.curobjs != 1) ? " objects, " :
1026 " object, ");
1027 malloc_write(umax2s(leak_nctx, 10, buf));
1028 malloc_write((leak_nctx != 1) ? " contexts\n" : " context\n");
1029 malloc_write("<jemalloc>: Run pprof on \"");
1030 malloc_write(filename);
1031 malloc_write("\" for leak detail\n");
Jason Evans6109fe02010-02-10 10:37:56 -08001032 }
Jason Evans22ca8552010-03-02 11:57:30 -08001033
1034 return (false);
1035ERROR:
1036 prof_leave();
1037 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -08001038}
1039
Jason Evansb01a6c22010-02-11 10:25:36 -08001040#define DUMP_FILENAME_BUFSIZE (PATH_MAX+ UMAX2S_BUFSIZE \
1041 + 1 \
1042 + UMAX2S_BUFSIZE \
1043 + 2 \
1044 + UMAX2S_BUFSIZE \
1045 + 5 + 1)
Jason Evans6109fe02010-02-10 10:37:56 -08001046static void
1047prof_dump_filename(char *filename, char v, int64_t vseq)
1048{
1049 char buf[UMAX2S_BUFSIZE];
1050 char *s;
1051 unsigned i, slen;
1052
Jason Evansb01a6c22010-02-11 10:25:36 -08001053 /*
1054 * Construct a filename of the form:
1055 *
1056 * <prefix>.<pid>.<seq>.v<vseq>.heap\0
1057 * or
1058 * jeprof.<pid>.<seq>.v<vseq>.heap\0
1059 */
1060
Jason Evans6109fe02010-02-10 10:37:56 -08001061 i = 0;
1062
Jason Evansb01a6c22010-02-11 10:25:36 -08001063 /*
1064 * Use JEMALLOC_PROF_PREFIX if it's set, and if it is short enough to
1065 * avoid overflowing DUMP_FILENAME_BUFSIZE. The result may exceed
1066 * PATH_MAX, but creat(2) will catch that problem.
1067 */
1068 if ((s = getenv("JEMALLOC_PROF_PREFIX")) != NULL
1069 && strlen(s) + (DUMP_FILENAME_BUFSIZE - PATH_MAX) <= PATH_MAX) {
1070 slen = strlen(s);
1071 memcpy(&filename[i], s, slen);
1072 i += slen;
1073
1074 s = ".";
1075 } else
1076 s = "jeprof.";
Jason Evans6109fe02010-02-10 10:37:56 -08001077 slen = strlen(s);
1078 memcpy(&filename[i], s, slen);
1079 i += slen;
1080
1081 s = umax2s(getpid(), 10, buf);
1082 slen = strlen(s);
1083 memcpy(&filename[i], s, slen);
1084 i += slen;
1085
1086 s = ".";
1087 slen = strlen(s);
1088 memcpy(&filename[i], s, slen);
1089 i += slen;
1090
1091 s = umax2s(prof_dump_seq, 10, buf);
1092 prof_dump_seq++;
1093 slen = strlen(s);
1094 memcpy(&filename[i], s, slen);
1095 i += slen;
1096
1097 s = ".";
1098 slen = strlen(s);
1099 memcpy(&filename[i], s, slen);
1100 i += slen;
1101
1102 filename[i] = v;
1103 i++;
1104
1105 if (vseq != 0xffffffffffffffffLLU) {
1106 s = umax2s(vseq, 10, buf);
1107 slen = strlen(s);
1108 memcpy(&filename[i], s, slen);
1109 i += slen;
1110 }
1111
1112 s = ".heap";
1113 slen = strlen(s);
1114 memcpy(&filename[i], s, slen);
1115 i += slen;
1116
1117 filename[i] = '\0';
1118}
1119
1120static void
1121prof_fdump(void)
1122{
1123 char filename[DUMP_FILENAME_BUFSIZE];
1124
1125 if (prof_booted == false)
1126 return;
1127
1128 malloc_mutex_lock(&prof_dump_seq_mtx);
1129 prof_dump_filename(filename, 'f', 0xffffffffffffffffLLU);
1130 malloc_mutex_unlock(&prof_dump_seq_mtx);
Jason Evans22ca8552010-03-02 11:57:30 -08001131 prof_dump(filename, opt_prof_leak, false);
Jason Evans6109fe02010-02-10 10:37:56 -08001132}
1133
1134void
1135prof_idump(void)
1136{
1137 char filename[DUMP_FILENAME_BUFSIZE];
1138
1139 if (prof_booted == false)
1140 return;
Jason Evansd34f9e72010-02-11 13:19:21 -08001141 malloc_mutex_lock(&enq_mtx);
1142 if (enq) {
1143 enq_idump = true;
1144 malloc_mutex_unlock(&enq_mtx);
1145 return;
1146 }
1147 malloc_mutex_unlock(&enq_mtx);
Jason Evans6109fe02010-02-10 10:37:56 -08001148
1149 malloc_mutex_lock(&prof_dump_seq_mtx);
1150 prof_dump_filename(filename, 'i', prof_dump_iseq);
1151 prof_dump_iseq++;
1152 malloc_mutex_unlock(&prof_dump_seq_mtx);
Jason Evans22ca8552010-03-02 11:57:30 -08001153 prof_dump(filename, false, false);
Jason Evans6109fe02010-02-10 10:37:56 -08001154}
1155
Jason Evans22ca8552010-03-02 11:57:30 -08001156bool
1157prof_mdump(const char *filename)
Jason Evans6109fe02010-02-10 10:37:56 -08001158{
Jason Evans22ca8552010-03-02 11:57:30 -08001159 char filename_buf[DUMP_FILENAME_BUFSIZE];
Jason Evans6109fe02010-02-10 10:37:56 -08001160
Jason Evans22ca8552010-03-02 11:57:30 -08001161 if (opt_prof == false || prof_booted == false)
1162 return (true);
Jason Evans6109fe02010-02-10 10:37:56 -08001163
Jason Evans22ca8552010-03-02 11:57:30 -08001164 if (filename == NULL) {
1165 /* No filename specified, so automatically generate one. */
1166 malloc_mutex_lock(&prof_dump_seq_mtx);
1167 prof_dump_filename(filename_buf, 'm', prof_dump_mseq);
1168 prof_dump_mseq++;
1169 malloc_mutex_unlock(&prof_dump_seq_mtx);
1170 filename = filename_buf;
1171 }
1172 return (prof_dump(filename, false, true));
Jason Evans6109fe02010-02-10 10:37:56 -08001173}
1174
1175void
1176prof_udump(void)
1177{
1178 char filename[DUMP_FILENAME_BUFSIZE];
1179
1180 if (prof_booted == false)
1181 return;
1182 malloc_mutex_lock(&enq_mtx);
1183 if (enq) {
1184 enq_udump = true;
1185 malloc_mutex_unlock(&enq_mtx);
1186 return;
1187 }
1188 malloc_mutex_unlock(&enq_mtx);
1189
1190 malloc_mutex_lock(&prof_dump_seq_mtx);
1191 prof_dump_filename(filename, 'u', prof_dump_useq);
1192 prof_dump_useq++;
1193 malloc_mutex_unlock(&prof_dump_seq_mtx);
Jason Evans22ca8552010-03-02 11:57:30 -08001194 prof_dump(filename, false, false);
Jason Evans6109fe02010-02-10 10:37:56 -08001195}
1196
1197static void
1198prof_bt_hash(const void *key, unsigned minbits, size_t *hash1, size_t *hash2)
1199{
1200 size_t ret1, ret2;
1201 uint64_t h;
1202 prof_bt_t *bt = (prof_bt_t *)key;
1203
1204 assert(minbits <= 32 || (SIZEOF_PTR == 8 && minbits <= 64));
1205 assert(hash1 != NULL);
1206 assert(hash2 != NULL);
1207
1208 h = hash(bt->vec, bt->len * sizeof(void *), 0x94122f335b332aeaLLU);
1209 if (minbits <= 32) {
1210 /*
1211 * Avoid doing multiple hashes, since a single hash provides
1212 * enough bits.
1213 */
1214 ret1 = h & ZU(0xffffffffU);
1215 ret2 = h >> 32;
1216 } else {
1217 ret1 = h;
1218 ret2 = hash(bt->vec, bt->len * sizeof(void *),
1219 0x8432a476666bbc13U);
1220 }
1221
1222 *hash1 = ret1;
1223 *hash2 = ret2;
1224}
1225
1226static bool
1227prof_bt_keycomp(const void *k1, const void *k2)
1228{
1229 const prof_bt_t *bt1 = (prof_bt_t *)k1;
1230 const prof_bt_t *bt2 = (prof_bt_t *)k2;
1231
1232 if (bt1->len != bt2->len)
1233 return (false);
1234 return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0);
1235}
1236
1237static void
1238bt2cnt_thread_cleanup(void *arg)
1239{
1240 ckh_t *bt2cnt;
1241
1242 bt2cnt = bt2cnt_tls;
1243 if (bt2cnt != NULL) {
1244 ql_head(prof_thr_cnt_t) cnts_ql;
1245 size_t tabind;
1246 prof_thr_cnt_t *cnt;
1247
1248 /* Iteratively merge cnt's into the global stats. */
1249 ql_new(&cnts_ql);
1250 tabind = 0;
1251 while (ckh_iter(bt2cnt, &tabind, NULL, (void **)&cnt) ==
1252 false) {
1253 prof_ctx_t *ctx = cnt->ctx;
1254 /* Merge stats and detach from ctx. */
1255 malloc_mutex_lock(&ctx->lock);
1256 ctx->cnt_merged.curobjs += cnt->cnts.curobjs;
1257 ctx->cnt_merged.curbytes += cnt->cnts.curbytes;
1258 ctx->cnt_merged.accumobjs += cnt->cnts.accumobjs;
1259 ctx->cnt_merged.accumbytes += cnt->cnts.accumbytes;
1260 ql_remove(&ctx->cnts_ql, cnt, link);
1261 malloc_mutex_unlock(&ctx->lock);
1262
1263 /*
1264 * Stash cnt for deletion after finishing with
1265 * ckh_iter().
1266 */
1267 ql_tail_insert(&cnts_ql, cnt, link);
1268 }
1269
1270 /*
1271 * Delete the hash table now that cnts_ql has a list of all
1272 * cnt's.
1273 */
1274 ckh_delete(bt2cnt);
1275 idalloc(bt2cnt);
1276 bt2cnt_tls = NULL;
1277
1278 /* Delete cnt's. */
1279 while ((cnt = ql_last(&cnts_ql, link)) != NULL) {
1280 ql_remove(&cnts_ql, cnt, link);
1281 idalloc(cnt);
1282 }
1283 }
1284}
1285
1286void
1287prof_boot0(void)
1288{
1289
1290 /*
Jason Evans0b270a92010-03-31 16:45:04 -07001291 * opt_prof and prof_promote must be in their final state before any
1292 * arenas are initialized, so this function must be executed early.
Jason Evans6109fe02010-02-10 10:37:56 -08001293 */
1294
1295 if (opt_prof_leak && opt_prof == false) {
1296 /*
1297 * Enable opt_prof, but in such a way that profiles are never
1298 * automatically dumped.
1299 */
1300 opt_prof = true;
1301 opt_prof_udump = false;
1302 prof_interval = 0;
Jason Evansa02fc082010-03-31 17:35:51 -07001303 } else if (opt_prof) {
1304 if (opt_lg_prof_interval >= 0) {
1305 prof_interval = (((uint64_t)1U) <<
1306 opt_lg_prof_interval);
1307 } else
1308 prof_interval = 0;
1309 }
Jason Evans0b270a92010-03-31 16:45:04 -07001310
1311 prof_promote = (opt_prof && opt_lg_prof_sample > PAGE_SHIFT);
Jason Evans6109fe02010-02-10 10:37:56 -08001312}
1313
1314bool
1315prof_boot1(void)
1316{
1317
1318 if (opt_prof) {
Jason Evans6109fe02010-02-10 10:37:56 -08001319 if (ckh_new(&bt2ctx, PROF_CKH_MINITEMS, prof_bt_hash,
1320 prof_bt_keycomp))
1321 return (true);
1322 if (malloc_mutex_init(&bt2ctx_mtx))
1323 return (true);
1324 if (pthread_key_create(&bt2cnt_tsd, bt2cnt_thread_cleanup)
1325 != 0) {
Jason Evans698805c2010-03-03 17:45:38 -08001326 malloc_write(
1327 "<jemalloc>: Error in pthread_key_create()\n");
Jason Evans6109fe02010-02-10 10:37:56 -08001328 abort();
1329 }
1330
1331 prof_bt_max = (1U << opt_lg_prof_bt_max);
1332 if (malloc_mutex_init(&prof_dump_seq_mtx))
1333 return (true);
1334
1335 if (malloc_mutex_init(&enq_mtx))
1336 return (true);
1337 enq = false;
Jason Evansd34f9e72010-02-11 13:19:21 -08001338 enq_idump = false;
Jason Evans6109fe02010-02-10 10:37:56 -08001339 enq_udump = false;
1340
1341 if (atexit(prof_fdump) != 0) {
Jason Evans698805c2010-03-03 17:45:38 -08001342 malloc_write("<jemalloc>: Error in atexit()\n");
Jason Evans6109fe02010-02-10 10:37:56 -08001343 if (opt_abort)
1344 abort();
1345 }
1346 }
1347
Jason Evansb27805b2010-02-10 18:15:53 -08001348#ifdef JEMALLOC_PROF_LIBGCC
1349 /*
1350 * Cause the backtracing machinery to allocate its internal state
1351 * before enabling profiling.
1352 */
1353 _Unwind_Backtrace(prof_unwind_init_callback, NULL);
1354#endif
1355
Jason Evans6109fe02010-02-10 10:37:56 -08001356 prof_booted = true;
1357
1358 return (false);
1359}
1360
Jason Evans6109fe02010-02-10 10:37:56 -08001361/******************************************************************************/
1362#endif /* JEMALLOC_PROF */