1 #define JEMALLOC_PROF_C_
2 #include "jemalloc/internal/jemalloc_internal.h"
4 /******************************************************************************/
6 #ifdef JEMALLOC_PROF_LIBUNWIND
11 #ifdef JEMALLOC_PROF_LIBGCC
15 /******************************************************************************/
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];
29 uint64_t prof_interval
;
35 __thread prof_tdata_t
*prof_tdata_tls
36 JEMALLOC_ATTR(tls_model("initial-exec"));
38 pthread_key_t prof_tdata_tsd
;
41 * Global hash of (prof_bt_t *)-->(prof_ctx_t *). This is the master data
42 * structure that knows about all backtraces currently captured.
45 static malloc_mutex_t bt2ctx_mtx
;
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
;
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.
58 static char prof_dump_buf
[PROF_DUMP_BUF_SIZE
];
59 static unsigned prof_dump_buf_end
;
60 static int prof_dump_fd
;
62 /* Do not dump any profiles until bootstrapping is complete. */
63 static bool prof_booted
= false;
65 static malloc_mutex_t enq_mtx
;
67 static bool enq_idump
;
68 static bool enq_gdump
;
70 /******************************************************************************/
71 /* Function prototypes for non-inline static functions. */
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
);
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
,
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
,
89 static bool prof_dump_maps(bool propagate_err
);
90 static bool prof_dump(const char *filename
, bool leakcheck
,
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
,
96 static bool prof_bt_keycomp(const void *k1
, const void *k2
);
97 static void prof_tdata_cleanup(void *arg
);
99 /******************************************************************************/
102 bt_init(prof_bt_t
*bt
, void **vec
)
110 bt_destroy(prof_bt_t
*bt
)
117 bt_dup(prof_bt_t
*bt
)
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.
128 ret
= (prof_bt_t
*)imalloc(QUANTUM_CEILING(sizeof(prof_bt_t
)) +
129 (bt
->len
* sizeof(void *)));
132 ret
->vec
= (void **)((uintptr_t)ret
+
133 QUANTUM_CEILING(sizeof(prof_bt_t
)));
134 memcpy(ret
->vec
, bt
->vec
, bt
->len
* sizeof(void *));
144 malloc_mutex_lock(&enq_mtx
);
146 malloc_mutex_unlock(&enq_mtx
);
148 malloc_mutex_lock(&bt2ctx_mtx
);
156 malloc_mutex_unlock(&bt2ctx_mtx
);
158 malloc_mutex_lock(&enq_mtx
);
164 malloc_mutex_unlock(&enq_mtx
);
172 #ifdef JEMALLOC_PROF_LIBUNWIND
174 prof_backtrace(prof_bt_t
*bt
, unsigned nignore
, unsigned max
)
181 assert(bt
->len
== 0);
182 assert(bt
->vec
!= NULL
);
183 assert(max
<= (1U << opt_lg_prof_bt_max
));
186 unw_init_local(&cursor
, &uc
);
188 /* Throw away (nignore+1) stack frames, if that many exist. */
189 for (i
= 0; i
< nignore
+ 1; i
++) {
190 err
= unw_step(&cursor
);
196 * Iterate over stack frames until there are no more, or until no space
199 for (i
= 0; i
< max
; i
++) {
200 unw_get_reg(&cursor
, UNW_REG_IP
, (unw_word_t
*)&bt
->vec
[i
]);
202 err
= unw_step(&cursor
);
208 #ifdef JEMALLOC_PROF_LIBGCC
209 static _Unwind_Reason_Code
210 prof_unwind_init_callback(struct _Unwind_Context
*context
, void *arg
)
213 return (_URC_NO_REASON
);
216 static _Unwind_Reason_Code
217 prof_unwind_callback(struct _Unwind_Context
*context
, void *arg
)
219 prof_unwind_data_t
*data
= (prof_unwind_data_t
*)arg
;
221 if (data
->nignore
> 0)
224 data
->bt
->vec
[data
->bt
->len
] = (void *)_Unwind_GetIP(context
);
226 if (data
->bt
->len
== data
->max
)
227 return (_URC_END_OF_STACK
);
230 return (_URC_NO_REASON
);
234 prof_backtrace(prof_bt_t
*bt
, unsigned nignore
, unsigned max
)
236 prof_unwind_data_t data
= {bt
, nignore
, max
};
238 _Unwind_Backtrace(prof_unwind_callback
, &data
);
241 #ifdef JEMALLOC_PROF_GCC
243 prof_backtrace(prof_bt_t
*bt
, unsigned nignore
, unsigned max
)
245 #define BT_FRAME(i) \
246 if ((i) < nignore + max) { \
248 if (__builtin_frame_address(i) == 0) \
250 p = __builtin_return_address(i); \
253 if (i >= nignore) { \
254 bt->vec[(i) - nignore] = p; \
255 bt->len = (i) - nignore + 1; \
260 assert(nignore
<= 3);
261 assert(max
<= (1U << opt_lg_prof_bt_max
));
404 /* Extras to compensate for nignore. */
413 prof_lookup(prof_bt_t
*bt
)
419 prof_tdata_t
*prof_tdata
;
421 prof_tdata
= PROF_TCACHE_GET();
422 if (prof_tdata
== NULL
) {
423 prof_tdata
= prof_tdata_init();
424 if (prof_tdata
== NULL
)
428 if (ckh_search(&prof_tdata
->bt2cnt
, bt
, NULL
, &ret
.v
)) {
440 * This thread's cache lacks bt. Look for it in the global
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
));
451 btkey
.p
= bt_dup(bt
);
452 if (btkey
.v
== NULL
) {
458 if (malloc_mutex_init(&ctx
.p
->lock
)) {
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
)) {
469 malloc_mutex_destroy(&ctx
.p
->lock
);
475 * Artificially raise curobjs, in order to avoid a race
476 * condition with prof_ctx_merge()/prof_ctx_destroy().
478 ctx
.p
->cnt_merged
.curobjs
++;
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);
489 * Flush the least recently used cnt in order to keep
490 * bt2cnt from becoming too large.
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
,
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. */
500 assert(opt_lg_prof_tcmax
< 0 ||
501 ckh_count(&prof_tdata
->bt2cnt
) < (ZU(1) <<
503 /* Allocate and partially initialize a new cnt. */
504 ret
.v
= imalloc(sizeof(prof_thr_cnt_t
));
507 malloc_mutex_lock(&ctx
.p
->lock
);
508 ctx
.p
->cnt_merged
.curobjs
--;
509 malloc_mutex_unlock(&ctx
.p
->lock
);
513 ql_elm_new(ret
.p
, cnts_link
);
514 ql_elm_new(ret
.p
, lru_link
);
516 /* Finish initializing ret. */
519 memset(&ret
.p
->cnts
, 0, sizeof(prof_cnt_t
));
520 if (ckh_insert(&prof_tdata
->bt2cnt
, btkey
.v
, ret
.v
)) {
522 malloc_mutex_lock(&ctx
.p
->lock
);
523 ctx
.p
->cnt_merged
.curobjs
--;
524 malloc_mutex_unlock(&ctx
.p
->lock
);
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
);
533 ctx
.p
->cnt_merged
.curobjs
--;
534 malloc_mutex_unlock(&ctx
.p
->lock
);
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
);
545 prof_flush(bool propagate_err
)
550 err
= write(prof_dump_fd
, prof_dump_buf
, prof_dump_buf_end
);
552 if (propagate_err
== false) {
553 malloc_write("<jemalloc>: write() failed during heap "
560 prof_dump_buf_end
= 0;
566 prof_write(const char *s
, bool propagate_err
)
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
)
578 if (prof_dump_buf_end
+ slen
<= PROF_DUMP_BUF_SIZE
) {
579 /* Finish writing. */
582 /* Write as much of s as will fit. */
583 n
= PROF_DUMP_BUF_SIZE
- prof_dump_buf_end
;
585 memcpy(&prof_dump_buf
[prof_dump_buf_end
], &s
[i
], n
);
586 prof_dump_buf_end
+= n
;
594 prof_ctx_sum(prof_ctx_t
*ctx
, prof_cnt_t
*cnt_all
, size_t *leak_nctx
)
596 prof_thr_cnt_t
*thr_cnt
;
599 malloc_mutex_lock(&ctx
->lock
);
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
;
606 unsigned epoch0
= *epoch
;
608 /* Make sure epoch is even. */
612 memcpy(&tcnt
, &thr_cnt
->cnts
, sizeof(prof_cnt_t
));
614 /* Terminate if epoch didn't change while reading. */
615 if (*epoch
== epoch0
)
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
;
627 if (ctx
->cnt_summed
.curobjs
!= 0)
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
;
638 malloc_mutex_unlock(&ctx
->lock
);
642 prof_ctx_destroy(prof_ctx_t
*ctx
)
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
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
);
663 malloc_mutex_unlock(&ctx
->lock
);
665 malloc_mutex_destroy(&ctx
->lock
);
668 /* Compensate for increment in prof_ctx_merge(). */
669 ctx
->cnt_merged
.curobjs
--;
670 malloc_mutex_unlock(&ctx
->lock
);
676 prof_ctx_merge(prof_ctx_t
*ctx
, prof_thr_cnt_t
*cnt
)
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) {
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:
695 * 1) Sample an allocation associated with ctx.
696 * 2) Deallocate the sampled object.
697 * 3) Successfully prof_ctx_destroy(ctx).
699 * The result would be that ctx no longer exists by the time
700 * this thread accesses it in prof_ctx_destroy().
702 ctx
->cnt_merged
.curobjs
++;
706 malloc_mutex_unlock(&ctx
->lock
);
708 prof_ctx_destroy(ctx
);
712 prof_dump_ctx(prof_ctx_t
*ctx
, prof_bt_t
*bt
, bool propagate_err
)
714 char buf
[UMAX2S_BUFSIZE
];
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);
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
),
728 || prof_write(" [", propagate_err
)
729 || prof_write(u2s(ctx
->cnt_summed
.accumobjs
, 10, buf
),
731 || prof_write(": ", propagate_err
)
732 || prof_write(u2s(ctx
->cnt_summed
.accumbytes
, 10, buf
),
734 || prof_write("] @", propagate_err
))
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
),
744 if (prof_write("\n", propagate_err
))
751 prof_dump_maps(bool propagate_err
)
754 char buf
[UMAX2S_BUFSIZE
];
757 /* /proc/<pid>/maps\0 */
758 char mpath
[6 + UMAX2S_BUFSIZE
765 memcpy(&mpath
[i
], s
, slen
);
768 s
= u2s(getpid(), 10, buf
);
770 memcpy(&mpath
[i
], s
, slen
);
775 memcpy(&mpath
[i
], s
, slen
);
780 mfd
= open(mpath
, O_RDONLY
);
784 if (prof_write("\nMAPPED_LIBRARIES:\n", propagate_err
) &&
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
)
795 nread
= read(mfd
, &prof_dump_buf
[prof_dump_buf_end
],
796 PROF_DUMP_BUF_SIZE
- prof_dump_buf_end
);
806 prof_dump(const char *filename
, bool leakcheck
, bool propagate_err
)
818 char buf
[UMAX2S_BUFSIZE
];
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");
834 /* Merge per thread profile stats, and sum them in cnt_all. */
835 memset(&cnt_all
, 0, sizeof(prof_cnt_t
));
837 for (tabind
= 0; ckh_iter(&bt2ctx
, &tabind
, NULL
, &ctx
.v
) == false;)
838 prof_ctx_sum(ctx
.p
, &cnt_all
, &leak_nctx
);
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
))
851 if (opt_lg_prof_sample
== 0) {
852 if (prof_write("] @ heapprofile\n", propagate_err
))
855 if (prof_write("] @ heap_v2/", propagate_err
)
856 || prof_write(u2s((uint64_t)1U << opt_lg_prof_sample
, 10,
858 || prof_write("\n", propagate_err
))
862 /* Dump per ctx profile stats. */
863 for (tabind
= 0; ckh_iter(&bt2ctx
, &tabind
, &bt
.v
, &ctx
.v
)
865 if (prof_dump_ctx(ctx
.p
, bt
.p
, propagate_err
))
869 /* Dump /proc/<pid>/maps if possible. */
870 if (prof_dump_maps(propagate_err
))
873 if (prof_flush(propagate_err
))
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, " :
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");
898 #define DUMP_FILENAME_BUFSIZE (PATH_MAX+ UMAX2S_BUFSIZE \
905 prof_dump_filename(char *filename
, char v
, int64_t vseq
)
907 char buf
[UMAX2S_BUFSIZE
];
912 * Construct a filename of the form:
914 * <prefix>.<pid>.<seq>.v<vseq>.heap\0
921 memcpy(&filename
[i
], s
, slen
);
926 memcpy(&filename
[i
], s
, slen
);
929 s
= u2s(getpid(), 10, buf
);
931 memcpy(&filename
[i
], s
, slen
);
936 memcpy(&filename
[i
], s
, slen
);
939 s
= u2s(prof_dump_seq
, 10, buf
);
942 memcpy(&filename
[i
], s
, slen
);
947 memcpy(&filename
[i
], s
, slen
);
953 if (vseq
!= 0xffffffffffffffffLLU
) {
954 s
= u2s(vseq
, 10, buf
);
956 memcpy(&filename
[i
], s
, slen
);
962 memcpy(&filename
[i
], s
, slen
);
971 char filename
[DUMP_FILENAME_BUFSIZE
];
973 if (prof_booted
== false)
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);
987 char filename
[DUMP_FILENAME_BUFSIZE
];
989 if (prof_booted
== false)
991 malloc_mutex_lock(&enq_mtx
);
994 malloc_mutex_unlock(&enq_mtx
);
997 malloc_mutex_unlock(&enq_mtx
);
999 if (opt_prof_prefix
[0] != '\0') {
1000 malloc_mutex_lock(&prof_dump_seq_mtx
);
1001 prof_dump_filename(filename
, 'i', prof_dump_iseq
);
1003 malloc_mutex_unlock(&prof_dump_seq_mtx
);
1004 prof_dump(filename
, false, false);
1009 prof_mdump(const char *filename
)
1011 char filename_buf
[DUMP_FILENAME_BUFSIZE
];
1013 if (opt_prof
== false || prof_booted
== false)
1016 if (filename
== NULL
) {
1017 /* No filename specified, so automatically generate one. */
1018 if (opt_prof_prefix
[0] == '\0')
1020 malloc_mutex_lock(&prof_dump_seq_mtx
);
1021 prof_dump_filename(filename_buf
, 'm', prof_dump_mseq
);
1023 malloc_mutex_unlock(&prof_dump_seq_mtx
);
1024 filename
= filename_buf
;
1026 return (prof_dump(filename
, false, true));
1032 char filename
[DUMP_FILENAME_BUFSIZE
];
1034 if (prof_booted
== false)
1036 malloc_mutex_lock(&enq_mtx
);
1039 malloc_mutex_unlock(&enq_mtx
);
1042 malloc_mutex_unlock(&enq_mtx
);
1044 if (opt_prof_prefix
[0] != '\0') {
1045 malloc_mutex_lock(&prof_dump_seq_mtx
);
1046 prof_dump_filename(filename
, 'u', prof_dump_useq
);
1048 malloc_mutex_unlock(&prof_dump_seq_mtx
);
1049 prof_dump(filename
, false, false);
1054 prof_bt_hash(const void *key
, unsigned minbits
, size_t *hash1
, size_t *hash2
)
1058 prof_bt_t
*bt
= (prof_bt_t
*)key
;
1060 assert(minbits
<= 32 || (SIZEOF_PTR
== 8 && minbits
<= 64));
1061 assert(hash1
!= NULL
);
1062 assert(hash2
!= NULL
);
1064 h
= hash(bt
->vec
, bt
->len
* sizeof(void *), 0x94122f335b332aeaLLU
);
1065 if (minbits
<= 32) {
1067 * Avoid doing multiple hashes, since a single hash provides
1070 ret1
= h
& ZU(0xffffffffU
);
1074 ret2
= hash(bt
->vec
, bt
->len
* sizeof(void *),
1075 0x8432a476666bbc13U
);
1083 prof_bt_keycomp(const void *k1
, const void *k2
)
1085 const prof_bt_t
*bt1
= (prof_bt_t
*)k1
;
1086 const prof_bt_t
*bt2
= (prof_bt_t
*)k2
;
1088 if (bt1
->len
!= bt2
->len
)
1090 return (memcmp(bt1
->vec
, bt2
->vec
, bt1
->len
* sizeof(void *)) == 0);
1094 prof_tdata_init(void)
1096 prof_tdata_t
*prof_tdata
;
1098 /* Initialize an empty cache for this thread. */
1099 prof_tdata
= (prof_tdata_t
*)imalloc(sizeof(prof_tdata_t
));
1100 if (prof_tdata
== NULL
)
1103 if (ckh_new(&prof_tdata
->bt2cnt
, PROF_CKH_MINITEMS
,
1104 prof_bt_hash
, prof_bt_keycomp
)) {
1105 idalloc(prof_tdata
);
1108 ql_new(&prof_tdata
->lru_ql
);
1110 prof_tdata
->vec
= imalloc(sizeof(void *) * prof_bt_max
);
1111 if (prof_tdata
->vec
== NULL
) {
1113 ckh_delete(&prof_tdata
->bt2cnt
);
1114 idalloc(prof_tdata
);
1118 prof_tdata
->prn_state
= 0;
1119 prof_tdata
->threshold
= 0;
1120 prof_tdata
->accum
= 0;
1122 PROF_TCACHE_SET(prof_tdata
);
1124 return (prof_tdata
);
1128 prof_tdata_cleanup(void *arg
)
1130 prof_tdata_t
*prof_tdata
;
1132 prof_tdata
= PROF_TCACHE_GET();
1133 if (prof_tdata
!= NULL
) {
1134 prof_thr_cnt_t
*cnt
;
1137 * Delete the hash table. All of its contents can still be
1138 * iterated over via the LRU.
1140 ckh_delete(&prof_tdata
->bt2cnt
);
1143 * Iteratively merge cnt's into the global stats and delete
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
);
1152 idalloc(prof_tdata
->vec
);
1154 idalloc(prof_tdata
);
1155 PROF_TCACHE_SET(NULL
);
1163 memcpy(opt_prof_prefix
, PROF_PREFIX_DEFAULT
,
1164 sizeof(PROF_PREFIX_DEFAULT
));
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.
1176 if (opt_prof_leak
&& opt_prof
== false) {
1178 * Enable opt_prof, but in such a way that profiles are never
1179 * automatically dumped.
1182 opt_prof_gdump
= false;
1184 } else if (opt_prof
) {
1185 if (opt_lg_prof_interval
>= 0) {
1186 prof_interval
= (((uint64_t)1U) <<
1187 opt_lg_prof_interval
);
1192 prof_promote
= (opt_prof
&& opt_lg_prof_sample
> PAGE_SHIFT
);
1200 if (ckh_new(&bt2ctx
, PROF_CKH_MINITEMS
, prof_bt_hash
,
1203 if (malloc_mutex_init(&bt2ctx_mtx
))
1205 if (pthread_key_create(&prof_tdata_tsd
, prof_tdata_cleanup
)
1208 "<jemalloc>: Error in pthread_key_create()\n");
1212 prof_bt_max
= (1U << opt_lg_prof_bt_max
);
1213 if (malloc_mutex_init(&prof_dump_seq_mtx
))
1216 if (malloc_mutex_init(&enq_mtx
))
1222 if (atexit(prof_fdump
) != 0) {
1223 malloc_write("<jemalloc>: Error in atexit()\n");
1229 #ifdef JEMALLOC_PROF_LIBGCC
1231 * Cause the backtracing machinery to allocate its internal state
1232 * before enabling profiling.
1234 _Unwind_Backtrace(prof_unwind_init_callback
, NULL
);
1242 /******************************************************************************/
1243 #endif /* JEMALLOC_PROF */