xref: /redis-3.2.3/deps/jemalloc/src/prof.c (revision 80586cb8)
1 #define	JEMALLOC_PROF_C_
2 #include "jemalloc/internal/jemalloc_internal.h"
3 #ifdef JEMALLOC_PROF
4 /******************************************************************************/
5 
6 #ifdef JEMALLOC_PROF_LIBUNWIND
7 #define	UNW_LOCAL_ONLY
8 #include <libunwind.h>
9 #endif
10 
11 #ifdef JEMALLOC_PROF_LIBGCC
12 #include <unwind.h>
13 #endif
14 
15 /******************************************************************************/
16 /* Data. */
17 
18 bool		opt_prof = false;
19 bool		opt_prof_active = true;
20 size_t		opt_lg_prof_bt_max = LG_PROF_BT_MAX_DEFAULT;
21 size_t		opt_lg_prof_sample = LG_PROF_SAMPLE_DEFAULT;
22 ssize_t		opt_lg_prof_interval = LG_PROF_INTERVAL_DEFAULT;
23 bool		opt_prof_gdump = false;
24 bool		opt_prof_leak = false;
25 bool		opt_prof_accum = true;
26 ssize_t		opt_lg_prof_tcmax = LG_PROF_TCMAX_DEFAULT;
27 char		opt_prof_prefix[PATH_MAX + 1];
28 
29 uint64_t	prof_interval;
30 bool		prof_promote;
31 
32 unsigned	prof_bt_max;
33 
34 #ifndef NO_TLS
35 __thread prof_tdata_t	*prof_tdata_tls
36     JEMALLOC_ATTR(tls_model("initial-exec"));
37 #endif
38 pthread_key_t	prof_tdata_tsd;
39 
40 /*
41  * Global hash of (prof_bt_t *)-->(prof_ctx_t *).  This is the master data
42  * structure that knows about all backtraces currently captured.
43  */
44 static ckh_t		bt2ctx;
45 static malloc_mutex_t	bt2ctx_mtx;
46 
47 static malloc_mutex_t	prof_dump_seq_mtx;
48 static uint64_t		prof_dump_seq;
49 static uint64_t		prof_dump_iseq;
50 static uint64_t		prof_dump_mseq;
51 static uint64_t		prof_dump_useq;
52 
53 /*
54  * This buffer is rather large for stack allocation, so use a single buffer for
55  * all profile dumps.  The buffer is implicitly protected by bt2ctx_mtx, since
56  * it must be locked anyway during dumping.
57  */
58 static char		prof_dump_buf[PROF_DUMP_BUF_SIZE];
59 static unsigned		prof_dump_buf_end;
60 static int		prof_dump_fd;
61 
62 /* Do not dump any profiles until bootstrapping is complete. */
63 static bool		prof_booted = false;
64 
65 static malloc_mutex_t	enq_mtx;
66 static bool		enq;
67 static bool		enq_idump;
68 static bool		enq_gdump;
69 
70 /******************************************************************************/
71 /* Function prototypes for non-inline static functions. */
72 
73 static prof_bt_t	*bt_dup(prof_bt_t *bt);
74 static void	bt_destroy(prof_bt_t *bt);
75 #ifdef JEMALLOC_PROF_LIBGCC
76 static _Unwind_Reason_Code	prof_unwind_init_callback(
77     struct _Unwind_Context *context, void *arg);
78 static _Unwind_Reason_Code	prof_unwind_callback(
79     struct _Unwind_Context *context, void *arg);
80 #endif
81 static bool	prof_flush(bool propagate_err);
82 static bool	prof_write(const char *s, bool propagate_err);
83 static void	prof_ctx_sum(prof_ctx_t *ctx, prof_cnt_t *cnt_all,
84     size_t *leak_nctx);
85 static void	prof_ctx_destroy(prof_ctx_t *ctx);
86 static void	prof_ctx_merge(prof_ctx_t *ctx, prof_thr_cnt_t *cnt);
87 static bool	prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt,
88     bool propagate_err);
89 static bool	prof_dump_maps(bool propagate_err);
90 static bool	prof_dump(const char *filename, bool leakcheck,
91     bool propagate_err);
92 static void	prof_dump_filename(char *filename, char v, int64_t vseq);
93 static void	prof_fdump(void);
94 static void	prof_bt_hash(const void *key, unsigned minbits, size_t *hash1,
95     size_t *hash2);
96 static bool	prof_bt_keycomp(const void *k1, const void *k2);
97 static void	prof_tdata_cleanup(void *arg);
98 
99 /******************************************************************************/
100 
101 void
102 bt_init(prof_bt_t *bt, void **vec)
103 {
104 
105 	bt->vec = vec;
106 	bt->len = 0;
107 }
108 
109 static void
110 bt_destroy(prof_bt_t *bt)
111 {
112 
113 	idalloc(bt);
114 }
115 
116 static prof_bt_t *
117 bt_dup(prof_bt_t *bt)
118 {
119 	prof_bt_t *ret;
120 
121 	/*
122 	 * Create a single allocation that has space for vec immediately
123 	 * following the prof_bt_t structure.  The backtraces that get
124 	 * stored in the backtrace caches are copied from stack-allocated
125 	 * temporary variables, so size is known at creation time.  Making this
126 	 * a contiguous object improves cache locality.
127 	 */
128 	ret = (prof_bt_t *)imalloc(QUANTUM_CEILING(sizeof(prof_bt_t)) +
129 	    (bt->len * sizeof(void *)));
130 	if (ret == NULL)
131 		return (NULL);
132 	ret->vec = (void **)((uintptr_t)ret +
133 	    QUANTUM_CEILING(sizeof(prof_bt_t)));
134 	memcpy(ret->vec, bt->vec, bt->len * sizeof(void *));
135 	ret->len = bt->len;
136 
137 	return (ret);
138 }
139 
140 static inline void
141 prof_enter(void)
142 {
143 
144 	malloc_mutex_lock(&enq_mtx);
145 	enq = true;
146 	malloc_mutex_unlock(&enq_mtx);
147 
148 	malloc_mutex_lock(&bt2ctx_mtx);
149 }
150 
151 static inline void
152 prof_leave(void)
153 {
154 	bool idump, gdump;
155 
156 	malloc_mutex_unlock(&bt2ctx_mtx);
157 
158 	malloc_mutex_lock(&enq_mtx);
159 	enq = false;
160 	idump = enq_idump;
161 	enq_idump = false;
162 	gdump = enq_gdump;
163 	enq_gdump = false;
164 	malloc_mutex_unlock(&enq_mtx);
165 
166 	if (idump)
167 		prof_idump();
168 	if (gdump)
169 		prof_gdump();
170 }
171 
172 #ifdef JEMALLOC_PROF_LIBUNWIND
173 void
174 prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
175 {
176 	unw_context_t uc;
177 	unw_cursor_t cursor;
178 	unsigned i;
179 	int err;
180 
181 	assert(bt->len == 0);
182 	assert(bt->vec != NULL);
183 	assert(max <= (1U << opt_lg_prof_bt_max));
184 
185 	unw_getcontext(&uc);
186 	unw_init_local(&cursor, &uc);
187 
188 	/* Throw away (nignore+1) stack frames, if that many exist. */
189 	for (i = 0; i < nignore + 1; i++) {
190 		err = unw_step(&cursor);
191 		if (err <= 0)
192 			return;
193 	}
194 
195 	/*
196 	 * Iterate over stack frames until there are no more, or until no space
197 	 * remains in bt.
198 	 */
199 	for (i = 0; i < max; i++) {
200 		unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *)&bt->vec[i]);
201 		bt->len++;
202 		err = unw_step(&cursor);
203 		if (err <= 0)
204 			break;
205 	}
206 }
207 #endif
208 #ifdef JEMALLOC_PROF_LIBGCC
209 static _Unwind_Reason_Code
210 prof_unwind_init_callback(struct _Unwind_Context *context, void *arg)
211 {
212 
213 	return (_URC_NO_REASON);
214 }
215 
216 static _Unwind_Reason_Code
217 prof_unwind_callback(struct _Unwind_Context *context, void *arg)
218 {
219 	prof_unwind_data_t *data = (prof_unwind_data_t *)arg;
220 
221 	if (data->nignore > 0)
222 		data->nignore--;
223 	else {
224 		data->bt->vec[data->bt->len] = (void *)_Unwind_GetIP(context);
225 		data->bt->len++;
226 		if (data->bt->len == data->max)
227 			return (_URC_END_OF_STACK);
228 	}
229 
230 	return (_URC_NO_REASON);
231 }
232 
233 void
234 prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
235 {
236 	prof_unwind_data_t data = {bt, nignore, max};
237 
238 	_Unwind_Backtrace(prof_unwind_callback, &data);
239 }
240 #endif
241 #ifdef JEMALLOC_PROF_GCC
242 void
243 prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
244 {
245 #define	BT_FRAME(i)							\
246 	if ((i) < nignore + max) {					\
247 		void *p;						\
248 		if (__builtin_frame_address(i) == 0)			\
249 			return;						\
250 		p = __builtin_return_address(i);			\
251 		if (p == NULL)						\
252 			return;						\
253 		if (i >= nignore) {					\
254 			bt->vec[(i) - nignore] = p;			\
255 			bt->len = (i) - nignore + 1;			\
256 		}							\
257 	} else								\
258 		return;
259 
260 	assert(nignore <= 3);
261 	assert(max <= (1U << opt_lg_prof_bt_max));
262 
263 	BT_FRAME(0)
264 	BT_FRAME(1)
265 	BT_FRAME(2)
266 	BT_FRAME(3)
267 	BT_FRAME(4)
268 	BT_FRAME(5)
269 	BT_FRAME(6)
270 	BT_FRAME(7)
271 	BT_FRAME(8)
272 	BT_FRAME(9)
273 
274 	BT_FRAME(10)
275 	BT_FRAME(11)
276 	BT_FRAME(12)
277 	BT_FRAME(13)
278 	BT_FRAME(14)
279 	BT_FRAME(15)
280 	BT_FRAME(16)
281 	BT_FRAME(17)
282 	BT_FRAME(18)
283 	BT_FRAME(19)
284 
285 	BT_FRAME(20)
286 	BT_FRAME(21)
287 	BT_FRAME(22)
288 	BT_FRAME(23)
289 	BT_FRAME(24)
290 	BT_FRAME(25)
291 	BT_FRAME(26)
292 	BT_FRAME(27)
293 	BT_FRAME(28)
294 	BT_FRAME(29)
295 
296 	BT_FRAME(30)
297 	BT_FRAME(31)
298 	BT_FRAME(32)
299 	BT_FRAME(33)
300 	BT_FRAME(34)
301 	BT_FRAME(35)
302 	BT_FRAME(36)
303 	BT_FRAME(37)
304 	BT_FRAME(38)
305 	BT_FRAME(39)
306 
307 	BT_FRAME(40)
308 	BT_FRAME(41)
309 	BT_FRAME(42)
310 	BT_FRAME(43)
311 	BT_FRAME(44)
312 	BT_FRAME(45)
313 	BT_FRAME(46)
314 	BT_FRAME(47)
315 	BT_FRAME(48)
316 	BT_FRAME(49)
317 
318 	BT_FRAME(50)
319 	BT_FRAME(51)
320 	BT_FRAME(52)
321 	BT_FRAME(53)
322 	BT_FRAME(54)
323 	BT_FRAME(55)
324 	BT_FRAME(56)
325 	BT_FRAME(57)
326 	BT_FRAME(58)
327 	BT_FRAME(59)
328 
329 	BT_FRAME(60)
330 	BT_FRAME(61)
331 	BT_FRAME(62)
332 	BT_FRAME(63)
333 	BT_FRAME(64)
334 	BT_FRAME(65)
335 	BT_FRAME(66)
336 	BT_FRAME(67)
337 	BT_FRAME(68)
338 	BT_FRAME(69)
339 
340 	BT_FRAME(70)
341 	BT_FRAME(71)
342 	BT_FRAME(72)
343 	BT_FRAME(73)
344 	BT_FRAME(74)
345 	BT_FRAME(75)
346 	BT_FRAME(76)
347 	BT_FRAME(77)
348 	BT_FRAME(78)
349 	BT_FRAME(79)
350 
351 	BT_FRAME(80)
352 	BT_FRAME(81)
353 	BT_FRAME(82)
354 	BT_FRAME(83)
355 	BT_FRAME(84)
356 	BT_FRAME(85)
357 	BT_FRAME(86)
358 	BT_FRAME(87)
359 	BT_FRAME(88)
360 	BT_FRAME(89)
361 
362 	BT_FRAME(90)
363 	BT_FRAME(91)
364 	BT_FRAME(92)
365 	BT_FRAME(93)
366 	BT_FRAME(94)
367 	BT_FRAME(95)
368 	BT_FRAME(96)
369 	BT_FRAME(97)
370 	BT_FRAME(98)
371 	BT_FRAME(99)
372 
373 	BT_FRAME(100)
374 	BT_FRAME(101)
375 	BT_FRAME(102)
376 	BT_FRAME(103)
377 	BT_FRAME(104)
378 	BT_FRAME(105)
379 	BT_FRAME(106)
380 	BT_FRAME(107)
381 	BT_FRAME(108)
382 	BT_FRAME(109)
383 
384 	BT_FRAME(110)
385 	BT_FRAME(111)
386 	BT_FRAME(112)
387 	BT_FRAME(113)
388 	BT_FRAME(114)
389 	BT_FRAME(115)
390 	BT_FRAME(116)
391 	BT_FRAME(117)
392 	BT_FRAME(118)
393 	BT_FRAME(119)
394 
395 	BT_FRAME(120)
396 	BT_FRAME(121)
397 	BT_FRAME(122)
398 	BT_FRAME(123)
399 	BT_FRAME(124)
400 	BT_FRAME(125)
401 	BT_FRAME(126)
402 	BT_FRAME(127)
403 
404 	/* Extras to compensate for nignore. */
405 	BT_FRAME(128)
406 	BT_FRAME(129)
407 	BT_FRAME(130)
408 #undef BT_FRAME
409 }
410 #endif
411 
412 prof_thr_cnt_t *
413 prof_lookup(prof_bt_t *bt)
414 {
415 	union {
416 		prof_thr_cnt_t	*p;
417 		void		*v;
418 	} ret;
419 	prof_tdata_t *prof_tdata;
420 
421 	prof_tdata = PROF_TCACHE_GET();
422 	if (prof_tdata == NULL) {
423 		prof_tdata = prof_tdata_init();
424 		if (prof_tdata == NULL)
425 			return (NULL);
426 	}
427 
428 	if (ckh_search(&prof_tdata->bt2cnt, bt, NULL, &ret.v)) {
429 		union {
430 			prof_bt_t	*p;
431 			void		*v;
432 		} btkey;
433 		union {
434 			prof_ctx_t	*p;
435 			void		*v;
436 		} ctx;
437 		bool new_ctx;
438 
439 		/*
440 		 * This thread's cache lacks bt.  Look for it in the global
441 		 * cache.
442 		 */
443 		prof_enter();
444 		if (ckh_search(&bt2ctx, bt, &btkey.v, &ctx.v)) {
445 			/* bt has never been seen before.  Insert it. */
446 			ctx.v = imalloc(sizeof(prof_ctx_t));
447 			if (ctx.v == NULL) {
448 				prof_leave();
449 				return (NULL);
450 			}
451 			btkey.p = bt_dup(bt);
452 			if (btkey.v == NULL) {
453 				prof_leave();
454 				idalloc(ctx.v);
455 				return (NULL);
456 			}
457 			ctx.p->bt = btkey.p;
458 			if (malloc_mutex_init(&ctx.p->lock)) {
459 				prof_leave();
460 				idalloc(btkey.v);
461 				idalloc(ctx.v);
462 				return (NULL);
463 			}
464 			memset(&ctx.p->cnt_merged, 0, sizeof(prof_cnt_t));
465 			ql_new(&ctx.p->cnts_ql);
466 			if (ckh_insert(&bt2ctx, btkey.v, ctx.v)) {
467 				/* OOM. */
468 				prof_leave();
469 				malloc_mutex_destroy(&ctx.p->lock);
470 				idalloc(btkey.v);
471 				idalloc(ctx.v);
472 				return (NULL);
473 			}
474 			/*
475 			 * Artificially raise curobjs, in order to avoid a race
476 			 * condition with prof_ctx_merge()/prof_ctx_destroy().
477 			 *
478 			 * No locking is necessary for ctx here because no other
479 			 * threads have had the opportunity to fetch it from
480 			 * bt2ctx yet.
481 			 */
482 			ctx.p->cnt_merged.curobjs++;
483 			new_ctx = true;
484 		} else {
485 			/*
486 			 * Artificially raise curobjs, in order to avoid a race
487 			 * condition with prof_ctx_merge()/prof_ctx_destroy().
488 			 */
489 			malloc_mutex_lock(&ctx.p->lock);
490 			ctx.p->cnt_merged.curobjs++;
491 			malloc_mutex_unlock(&ctx.p->lock);
492 			new_ctx = false;
493 		}
494 		prof_leave();
495 
496 		/* Link a prof_thd_cnt_t into ctx for this thread. */
497 		if (opt_lg_prof_tcmax >= 0 && ckh_count(&prof_tdata->bt2cnt)
498 		    == (ZU(1) << opt_lg_prof_tcmax)) {
499 			assert(ckh_count(&prof_tdata->bt2cnt) > 0);
500 			/*
501 			 * Flush the least recently used cnt in order to keep
502 			 * bt2cnt from becoming too large.
503 			 */
504 			ret.p = ql_last(&prof_tdata->lru_ql, lru_link);
505 			assert(ret.v != NULL);
506 			if (ckh_remove(&prof_tdata->bt2cnt, ret.p->ctx->bt,
507 			    NULL, NULL))
508 				assert(false);
509 			ql_remove(&prof_tdata->lru_ql, ret.p, lru_link);
510 			prof_ctx_merge(ret.p->ctx, ret.p);
511 			/* ret can now be re-used. */
512 		} else {
513 			assert(opt_lg_prof_tcmax < 0 ||
514 			    ckh_count(&prof_tdata->bt2cnt) < (ZU(1) <<
515 			    opt_lg_prof_tcmax));
516 			/* Allocate and partially initialize a new cnt. */
517 			ret.v = imalloc(sizeof(prof_thr_cnt_t));
518 			if (ret.p == NULL) {
519 				if (new_ctx)
520 					prof_ctx_destroy(ctx.p);
521 				return (NULL);
522 			}
523 			ql_elm_new(ret.p, cnts_link);
524 			ql_elm_new(ret.p, lru_link);
525 		}
526 		/* Finish initializing ret. */
527 		ret.p->ctx = ctx.p;
528 		ret.p->epoch = 0;
529 		memset(&ret.p->cnts, 0, sizeof(prof_cnt_t));
530 		if (ckh_insert(&prof_tdata->bt2cnt, btkey.v, ret.v)) {
531 			if (new_ctx)
532 				prof_ctx_destroy(ctx.p);
533 			idalloc(ret.v);
534 			return (NULL);
535 		}
536 		ql_head_insert(&prof_tdata->lru_ql, ret.p, lru_link);
537 		malloc_mutex_lock(&ctx.p->lock);
538 		ql_tail_insert(&ctx.p->cnts_ql, ret.p, cnts_link);
539 		ctx.p->cnt_merged.curobjs--;
540 		malloc_mutex_unlock(&ctx.p->lock);
541 	} else {
542 		/* Move ret to the front of the LRU. */
543 		ql_remove(&prof_tdata->lru_ql, ret.p, lru_link);
544 		ql_head_insert(&prof_tdata->lru_ql, ret.p, lru_link);
545 	}
546 
547 	return (ret.p);
548 }
549 
550 static bool
551 prof_flush(bool propagate_err)
552 {
553 	bool ret = false;
554 	ssize_t err;
555 
556 	err = write(prof_dump_fd, prof_dump_buf, prof_dump_buf_end);
557 	if (err == -1) {
558 		if (propagate_err == false) {
559 			malloc_write("<jemalloc>: write() failed during heap "
560 			    "profile flush\n");
561 			if (opt_abort)
562 				abort();
563 		}
564 		ret = true;
565 	}
566 	prof_dump_buf_end = 0;
567 
568 	return (ret);
569 }
570 
571 static bool
572 prof_write(const char *s, bool propagate_err)
573 {
574 	unsigned i, slen, n;
575 
576 	i = 0;
577 	slen = strlen(s);
578 	while (i < slen) {
579 		/* Flush the buffer if it is full. */
580 		if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE)
581 			if (prof_flush(propagate_err) && propagate_err)
582 				return (true);
583 
584 		if (prof_dump_buf_end + slen <= PROF_DUMP_BUF_SIZE) {
585 			/* Finish writing. */
586 			n = slen - i;
587 		} else {
588 			/* Write as much of s as will fit. */
589 			n = PROF_DUMP_BUF_SIZE - prof_dump_buf_end;
590 		}
591 		memcpy(&prof_dump_buf[prof_dump_buf_end], &s[i], n);
592 		prof_dump_buf_end += n;
593 		i += n;
594 	}
595 
596 	return (false);
597 }
598 
599 static void
600 prof_ctx_sum(prof_ctx_t *ctx, prof_cnt_t *cnt_all, size_t *leak_nctx)
601 {
602 	prof_thr_cnt_t *thr_cnt;
603 	prof_cnt_t tcnt;
604 
605 	malloc_mutex_lock(&ctx->lock);
606 
607 	memcpy(&ctx->cnt_summed, &ctx->cnt_merged, sizeof(prof_cnt_t));
608 	ql_foreach(thr_cnt, &ctx->cnts_ql, cnts_link) {
609 		volatile unsigned *epoch = &thr_cnt->epoch;
610 
611 		while (true) {
612 			unsigned epoch0 = *epoch;
613 
614 			/* Make sure epoch is even. */
615 			if (epoch0 & 1U)
616 				continue;
617 
618 			memcpy(&tcnt, &thr_cnt->cnts, sizeof(prof_cnt_t));
619 
620 			/* Terminate if epoch didn't change while reading. */
621 			if (*epoch == epoch0)
622 				break;
623 		}
624 
625 		ctx->cnt_summed.curobjs += tcnt.curobjs;
626 		ctx->cnt_summed.curbytes += tcnt.curbytes;
627 		if (opt_prof_accum) {
628 			ctx->cnt_summed.accumobjs += tcnt.accumobjs;
629 			ctx->cnt_summed.accumbytes += tcnt.accumbytes;
630 		}
631 	}
632 
633 	if (ctx->cnt_summed.curobjs != 0)
634 		(*leak_nctx)++;
635 
636 	/* Add to cnt_all. */
637 	cnt_all->curobjs += ctx->cnt_summed.curobjs;
638 	cnt_all->curbytes += ctx->cnt_summed.curbytes;
639 	if (opt_prof_accum) {
640 		cnt_all->accumobjs += ctx->cnt_summed.accumobjs;
641 		cnt_all->accumbytes += ctx->cnt_summed.accumbytes;
642 	}
643 
644 	malloc_mutex_unlock(&ctx->lock);
645 }
646 
647 static void
648 prof_ctx_destroy(prof_ctx_t *ctx)
649 {
650 
651 	/*
652 	 * Check that ctx is still unused by any thread cache before destroying
653 	 * it.  prof_lookup() artificially raises ctx->cnt_merge.curobjs in
654 	 * order to avoid a race condition with this function, as does
655 	 * prof_ctx_merge() in order to avoid a race between the main body of
656 	 * prof_ctx_merge() and entry into this function.
657 	 */
658 	prof_enter();
659 	malloc_mutex_lock(&ctx->lock);
660 	if (ql_first(&ctx->cnts_ql) == NULL && ctx->cnt_merged.curobjs == 1) {
661 		assert(ctx->cnt_merged.curbytes == 0);
662 		assert(ctx->cnt_merged.accumobjs == 0);
663 		assert(ctx->cnt_merged.accumbytes == 0);
664 		/* Remove ctx from bt2ctx. */
665 		if (ckh_remove(&bt2ctx, ctx->bt, NULL, NULL))
666 			assert(false);
667 		prof_leave();
668 		/* Destroy ctx. */
669 		malloc_mutex_unlock(&ctx->lock);
670 		bt_destroy(ctx->bt);
671 		malloc_mutex_destroy(&ctx->lock);
672 		idalloc(ctx);
673 	} else {
674 		/*
675 		 * Compensate for increment in prof_ctx_merge() or
676 		 * prof_lookup().
677 		 */
678 		ctx->cnt_merged.curobjs--;
679 		malloc_mutex_unlock(&ctx->lock);
680 		prof_leave();
681 	}
682 }
683 
684 static void
685 prof_ctx_merge(prof_ctx_t *ctx, prof_thr_cnt_t *cnt)
686 {
687 	bool destroy;
688 
689 	/* Merge cnt stats and detach from ctx. */
690 	malloc_mutex_lock(&ctx->lock);
691 	ctx->cnt_merged.curobjs += cnt->cnts.curobjs;
692 	ctx->cnt_merged.curbytes += cnt->cnts.curbytes;
693 	ctx->cnt_merged.accumobjs += cnt->cnts.accumobjs;
694 	ctx->cnt_merged.accumbytes += cnt->cnts.accumbytes;
695 	ql_remove(&ctx->cnts_ql, cnt, cnts_link);
696 	if (opt_prof_accum == false && ql_first(&ctx->cnts_ql) == NULL &&
697 	    ctx->cnt_merged.curobjs == 0) {
698 		/*
699 		 * Artificially raise ctx->cnt_merged.curobjs in order to keep
700 		 * another thread from winning the race to destroy ctx while
701 		 * this one has ctx->lock dropped.  Without this, it would be
702 		 * possible for another thread to:
703 		 *
704 		 * 1) Sample an allocation associated with ctx.
705 		 * 2) Deallocate the sampled object.
706 		 * 3) Successfully prof_ctx_destroy(ctx).
707 		 *
708 		 * The result would be that ctx no longer exists by the time
709 		 * this thread accesses it in prof_ctx_destroy().
710 		 */
711 		ctx->cnt_merged.curobjs++;
712 		destroy = true;
713 	} else
714 		destroy = false;
715 	malloc_mutex_unlock(&ctx->lock);
716 	if (destroy)
717 		prof_ctx_destroy(ctx);
718 }
719 
720 static bool
721 prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt, bool propagate_err)
722 {
723 	char buf[UMAX2S_BUFSIZE];
724 	unsigned i;
725 
726 	if (opt_prof_accum == false && ctx->cnt_summed.curobjs == 0) {
727 		assert(ctx->cnt_summed.curbytes == 0);
728 		assert(ctx->cnt_summed.accumobjs == 0);
729 		assert(ctx->cnt_summed.accumbytes == 0);
730 		return (false);
731 	}
732 
733 	if (prof_write(u2s(ctx->cnt_summed.curobjs, 10, buf), propagate_err)
734 	    || prof_write(": ", propagate_err)
735 	    || prof_write(u2s(ctx->cnt_summed.curbytes, 10, buf),
736 	    propagate_err)
737 	    || prof_write(" [", propagate_err)
738 	    || prof_write(u2s(ctx->cnt_summed.accumobjs, 10, buf),
739 	    propagate_err)
740 	    || prof_write(": ", propagate_err)
741 	    || prof_write(u2s(ctx->cnt_summed.accumbytes, 10, buf),
742 	    propagate_err)
743 	    || prof_write("] @", propagate_err))
744 		return (true);
745 
746 	for (i = 0; i < bt->len; i++) {
747 		if (prof_write(" 0x", propagate_err)
748 		    || prof_write(u2s((uintptr_t)bt->vec[i], 16, buf),
749 		    propagate_err))
750 			return (true);
751 	}
752 
753 	if (prof_write("\n", propagate_err))
754 		return (true);
755 
756 	return (false);
757 }
758 
759 static bool
760 prof_dump_maps(bool propagate_err)
761 {
762 	int mfd;
763 	char buf[UMAX2S_BUFSIZE];
764 	char *s;
765 	unsigned i, slen;
766 	/*         /proc/<pid>/maps\0 */
767 	char mpath[6     + UMAX2S_BUFSIZE
768 			      + 5  + 1];
769 
770 	i = 0;
771 
772 	s = "/proc/";
773 	slen = strlen(s);
774 	memcpy(&mpath[i], s, slen);
775 	i += slen;
776 
777 	s = u2s(getpid(), 10, buf);
778 	slen = strlen(s);
779 	memcpy(&mpath[i], s, slen);
780 	i += slen;
781 
782 	s = "/maps";
783 	slen = strlen(s);
784 	memcpy(&mpath[i], s, slen);
785 	i += slen;
786 
787 	mpath[i] = '\0';
788 
789 	mfd = open(mpath, O_RDONLY);
790 	if (mfd != -1) {
791 		ssize_t nread;
792 
793 		if (prof_write("\nMAPPED_LIBRARIES:\n", propagate_err) &&
794 		    propagate_err)
795 			return (true);
796 		nread = 0;
797 		do {
798 			prof_dump_buf_end += nread;
799 			if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE) {
800 				/* Make space in prof_dump_buf before read(). */
801 				if (prof_flush(propagate_err) && propagate_err)
802 					return (true);
803 			}
804 			nread = read(mfd, &prof_dump_buf[prof_dump_buf_end],
805 			    PROF_DUMP_BUF_SIZE - prof_dump_buf_end);
806 		} while (nread > 0);
807 		close(mfd);
808 	} else
809 		return (true);
810 
811 	return (false);
812 }
813 
814 static bool
815 prof_dump(const char *filename, bool leakcheck, bool propagate_err)
816 {
817 	prof_cnt_t cnt_all;
818 	size_t tabind;
819 	union {
820 		prof_bt_t	*p;
821 		void		*v;
822 	} bt;
823 	union {
824 		prof_ctx_t	*p;
825 		void		*v;
826 	} ctx;
827 	char buf[UMAX2S_BUFSIZE];
828 	size_t leak_nctx;
829 
830 	prof_enter();
831 	prof_dump_fd = creat(filename, 0644);
832 	if (prof_dump_fd == -1) {
833 		if (propagate_err == false) {
834 			malloc_write("<jemalloc>: creat(\"");
835 			malloc_write(filename);
836 			malloc_write("\", 0644) failed\n");
837 			if (opt_abort)
838 				abort();
839 		}
840 		goto ERROR;
841 	}
842 
843 	/* Merge per thread profile stats, and sum them in cnt_all. */
844 	memset(&cnt_all, 0, sizeof(prof_cnt_t));
845 	leak_nctx = 0;
846 	for (tabind = 0; ckh_iter(&bt2ctx, &tabind, NULL, &ctx.v) == false;)
847 		prof_ctx_sum(ctx.p, &cnt_all, &leak_nctx);
848 
849 	/* Dump profile header. */
850 	if (prof_write("heap profile: ", propagate_err)
851 	    || prof_write(u2s(cnt_all.curobjs, 10, buf), propagate_err)
852 	    || prof_write(": ", propagate_err)
853 	    || prof_write(u2s(cnt_all.curbytes, 10, buf), propagate_err)
854 	    || prof_write(" [", propagate_err)
855 	    || prof_write(u2s(cnt_all.accumobjs, 10, buf), propagate_err)
856 	    || prof_write(": ", propagate_err)
857 	    || prof_write(u2s(cnt_all.accumbytes, 10, buf), propagate_err))
858 		goto ERROR;
859 
860 	if (opt_lg_prof_sample == 0) {
861 		if (prof_write("] @ heapprofile\n", propagate_err))
862 			goto ERROR;
863 	} else {
864 		if (prof_write("] @ heap_v2/", propagate_err)
865 		    || prof_write(u2s((uint64_t)1U << opt_lg_prof_sample, 10,
866 		    buf), propagate_err)
867 		    || prof_write("\n", propagate_err))
868 			goto ERROR;
869 	}
870 
871 	/* Dump  per ctx profile stats. */
872 	for (tabind = 0; ckh_iter(&bt2ctx, &tabind, &bt.v, &ctx.v)
873 	    == false;) {
874 		if (prof_dump_ctx(ctx.p, bt.p, propagate_err))
875 			goto ERROR;
876 	}
877 
878 	/* Dump /proc/<pid>/maps if possible. */
879 	if (prof_dump_maps(propagate_err))
880 		goto ERROR;
881 
882 	if (prof_flush(propagate_err))
883 		goto ERROR;
884 	close(prof_dump_fd);
885 	prof_leave();
886 
887 	if (leakcheck && cnt_all.curbytes != 0) {
888 		malloc_write("<jemalloc>: Leak summary: ");
889 		malloc_write(u2s(cnt_all.curbytes, 10, buf));
890 		malloc_write((cnt_all.curbytes != 1) ? " bytes, " : " byte, ");
891 		malloc_write(u2s(cnt_all.curobjs, 10, buf));
892 		malloc_write((cnt_all.curobjs != 1) ? " objects, " :
893 		    " object, ");
894 		malloc_write(u2s(leak_nctx, 10, buf));
895 		malloc_write((leak_nctx != 1) ? " contexts\n" : " context\n");
896 		malloc_write("<jemalloc>: Run pprof on \"");
897 		malloc_write(filename);
898 		malloc_write("\" for leak detail\n");
899 	}
900 
901 	return (false);
902 ERROR:
903 	prof_leave();
904 	return (true);
905 }
906 
907 #define	DUMP_FILENAME_BUFSIZE	(PATH_MAX+ UMAX2S_BUFSIZE		\
908 					       + 1			\
909 						+ UMAX2S_BUFSIZE	\
910 						     + 2		\
911 						       + UMAX2S_BUFSIZE	\
912 						             + 5  + 1)
913 static void
914 prof_dump_filename(char *filename, char v, int64_t vseq)
915 {
916 	char buf[UMAX2S_BUFSIZE];
917 	char *s;
918 	unsigned i, slen;
919 
920 	/*
921 	 * Construct a filename of the form:
922 	 *
923 	 *   <prefix>.<pid>.<seq>.v<vseq>.heap\0
924 	 */
925 
926 	i = 0;
927 
928 	s = opt_prof_prefix;
929 	slen = strlen(s);
930 	memcpy(&filename[i], s, slen);
931 	i += slen;
932 
933 	s = ".";
934 	slen = strlen(s);
935 	memcpy(&filename[i], s, slen);
936 	i += slen;
937 
938 	s = u2s(getpid(), 10, buf);
939 	slen = strlen(s);
940 	memcpy(&filename[i], s, slen);
941 	i += slen;
942 
943 	s = ".";
944 	slen = strlen(s);
945 	memcpy(&filename[i], s, slen);
946 	i += slen;
947 
948 	s = u2s(prof_dump_seq, 10, buf);
949 	prof_dump_seq++;
950 	slen = strlen(s);
951 	memcpy(&filename[i], s, slen);
952 	i += slen;
953 
954 	s = ".";
955 	slen = strlen(s);
956 	memcpy(&filename[i], s, slen);
957 	i += slen;
958 
959 	filename[i] = v;
960 	i++;
961 
962 	if (vseq != 0xffffffffffffffffLLU) {
963 		s = u2s(vseq, 10, buf);
964 		slen = strlen(s);
965 		memcpy(&filename[i], s, slen);
966 		i += slen;
967 	}
968 
969 	s = ".heap";
970 	slen = strlen(s);
971 	memcpy(&filename[i], s, slen);
972 	i += slen;
973 
974 	filename[i] = '\0';
975 }
976 
977 static void
978 prof_fdump(void)
979 {
980 	char filename[DUMP_FILENAME_BUFSIZE];
981 
982 	if (prof_booted == false)
983 		return;
984 
985 	if (opt_prof_prefix[0] != '\0') {
986 		malloc_mutex_lock(&prof_dump_seq_mtx);
987 		prof_dump_filename(filename, 'f', 0xffffffffffffffffLLU);
988 		malloc_mutex_unlock(&prof_dump_seq_mtx);
989 		prof_dump(filename, opt_prof_leak, false);
990 	}
991 }
992 
993 void
994 prof_idump(void)
995 {
996 	char filename[DUMP_FILENAME_BUFSIZE];
997 
998 	if (prof_booted == false)
999 		return;
1000 	malloc_mutex_lock(&enq_mtx);
1001 	if (enq) {
1002 		enq_idump = true;
1003 		malloc_mutex_unlock(&enq_mtx);
1004 		return;
1005 	}
1006 	malloc_mutex_unlock(&enq_mtx);
1007 
1008 	if (opt_prof_prefix[0] != '\0') {
1009 		malloc_mutex_lock(&prof_dump_seq_mtx);
1010 		prof_dump_filename(filename, 'i', prof_dump_iseq);
1011 		prof_dump_iseq++;
1012 		malloc_mutex_unlock(&prof_dump_seq_mtx);
1013 		prof_dump(filename, false, false);
1014 	}
1015 }
1016 
1017 bool
1018 prof_mdump(const char *filename)
1019 {
1020 	char filename_buf[DUMP_FILENAME_BUFSIZE];
1021 
1022 	if (opt_prof == false || prof_booted == false)
1023 		return (true);
1024 
1025 	if (filename == NULL) {
1026 		/* No filename specified, so automatically generate one. */
1027 		if (opt_prof_prefix[0] == '\0')
1028 			return (true);
1029 		malloc_mutex_lock(&prof_dump_seq_mtx);
1030 		prof_dump_filename(filename_buf, 'm', prof_dump_mseq);
1031 		prof_dump_mseq++;
1032 		malloc_mutex_unlock(&prof_dump_seq_mtx);
1033 		filename = filename_buf;
1034 	}
1035 	return (prof_dump(filename, false, true));
1036 }
1037 
1038 void
1039 prof_gdump(void)
1040 {
1041 	char filename[DUMP_FILENAME_BUFSIZE];
1042 
1043 	if (prof_booted == false)
1044 		return;
1045 	malloc_mutex_lock(&enq_mtx);
1046 	if (enq) {
1047 		enq_gdump = true;
1048 		malloc_mutex_unlock(&enq_mtx);
1049 		return;
1050 	}
1051 	malloc_mutex_unlock(&enq_mtx);
1052 
1053 	if (opt_prof_prefix[0] != '\0') {
1054 		malloc_mutex_lock(&prof_dump_seq_mtx);
1055 		prof_dump_filename(filename, 'u', prof_dump_useq);
1056 		prof_dump_useq++;
1057 		malloc_mutex_unlock(&prof_dump_seq_mtx);
1058 		prof_dump(filename, false, false);
1059 	}
1060 }
1061 
1062 static void
1063 prof_bt_hash(const void *key, unsigned minbits, size_t *hash1, size_t *hash2)
1064 {
1065 	size_t ret1, ret2;
1066 	uint64_t h;
1067 	prof_bt_t *bt = (prof_bt_t *)key;
1068 
1069 	assert(minbits <= 32 || (SIZEOF_PTR == 8 && minbits <= 64));
1070 	assert(hash1 != NULL);
1071 	assert(hash2 != NULL);
1072 
1073 	h = hash(bt->vec, bt->len * sizeof(void *), 0x94122f335b332aeaLLU);
1074 	if (minbits <= 32) {
1075 		/*
1076 		 * Avoid doing multiple hashes, since a single hash provides
1077 		 * enough bits.
1078 		 */
1079 		ret1 = h & ZU(0xffffffffU);
1080 		ret2 = h >> 32;
1081 	} else {
1082 		ret1 = h;
1083 		ret2 = hash(bt->vec, bt->len * sizeof(void *),
1084 		    0x8432a476666bbc13LLU);
1085 	}
1086 
1087 	*hash1 = ret1;
1088 	*hash2 = ret2;
1089 }
1090 
1091 static bool
1092 prof_bt_keycomp(const void *k1, const void *k2)
1093 {
1094 	const prof_bt_t *bt1 = (prof_bt_t *)k1;
1095 	const prof_bt_t *bt2 = (prof_bt_t *)k2;
1096 
1097 	if (bt1->len != bt2->len)
1098 		return (false);
1099 	return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0);
1100 }
1101 
1102 prof_tdata_t *
1103 prof_tdata_init(void)
1104 {
1105 	prof_tdata_t *prof_tdata;
1106 
1107 	/* Initialize an empty cache for this thread. */
1108 	prof_tdata = (prof_tdata_t *)imalloc(sizeof(prof_tdata_t));
1109 	if (prof_tdata == NULL)
1110 		return (NULL);
1111 
1112 	if (ckh_new(&prof_tdata->bt2cnt, PROF_CKH_MINITEMS,
1113 	    prof_bt_hash, prof_bt_keycomp)) {
1114 		idalloc(prof_tdata);
1115 		return (NULL);
1116 	}
1117 	ql_new(&prof_tdata->lru_ql);
1118 
1119 	prof_tdata->vec = imalloc(sizeof(void *) * prof_bt_max);
1120 	if (prof_tdata->vec == NULL) {
1121 		ckh_delete(&prof_tdata->bt2cnt);
1122 		idalloc(prof_tdata);
1123 		return (NULL);
1124 	}
1125 
1126 	prof_tdata->prn_state = 0;
1127 	prof_tdata->threshold = 0;
1128 	prof_tdata->accum = 0;
1129 
1130 	PROF_TCACHE_SET(prof_tdata);
1131 
1132 	return (prof_tdata);
1133 }
1134 
1135 static void
1136 prof_tdata_cleanup(void *arg)
1137 {
1138 	prof_thr_cnt_t *cnt;
1139 	prof_tdata_t *prof_tdata = (prof_tdata_t *)arg;
1140 
1141 	/*
1142 	 * Delete the hash table.  All of its contents can still be iterated
1143 	 * over via the LRU.
1144 	 */
1145 	ckh_delete(&prof_tdata->bt2cnt);
1146 
1147 	/* Iteratively merge cnt's into the global stats and delete them. */
1148 	while ((cnt = ql_last(&prof_tdata->lru_ql, lru_link)) != NULL) {
1149 		ql_remove(&prof_tdata->lru_ql, cnt, lru_link);
1150 		prof_ctx_merge(cnt->ctx, cnt);
1151 		idalloc(cnt);
1152 	}
1153 
1154 	idalloc(prof_tdata->vec);
1155 
1156 	idalloc(prof_tdata);
1157 	PROF_TCACHE_SET(NULL);
1158 }
1159 
1160 void
1161 prof_boot0(void)
1162 {
1163 
1164 	memcpy(opt_prof_prefix, PROF_PREFIX_DEFAULT,
1165 	    sizeof(PROF_PREFIX_DEFAULT));
1166 }
1167 
1168 void
1169 prof_boot1(void)
1170 {
1171 
1172 	/*
1173 	 * opt_prof and prof_promote must be in their final state before any
1174 	 * arenas are initialized, so this function must be executed early.
1175 	 */
1176 
1177 	if (opt_prof_leak && opt_prof == false) {
1178 		/*
1179 		 * Enable opt_prof, but in such a way that profiles are never
1180 		 * automatically dumped.
1181 		 */
1182 		opt_prof = true;
1183 		opt_prof_gdump = false;
1184 		prof_interval = 0;
1185 	} else if (opt_prof) {
1186 		if (opt_lg_prof_interval >= 0) {
1187 			prof_interval = (((uint64_t)1U) <<
1188 			    opt_lg_prof_interval);
1189 		} else
1190 			prof_interval = 0;
1191 	}
1192 
1193 	prof_promote = (opt_prof && opt_lg_prof_sample > PAGE_SHIFT);
1194 }
1195 
1196 bool
1197 prof_boot2(void)
1198 {
1199 
1200 	if (opt_prof) {
1201 		if (ckh_new(&bt2ctx, PROF_CKH_MINITEMS, prof_bt_hash,
1202 		    prof_bt_keycomp))
1203 			return (true);
1204 		if (malloc_mutex_init(&bt2ctx_mtx))
1205 			return (true);
1206 		if (pthread_key_create(&prof_tdata_tsd, prof_tdata_cleanup)
1207 		    != 0) {
1208 			malloc_write(
1209 			    "<jemalloc>: Error in pthread_key_create()\n");
1210 			abort();
1211 		}
1212 
1213 		prof_bt_max = (1U << opt_lg_prof_bt_max);
1214 		if (malloc_mutex_init(&prof_dump_seq_mtx))
1215 			return (true);
1216 
1217 		if (malloc_mutex_init(&enq_mtx))
1218 			return (true);
1219 		enq = false;
1220 		enq_idump = false;
1221 		enq_gdump = false;
1222 
1223 		if (atexit(prof_fdump) != 0) {
1224 			malloc_write("<jemalloc>: Error in atexit()\n");
1225 			if (opt_abort)
1226 				abort();
1227 		}
1228 	}
1229 
1230 #ifdef JEMALLOC_PROF_LIBGCC
1231 	/*
1232 	 * Cause the backtracing machinery to allocate its internal state
1233 	 * before enabling profiling.
1234 	 */
1235 	_Unwind_Backtrace(prof_unwind_init_callback, NULL);
1236 #endif
1237 
1238 	prof_booted = true;
1239 
1240 	return (false);
1241 }
1242 
1243 /******************************************************************************/
1244 #endif /* JEMALLOC_PROF */
1245