xref: /redis-3.2.3/deps/jemalloc/src/prof.c (revision c9d0c362)
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 			ctx.p->cnt_merged.curobjs++;
479 			new_ctx = true;
480 		} else
481 			new_ctx = false;
482 		prof_leave();
483 
484 		/* Link a prof_thd_cnt_t into ctx for this thread. */
485 		if (opt_lg_prof_tcmax >= 0 && ckh_count(&prof_tdata->bt2cnt)
486 		    == (ZU(1) << opt_lg_prof_tcmax)) {
487 			assert(ckh_count(&prof_tdata->bt2cnt) > 0);
488 			/*
489 			 * Flush the least recently used cnt in order to keep
490 			 * bt2cnt from becoming too large.
491 			 */
492 			ret.p = ql_last(&prof_tdata->lru_ql, lru_link);
493 			assert(ret.v != NULL);
494 			ckh_remove(&prof_tdata->bt2cnt, ret.p->ctx->bt, NULL,
495 			    NULL);
496 			ql_remove(&prof_tdata->lru_ql, ret.p, lru_link);
497 			prof_ctx_merge(ret.p->ctx, ret.p);
498 			/* ret can now be re-used. */
499 		} else {
500 			assert(opt_lg_prof_tcmax < 0 ||
501 			    ckh_count(&prof_tdata->bt2cnt) < (ZU(1) <<
502 			    opt_lg_prof_tcmax));
503 			/* Allocate and partially initialize a new cnt. */
504 			ret.v = imalloc(sizeof(prof_thr_cnt_t));
505 			if (ret.p == NULL) {
506 				if (new_ctx) {
507 					malloc_mutex_lock(&ctx.p->lock);
508 					ctx.p->cnt_merged.curobjs--;
509 					malloc_mutex_unlock(&ctx.p->lock);
510 				}
511 				return (NULL);
512 			}
513 			ql_elm_new(ret.p, cnts_link);
514 			ql_elm_new(ret.p, lru_link);
515 		}
516 		/* Finish initializing ret. */
517 		ret.p->ctx = ctx.p;
518 		ret.p->epoch = 0;
519 		memset(&ret.p->cnts, 0, sizeof(prof_cnt_t));
520 		if (ckh_insert(&prof_tdata->bt2cnt, btkey.v, ret.v)) {
521 			if (new_ctx) {
522 				malloc_mutex_lock(&ctx.p->lock);
523 				ctx.p->cnt_merged.curobjs--;
524 				malloc_mutex_unlock(&ctx.p->lock);
525 			}
526 			idalloc(ret.v);
527 			return (NULL);
528 		}
529 		ql_head_insert(&prof_tdata->lru_ql, ret.p, lru_link);
530 		malloc_mutex_lock(&ctx.p->lock);
531 		ql_tail_insert(&ctx.p->cnts_ql, ret.p, cnts_link);
532 		if (new_ctx)
533 			ctx.p->cnt_merged.curobjs--;
534 		malloc_mutex_unlock(&ctx.p->lock);
535 	} else {
536 		/* Move ret to the front of the LRU. */
537 		ql_remove(&prof_tdata->lru_ql, ret.p, lru_link);
538 		ql_head_insert(&prof_tdata->lru_ql, ret.p, lru_link);
539 	}
540 
541 	return (ret.p);
542 }
543 
544 static bool
545 prof_flush(bool propagate_err)
546 {
547 	bool ret = false;
548 	ssize_t err;
549 
550 	err = write(prof_dump_fd, prof_dump_buf, prof_dump_buf_end);
551 	if (err == -1) {
552 		if (propagate_err == false) {
553 			malloc_write("<jemalloc>: write() failed during heap "
554 			    "profile flush\n");
555 			if (opt_abort)
556 				abort();
557 		}
558 		ret = true;
559 	}
560 	prof_dump_buf_end = 0;
561 
562 	return (ret);
563 }
564 
565 static bool
566 prof_write(const char *s, bool propagate_err)
567 {
568 	unsigned i, slen, n;
569 
570 	i = 0;
571 	slen = strlen(s);
572 	while (i < slen) {
573 		/* Flush the buffer if it is full. */
574 		if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE)
575 			if (prof_flush(propagate_err) && propagate_err)
576 				return (true);
577 
578 		if (prof_dump_buf_end + slen <= PROF_DUMP_BUF_SIZE) {
579 			/* Finish writing. */
580 			n = slen - i;
581 		} else {
582 			/* Write as much of s as will fit. */
583 			n = PROF_DUMP_BUF_SIZE - prof_dump_buf_end;
584 		}
585 		memcpy(&prof_dump_buf[prof_dump_buf_end], &s[i], n);
586 		prof_dump_buf_end += n;
587 		i += n;
588 	}
589 
590 	return (false);
591 }
592 
593 static void
594 prof_ctx_sum(prof_ctx_t *ctx, prof_cnt_t *cnt_all, size_t *leak_nctx)
595 {
596 	prof_thr_cnt_t *thr_cnt;
597 	prof_cnt_t tcnt;
598 
599 	malloc_mutex_lock(&ctx->lock);
600 
601 	memcpy(&ctx->cnt_summed, &ctx->cnt_merged, sizeof(prof_cnt_t));
602 	ql_foreach(thr_cnt, &ctx->cnts_ql, cnts_link) {
603 		volatile unsigned *epoch = &thr_cnt->epoch;
604 
605 		while (true) {
606 			unsigned epoch0 = *epoch;
607 
608 			/* Make sure epoch is even. */
609 			if (epoch0 & 1U)
610 				continue;
611 
612 			memcpy(&tcnt, &thr_cnt->cnts, sizeof(prof_cnt_t));
613 
614 			/* Terminate if epoch didn't change while reading. */
615 			if (*epoch == epoch0)
616 				break;
617 		}
618 
619 		ctx->cnt_summed.curobjs += tcnt.curobjs;
620 		ctx->cnt_summed.curbytes += tcnt.curbytes;
621 		if (opt_prof_accum) {
622 			ctx->cnt_summed.accumobjs += tcnt.accumobjs;
623 			ctx->cnt_summed.accumbytes += tcnt.accumbytes;
624 		}
625 	}
626 
627 	if (ctx->cnt_summed.curobjs != 0)
628 		(*leak_nctx)++;
629 
630 	/* Add to cnt_all. */
631 	cnt_all->curobjs += ctx->cnt_summed.curobjs;
632 	cnt_all->curbytes += ctx->cnt_summed.curbytes;
633 	if (opt_prof_accum) {
634 		cnt_all->accumobjs += ctx->cnt_summed.accumobjs;
635 		cnt_all->accumbytes += ctx->cnt_summed.accumbytes;
636 	}
637 
638 	malloc_mutex_unlock(&ctx->lock);
639 }
640 
641 static void
642 prof_ctx_destroy(prof_ctx_t *ctx)
643 {
644 
645 	/*
646 	 * Check that ctx is still unused by any thread cache before destroying
647 	 * it.  prof_lookup() interlocks bt2ctx_mtx and ctx->lock in order to
648 	 * avoid a race condition with this function, and prof_ctx_merge()
649 	 * artificially raises ctx->cnt_merged.curobjs in order to avoid a race
650 	 * between the main body of prof_ctx_merge() and entry into this
651 	 * function.
652 	 */
653 	prof_enter();
654 	malloc_mutex_lock(&ctx->lock);
655 	if (ql_first(&ctx->cnts_ql) == NULL && ctx->cnt_merged.curobjs == 1) {
656 		assert(ctx->cnt_merged.curbytes == 0);
657 		assert(ctx->cnt_merged.accumobjs == 0);
658 		assert(ctx->cnt_merged.accumbytes == 0);
659 		/* Remove ctx from bt2ctx. */
660 		ckh_remove(&bt2ctx, ctx->bt, NULL, NULL);
661 		prof_leave();
662 		/* Destroy ctx. */
663 		malloc_mutex_unlock(&ctx->lock);
664 		bt_destroy(ctx->bt);
665 		malloc_mutex_destroy(&ctx->lock);
666 		idalloc(ctx);
667 	} else {
668 		/* Compensate for increment in prof_ctx_merge(). */
669 		ctx->cnt_merged.curobjs--;
670 		malloc_mutex_unlock(&ctx->lock);
671 		prof_leave();
672 	}
673 }
674 
675 static void
676 prof_ctx_merge(prof_ctx_t *ctx, prof_thr_cnt_t *cnt)
677 {
678 	bool destroy;
679 
680 	/* Merge cnt stats and detach from ctx. */
681 	malloc_mutex_lock(&ctx->lock);
682 	ctx->cnt_merged.curobjs += cnt->cnts.curobjs;
683 	ctx->cnt_merged.curbytes += cnt->cnts.curbytes;
684 	ctx->cnt_merged.accumobjs += cnt->cnts.accumobjs;
685 	ctx->cnt_merged.accumbytes += cnt->cnts.accumbytes;
686 	ql_remove(&ctx->cnts_ql, cnt, cnts_link);
687 	if (opt_prof_accum == false && ql_first(&ctx->cnts_ql) == NULL &&
688 	    ctx->cnt_merged.curobjs == 0) {
689 		/*
690 		 * Artificially raise ctx->cnt_merged.curobjs in order to keep
691 		 * another thread from winning the race to destroy ctx while
692 		 * this one has ctx->lock dropped.  Without this, it would be
693 		 * possible for another thread to:
694 		 *
695 		 * 1) Sample an allocation associated with ctx.
696 		 * 2) Deallocate the sampled object.
697 		 * 3) Successfully prof_ctx_destroy(ctx).
698 		 *
699 		 * The result would be that ctx no longer exists by the time
700 		 * this thread accesses it in prof_ctx_destroy().
701 		 */
702 		ctx->cnt_merged.curobjs++;
703 		destroy = true;
704 	} else
705 		destroy = false;
706 	malloc_mutex_unlock(&ctx->lock);
707 	if (destroy)
708 		prof_ctx_destroy(ctx);
709 }
710 
711 static bool
712 prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt, bool propagate_err)
713 {
714 	char buf[UMAX2S_BUFSIZE];
715 	unsigned i;
716 
717 	if (opt_prof_accum == false && ctx->cnt_summed.curobjs == 0) {
718 		assert(ctx->cnt_summed.curbytes == 0);
719 		assert(ctx->cnt_summed.accumobjs == 0);
720 		assert(ctx->cnt_summed.accumbytes == 0);
721 		return (false);
722 	}
723 
724 	if (prof_write(u2s(ctx->cnt_summed.curobjs, 10, buf), propagate_err)
725 	    || prof_write(": ", propagate_err)
726 	    || prof_write(u2s(ctx->cnt_summed.curbytes, 10, buf),
727 	    propagate_err)
728 	    || prof_write(" [", propagate_err)
729 	    || prof_write(u2s(ctx->cnt_summed.accumobjs, 10, buf),
730 	    propagate_err)
731 	    || prof_write(": ", propagate_err)
732 	    || prof_write(u2s(ctx->cnt_summed.accumbytes, 10, buf),
733 	    propagate_err)
734 	    || prof_write("] @", propagate_err))
735 		return (true);
736 
737 	for (i = 0; i < bt->len; i++) {
738 		if (prof_write(" 0x", propagate_err)
739 		    || prof_write(u2s((uintptr_t)bt->vec[i], 16, buf),
740 		    propagate_err))
741 			return (true);
742 	}
743 
744 	if (prof_write("\n", propagate_err))
745 		return (true);
746 
747 	return (false);
748 }
749 
750 static bool
751 prof_dump_maps(bool propagate_err)
752 {
753 	int mfd;
754 	char buf[UMAX2S_BUFSIZE];
755 	char *s;
756 	unsigned i, slen;
757 	/*         /proc/<pid>/maps\0 */
758 	char mpath[6     + UMAX2S_BUFSIZE
759 			      + 5  + 1];
760 
761 	i = 0;
762 
763 	s = "/proc/";
764 	slen = strlen(s);
765 	memcpy(&mpath[i], s, slen);
766 	i += slen;
767 
768 	s = u2s(getpid(), 10, buf);
769 	slen = strlen(s);
770 	memcpy(&mpath[i], s, slen);
771 	i += slen;
772 
773 	s = "/maps";
774 	slen = strlen(s);
775 	memcpy(&mpath[i], s, slen);
776 	i += slen;
777 
778 	mpath[i] = '\0';
779 
780 	mfd = open(mpath, O_RDONLY);
781 	if (mfd != -1) {
782 		ssize_t nread;
783 
784 		if (prof_write("\nMAPPED_LIBRARIES:\n", propagate_err) &&
785 		    propagate_err)
786 			return (true);
787 		nread = 0;
788 		do {
789 			prof_dump_buf_end += nread;
790 			if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE) {
791 				/* Make space in prof_dump_buf before read(). */
792 				if (prof_flush(propagate_err) && propagate_err)
793 					return (true);
794 			}
795 			nread = read(mfd, &prof_dump_buf[prof_dump_buf_end],
796 			    PROF_DUMP_BUF_SIZE - prof_dump_buf_end);
797 		} while (nread > 0);
798 		close(mfd);
799 	} else
800 		return (true);
801 
802 	return (false);
803 }
804 
805 static bool
806 prof_dump(const char *filename, bool leakcheck, bool propagate_err)
807 {
808 	prof_cnt_t cnt_all;
809 	size_t tabind;
810 	union {
811 		prof_bt_t	*p;
812 		void		*v;
813 	} bt;
814 	union {
815 		prof_ctx_t	*p;
816 		void		*v;
817 	} ctx;
818 	char buf[UMAX2S_BUFSIZE];
819 	size_t leak_nctx;
820 
821 	prof_enter();
822 	prof_dump_fd = creat(filename, 0644);
823 	if (prof_dump_fd == -1) {
824 		if (propagate_err == false) {
825 			malloc_write("<jemalloc>: creat(\"");
826 			malloc_write(filename);
827 			malloc_write("\", 0644) failed\n");
828 			if (opt_abort)
829 				abort();
830 		}
831 		goto ERROR;
832 	}
833 
834 	/* Merge per thread profile stats, and sum them in cnt_all. */
835 	memset(&cnt_all, 0, sizeof(prof_cnt_t));
836 	leak_nctx = 0;
837 	for (tabind = 0; ckh_iter(&bt2ctx, &tabind, NULL, &ctx.v) == false;)
838 		prof_ctx_sum(ctx.p, &cnt_all, &leak_nctx);
839 
840 	/* Dump profile header. */
841 	if (prof_write("heap profile: ", propagate_err)
842 	    || prof_write(u2s(cnt_all.curobjs, 10, buf), propagate_err)
843 	    || prof_write(": ", propagate_err)
844 	    || prof_write(u2s(cnt_all.curbytes, 10, buf), propagate_err)
845 	    || prof_write(" [", propagate_err)
846 	    || prof_write(u2s(cnt_all.accumobjs, 10, buf), propagate_err)
847 	    || prof_write(": ", propagate_err)
848 	    || prof_write(u2s(cnt_all.accumbytes, 10, buf), propagate_err))
849 		goto ERROR;
850 
851 	if (opt_lg_prof_sample == 0) {
852 		if (prof_write("] @ heapprofile\n", propagate_err))
853 			goto ERROR;
854 	} else {
855 		if (prof_write("] @ heap_v2/", propagate_err)
856 		    || prof_write(u2s((uint64_t)1U << opt_lg_prof_sample, 10,
857 		    buf), propagate_err)
858 		    || prof_write("\n", propagate_err))
859 			goto ERROR;
860 	}
861 
862 	/* Dump  per ctx profile stats. */
863 	for (tabind = 0; ckh_iter(&bt2ctx, &tabind, &bt.v, &ctx.v)
864 	    == false;) {
865 		if (prof_dump_ctx(ctx.p, bt.p, propagate_err))
866 			goto ERROR;
867 	}
868 
869 	/* Dump /proc/<pid>/maps if possible. */
870 	if (prof_dump_maps(propagate_err))
871 		goto ERROR;
872 
873 	if (prof_flush(propagate_err))
874 		goto ERROR;
875 	close(prof_dump_fd);
876 	prof_leave();
877 
878 	if (leakcheck && cnt_all.curbytes != 0) {
879 		malloc_write("<jemalloc>: Leak summary: ");
880 		malloc_write(u2s(cnt_all.curbytes, 10, buf));
881 		malloc_write((cnt_all.curbytes != 1) ? " bytes, " : " byte, ");
882 		malloc_write(u2s(cnt_all.curobjs, 10, buf));
883 		malloc_write((cnt_all.curobjs != 1) ? " objects, " :
884 		    " object, ");
885 		malloc_write(u2s(leak_nctx, 10, buf));
886 		malloc_write((leak_nctx != 1) ? " contexts\n" : " context\n");
887 		malloc_write("<jemalloc>: Run pprof on \"");
888 		malloc_write(filename);
889 		malloc_write("\" for leak detail\n");
890 	}
891 
892 	return (false);
893 ERROR:
894 	prof_leave();
895 	return (true);
896 }
897 
898 #define	DUMP_FILENAME_BUFSIZE	(PATH_MAX+ UMAX2S_BUFSIZE		\
899 					       + 1			\
900 						+ UMAX2S_BUFSIZE	\
901 						     + 2		\
902 						       + UMAX2S_BUFSIZE	\
903 						             + 5  + 1)
904 static void
905 prof_dump_filename(char *filename, char v, int64_t vseq)
906 {
907 	char buf[UMAX2S_BUFSIZE];
908 	char *s;
909 	unsigned i, slen;
910 
911 	/*
912 	 * Construct a filename of the form:
913 	 *
914 	 *   <prefix>.<pid>.<seq>.v<vseq>.heap\0
915 	 */
916 
917 	i = 0;
918 
919 	s = opt_prof_prefix;
920 	slen = strlen(s);
921 	memcpy(&filename[i], s, slen);
922 	i += slen;
923 
924 	s = ".";
925 	slen = strlen(s);
926 	memcpy(&filename[i], s, slen);
927 	i += slen;
928 
929 	s = u2s(getpid(), 10, buf);
930 	slen = strlen(s);
931 	memcpy(&filename[i], s, slen);
932 	i += slen;
933 
934 	s = ".";
935 	slen = strlen(s);
936 	memcpy(&filename[i], s, slen);
937 	i += slen;
938 
939 	s = u2s(prof_dump_seq, 10, buf);
940 	prof_dump_seq++;
941 	slen = strlen(s);
942 	memcpy(&filename[i], s, slen);
943 	i += slen;
944 
945 	s = ".";
946 	slen = strlen(s);
947 	memcpy(&filename[i], s, slen);
948 	i += slen;
949 
950 	filename[i] = v;
951 	i++;
952 
953 	if (vseq != 0xffffffffffffffffLLU) {
954 		s = u2s(vseq, 10, buf);
955 		slen = strlen(s);
956 		memcpy(&filename[i], s, slen);
957 		i += slen;
958 	}
959 
960 	s = ".heap";
961 	slen = strlen(s);
962 	memcpy(&filename[i], s, slen);
963 	i += slen;
964 
965 	filename[i] = '\0';
966 }
967 
968 static void
969 prof_fdump(void)
970 {
971 	char filename[DUMP_FILENAME_BUFSIZE];
972 
973 	if (prof_booted == false)
974 		return;
975 
976 	if (opt_prof_prefix[0] != '\0') {
977 		malloc_mutex_lock(&prof_dump_seq_mtx);
978 		prof_dump_filename(filename, 'f', 0xffffffffffffffffLLU);
979 		malloc_mutex_unlock(&prof_dump_seq_mtx);
980 		prof_dump(filename, opt_prof_leak, false);
981 	}
982 }
983 
984 void
985 prof_idump(void)
986 {
987 	char filename[DUMP_FILENAME_BUFSIZE];
988 
989 	if (prof_booted == false)
990 		return;
991 	malloc_mutex_lock(&enq_mtx);
992 	if (enq) {
993 		enq_idump = true;
994 		malloc_mutex_unlock(&enq_mtx);
995 		return;
996 	}
997 	malloc_mutex_unlock(&enq_mtx);
998 
999 	if (opt_prof_prefix[0] != '\0') {
1000 		malloc_mutex_lock(&prof_dump_seq_mtx);
1001 		prof_dump_filename(filename, 'i', prof_dump_iseq);
1002 		prof_dump_iseq++;
1003 		malloc_mutex_unlock(&prof_dump_seq_mtx);
1004 		prof_dump(filename, false, false);
1005 	}
1006 }
1007 
1008 bool
1009 prof_mdump(const char *filename)
1010 {
1011 	char filename_buf[DUMP_FILENAME_BUFSIZE];
1012 
1013 	if (opt_prof == false || prof_booted == false)
1014 		return (true);
1015 
1016 	if (filename == NULL) {
1017 		/* No filename specified, so automatically generate one. */
1018 		if (opt_prof_prefix[0] == '\0')
1019 			return (true);
1020 		malloc_mutex_lock(&prof_dump_seq_mtx);
1021 		prof_dump_filename(filename_buf, 'm', prof_dump_mseq);
1022 		prof_dump_mseq++;
1023 		malloc_mutex_unlock(&prof_dump_seq_mtx);
1024 		filename = filename_buf;
1025 	}
1026 	return (prof_dump(filename, false, true));
1027 }
1028 
1029 void
1030 prof_gdump(void)
1031 {
1032 	char filename[DUMP_FILENAME_BUFSIZE];
1033 
1034 	if (prof_booted == false)
1035 		return;
1036 	malloc_mutex_lock(&enq_mtx);
1037 	if (enq) {
1038 		enq_gdump = true;
1039 		malloc_mutex_unlock(&enq_mtx);
1040 		return;
1041 	}
1042 	malloc_mutex_unlock(&enq_mtx);
1043 
1044 	if (opt_prof_prefix[0] != '\0') {
1045 		malloc_mutex_lock(&prof_dump_seq_mtx);
1046 		prof_dump_filename(filename, 'u', prof_dump_useq);
1047 		prof_dump_useq++;
1048 		malloc_mutex_unlock(&prof_dump_seq_mtx);
1049 		prof_dump(filename, false, false);
1050 	}
1051 }
1052 
1053 static void
1054 prof_bt_hash(const void *key, unsigned minbits, size_t *hash1, size_t *hash2)
1055 {
1056 	size_t ret1, ret2;
1057 	uint64_t h;
1058 	prof_bt_t *bt = (prof_bt_t *)key;
1059 
1060 	assert(minbits <= 32 || (SIZEOF_PTR == 8 && minbits <= 64));
1061 	assert(hash1 != NULL);
1062 	assert(hash2 != NULL);
1063 
1064 	h = hash(bt->vec, bt->len * sizeof(void *), 0x94122f335b332aeaLLU);
1065 	if (minbits <= 32) {
1066 		/*
1067 		 * Avoid doing multiple hashes, since a single hash provides
1068 		 * enough bits.
1069 		 */
1070 		ret1 = h & ZU(0xffffffffU);
1071 		ret2 = h >> 32;
1072 	} else {
1073 		ret1 = h;
1074 		ret2 = hash(bt->vec, bt->len * sizeof(void *),
1075 		    0x8432a476666bbc13U);
1076 	}
1077 
1078 	*hash1 = ret1;
1079 	*hash2 = ret2;
1080 }
1081 
1082 static bool
1083 prof_bt_keycomp(const void *k1, const void *k2)
1084 {
1085 	const prof_bt_t *bt1 = (prof_bt_t *)k1;
1086 	const prof_bt_t *bt2 = (prof_bt_t *)k2;
1087 
1088 	if (bt1->len != bt2->len)
1089 		return (false);
1090 	return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0);
1091 }
1092 
1093 prof_tdata_t *
1094 prof_tdata_init(void)
1095 {
1096 	prof_tdata_t *prof_tdata;
1097 
1098 	/* Initialize an empty cache for this thread. */
1099 	prof_tdata = (prof_tdata_t *)imalloc(sizeof(prof_tdata_t));
1100 	if (prof_tdata == NULL)
1101 		return (NULL);
1102 
1103 	if (ckh_new(&prof_tdata->bt2cnt, PROF_CKH_MINITEMS,
1104 	    prof_bt_hash, prof_bt_keycomp)) {
1105 		idalloc(prof_tdata);
1106 		return (NULL);
1107 	}
1108 	ql_new(&prof_tdata->lru_ql);
1109 
1110 	prof_tdata->vec = imalloc(sizeof(void *) * prof_bt_max);
1111 	if (prof_tdata->vec == NULL) {
1112 
1113 		ckh_delete(&prof_tdata->bt2cnt);
1114 		idalloc(prof_tdata);
1115 		return (NULL);
1116 	}
1117 
1118 	prof_tdata->prn_state = 0;
1119 	prof_tdata->threshold = 0;
1120 	prof_tdata->accum = 0;
1121 
1122 	PROF_TCACHE_SET(prof_tdata);
1123 
1124 	return (prof_tdata);
1125 }
1126 
1127 static void
1128 prof_tdata_cleanup(void *arg)
1129 {
1130 	prof_tdata_t *prof_tdata;
1131 
1132 	prof_tdata = PROF_TCACHE_GET();
1133 	if (prof_tdata != NULL) {
1134 		prof_thr_cnt_t *cnt;
1135 
1136 		/*
1137 		 * Delete the hash table.  All of its contents can still be
1138 		 * iterated over via the LRU.
1139 		 */
1140 		ckh_delete(&prof_tdata->bt2cnt);
1141 
1142 		/*
1143 		 * Iteratively merge cnt's into the global stats and delete
1144 		 * them.
1145 		 */
1146 		while ((cnt = ql_last(&prof_tdata->lru_ql, lru_link)) != NULL) {
1147 			prof_ctx_merge(cnt->ctx, cnt);
1148 			ql_remove(&prof_tdata->lru_ql, cnt, lru_link);
1149 			idalloc(cnt);
1150 		}
1151 
1152 		idalloc(prof_tdata->vec);
1153 
1154 		idalloc(prof_tdata);
1155 		PROF_TCACHE_SET(NULL);
1156 	}
1157 }
1158 
1159 void
1160 prof_boot0(void)
1161 {
1162 
1163 	memcpy(opt_prof_prefix, PROF_PREFIX_DEFAULT,
1164 	    sizeof(PROF_PREFIX_DEFAULT));
1165 }
1166 
1167 void
1168 prof_boot1(void)
1169 {
1170 
1171 	/*
1172 	 * opt_prof and prof_promote must be in their final state before any
1173 	 * arenas are initialized, so this function must be executed early.
1174 	 */
1175 
1176 	if (opt_prof_leak && opt_prof == false) {
1177 		/*
1178 		 * Enable opt_prof, but in such a way that profiles are never
1179 		 * automatically dumped.
1180 		 */
1181 		opt_prof = true;
1182 		opt_prof_gdump = false;
1183 		prof_interval = 0;
1184 	} else if (opt_prof) {
1185 		if (opt_lg_prof_interval >= 0) {
1186 			prof_interval = (((uint64_t)1U) <<
1187 			    opt_lg_prof_interval);
1188 		} else
1189 			prof_interval = 0;
1190 	}
1191 
1192 	prof_promote = (opt_prof && opt_lg_prof_sample > PAGE_SHIFT);
1193 }
1194 
1195 bool
1196 prof_boot2(void)
1197 {
1198 
1199 	if (opt_prof) {
1200 		if (ckh_new(&bt2ctx, PROF_CKH_MINITEMS, prof_bt_hash,
1201 		    prof_bt_keycomp))
1202 			return (true);
1203 		if (malloc_mutex_init(&bt2ctx_mtx))
1204 			return (true);
1205 		if (pthread_key_create(&prof_tdata_tsd, prof_tdata_cleanup)
1206 		    != 0) {
1207 			malloc_write(
1208 			    "<jemalloc>: Error in pthread_key_create()\n");
1209 			abort();
1210 		}
1211 
1212 		prof_bt_max = (1U << opt_lg_prof_bt_max);
1213 		if (malloc_mutex_init(&prof_dump_seq_mtx))
1214 			return (true);
1215 
1216 		if (malloc_mutex_init(&enq_mtx))
1217 			return (true);
1218 		enq = false;
1219 		enq_idump = false;
1220 		enq_gdump = false;
1221 
1222 		if (atexit(prof_fdump) != 0) {
1223 			malloc_write("<jemalloc>: Error in atexit()\n");
1224 			if (opt_abort)
1225 				abort();
1226 		}
1227 	}
1228 
1229 #ifdef JEMALLOC_PROF_LIBGCC
1230 	/*
1231 	 * Cause the backtracing machinery to allocate its internal state
1232 	 * before enabling profiling.
1233 	 */
1234 	_Unwind_Backtrace(prof_unwind_init_callback, NULL);
1235 #endif
1236 
1237 	prof_booted = true;
1238 
1239 	return (false);
1240 }
1241 
1242 /******************************************************************************/
1243 #endif /* JEMALLOC_PROF */
1244