Pass write callback explicitly in prof_data

This commit is contained in:
Yinan Zhang 2020-04-20 14:09:08 -07:00
parent 4556d3c0c8
commit 1f5fe3a3e3
4 changed files with 84 additions and 54 deletions

View File

@ -17,8 +17,8 @@ bool prof_data_init(tsd_t *tsd);
prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt); prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt);
char *prof_thread_name_alloc(tsd_t *tsd, const char *thread_name); char *prof_thread_name_alloc(tsd_t *tsd, const char *thread_name);
int prof_thread_name_set_impl(tsd_t *tsd, const char *thread_name); int prof_thread_name_set_impl(tsd_t *tsd, const char *thread_name);
void prof_dump_impl(tsd_t *tsd, prof_tdata_t *tdata, void prof_dump_impl(tsd_t *tsd, write_cb_t *prof_dump_write, void *cbopaque,
void (*write_cb)(const char *), bool leakcheck); prof_tdata_t *tdata, bool leakcheck);
prof_tdata_t * prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, prof_tdata_t * prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid,
uint64_t thr_discrim, char *thread_name, bool active); uint64_t thr_discrim, char *thread_name, bool active);
void prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata); void prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata);
@ -28,7 +28,8 @@ void prof_tctx_try_destroy(tsd_t *tsd, prof_tctx_t *tctx);
/* Used in unit tests. */ /* Used in unit tests. */
size_t prof_tdata_count(void); size_t prof_tdata_count(void);
size_t prof_bt_count(void); size_t prof_bt_count(void);
typedef void (prof_dump_header_t)(tsdn_t *, const prof_cnt_t *); typedef void (prof_dump_header_t)(tsdn_t *, write_cb_t *, void *,
const prof_cnt_t *);
extern prof_dump_header_t *JET_MUTABLE prof_dump_header; extern prof_dump_header_t *JET_MUTABLE prof_dump_header;
void prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, uint64_t *accumobjs, void prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, uint64_t *accumobjs,
uint64_t *accumbytes); uint64_t *accumbytes);

View File

@ -59,9 +59,6 @@ static ckh_t bt2gctx;
*/ */
static prof_tdata_tree_t tdatas; static prof_tdata_tree_t tdatas;
/* Dump write callback; stored global to simplify function interfaces. */
static void (*prof_dump_write)(const char *);
/******************************************************************************/ /******************************************************************************/
/* Red-black trees. */ /* Red-black trees. */
@ -504,21 +501,24 @@ prof_thread_name_set_impl(tsd_t *tsd, const char *thread_name) {
return 0; return 0;
} }
JEMALLOC_FORMAT_PRINTF(1, 2) JEMALLOC_FORMAT_PRINTF(3, 4)
static void static void
prof_dump_printf(const char *format, ...) { prof_dump_printf(write_cb_t *prof_dump_write, void *cbopaque,
const char *format, ...) {
va_list ap; va_list ap;
char buf[PROF_PRINTF_BUFSIZE]; char buf[PROF_PRINTF_BUFSIZE];
va_start(ap, format); va_start(ap, format);
malloc_vsnprintf(buf, sizeof(buf), format, ap); malloc_vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap); va_end(ap);
prof_dump_write(buf); prof_dump_write(cbopaque, buf);
} }
static void static void
prof_dump_print_cnts(const prof_cnt_t *cnts) { prof_dump_print_cnts(write_cb_t *prof_dump_write, void *cbopaque,
prof_dump_printf("%"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]", const prof_cnt_t *cnts) {
prof_dump_printf(prof_dump_write, cbopaque,
"%"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]",
cnts->curobjs, cnts->curbytes, cnts->accumobjs, cnts->accumbytes); cnts->curobjs, cnts->curbytes, cnts->accumobjs, cnts->accumbytes);
} }
@ -586,10 +586,17 @@ prof_tctx_merge_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) {
return NULL; return NULL;
} }
typedef struct prof_tctx_dump_iter_arg_s prof_tctx_dump_iter_arg_t;
struct prof_tctx_dump_iter_arg_s {
tsdn_t *tsdn;
write_cb_t *prof_dump_write;
void *cbopaque;
};
static prof_tctx_t * static prof_tctx_t *
prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) { prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *opaque) {
tsdn_t *tsdn = (tsdn_t *)arg; prof_tctx_dump_iter_arg_t *arg = (prof_tctx_dump_iter_arg_t *)opaque;
malloc_mutex_assert_owner(tsdn, tctx->gctx->lock); malloc_mutex_assert_owner(arg->tsdn, tctx->gctx->lock);
switch (tctx->state) { switch (tctx->state) {
case prof_tctx_state_initializing: case prof_tctx_state_initializing:
@ -598,9 +605,11 @@ prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) {
break; break;
case prof_tctx_state_dumping: case prof_tctx_state_dumping:
case prof_tctx_state_purgatory: case prof_tctx_state_purgatory:
prof_dump_printf(" t%"FMTu64": ", tctx->thr_uid); prof_dump_printf(arg->prof_dump_write, arg->cbopaque,
prof_dump_print_cnts(&tctx->dump_cnts); " t%"FMTu64": ", tctx->thr_uid);
prof_dump_write("\n"); prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque,
&tctx->dump_cnts);
arg->prof_dump_write(arg->cbopaque, "\n");
break; break;
default: default:
not_reached(); not_reached();
@ -761,38 +770,50 @@ prof_tdata_merge_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata,
return NULL; return NULL;
} }
typedef struct prof_tdata_dump_iter_arg_s prof_tdata_dump_iter_arg_t;
struct prof_tdata_dump_iter_arg_s {
write_cb_t *prof_dump_write;
void *cbopaque;
};
static prof_tdata_t * static prof_tdata_t *
prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata,
void *unused) { void *opaque) {
if (!tdata->dumping) { if (!tdata->dumping) {
return NULL; return NULL;
} }
prof_dump_printf(" t%"FMTu64": ", tdata->thr_uid); prof_tdata_dump_iter_arg_t *arg = (prof_tdata_dump_iter_arg_t *)opaque;
prof_dump_print_cnts(&tdata->cnt_summed); prof_dump_printf(arg->prof_dump_write, arg->cbopaque, " t%"FMTu64": ",
tdata->thr_uid);
prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque,
&tdata->cnt_summed);
if (tdata->thread_name != NULL) { if (tdata->thread_name != NULL) {
prof_dump_printf(" %s", tdata->thread_name); arg->prof_dump_write(arg->cbopaque, " ");
arg->prof_dump_write(arg->cbopaque, tdata->thread_name);
} }
prof_dump_write("\n"); arg->prof_dump_write(arg->cbopaque, "\n");
return NULL; return NULL;
} }
static void static void
prof_dump_header_impl(tsdn_t *tsdn, const prof_cnt_t *cnt_all) { prof_dump_header_impl(tsdn_t *tsdn, write_cb_t *prof_dump_write,
prof_dump_printf("heap_v2/%"FMTu64"\n t*: ", void *cbopaque, const prof_cnt_t *cnt_all) {
((uint64_t)1U << lg_prof_sample)); prof_dump_printf(prof_dump_write, cbopaque,
prof_dump_print_cnts(cnt_all); "heap_v2/%"FMTu64"\n t*: ", ((uint64_t)1U << lg_prof_sample));
prof_dump_write("\n"); prof_dump_print_cnts(prof_dump_write, cbopaque, cnt_all);
prof_dump_write(cbopaque, "\n");
prof_tdata_dump_iter_arg_t arg = {prof_dump_write, cbopaque};
malloc_mutex_lock(tsdn, &tdatas_mtx); malloc_mutex_lock(tsdn, &tdatas_mtx);
tdata_tree_iter(&tdatas, NULL, prof_tdata_dump_iter, NULL); tdata_tree_iter(&tdatas, NULL, prof_tdata_dump_iter, &arg);
malloc_mutex_unlock(tsdn, &tdatas_mtx); malloc_mutex_unlock(tsdn, &tdatas_mtx);
} }
prof_dump_header_t *JET_MUTABLE prof_dump_header = prof_dump_header_impl; prof_dump_header_t *JET_MUTABLE prof_dump_header = prof_dump_header_impl;
static void static void
prof_dump_gctx(tsdn_t *tsdn, prof_gctx_t *gctx, const prof_bt_t *bt, prof_dump_gctx(tsdn_t *tsdn, write_cb_t *prof_dump_write, void *cbopaque,
prof_gctx_tree_t *gctxs) { prof_gctx_t *gctx, const prof_bt_t *bt, prof_gctx_tree_t *gctxs) {
cassert(config_prof); cassert(config_prof);
malloc_mutex_assert_owner(tsdn, gctx->lock); malloc_mutex_assert_owner(tsdn, gctx->lock);
@ -806,17 +827,18 @@ prof_dump_gctx(tsdn_t *tsdn, prof_gctx_t *gctx, const prof_bt_t *bt,
return; return;
} }
prof_dump_write("@"); prof_dump_write(cbopaque, "@");
for (unsigned i = 0; i < bt->len; i++) { for (unsigned i = 0; i < bt->len; i++) {
prof_dump_printf(" %#"FMTxPTR, (uintptr_t)bt->vec[i]); prof_dump_printf(prof_dump_write, cbopaque, " %#"FMTxPTR,
(uintptr_t)bt->vec[i]);
} }
prof_dump_write("\n t*: "); prof_dump_write(cbopaque, "\n t*: ");
prof_dump_print_cnts(&gctx->cnt_summed); prof_dump_print_cnts(prof_dump_write, cbopaque, &gctx->cnt_summed);
prof_dump_write("\n"); prof_dump_write(cbopaque, "\n");
tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_dump_iter, prof_tctx_dump_iter_arg_t arg = {tsdn, prof_dump_write, cbopaque};
(void *)tsdn); tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_dump_iter, &arg);
} }
/* /*
@ -852,12 +874,20 @@ prof_leakcheck(const prof_cnt_t *cnt_all, size_t leak_ngctx) {
#endif #endif
} }
typedef struct prof_gctx_dump_iter_arg_s prof_gctx_dump_iter_arg_t;
struct prof_gctx_dump_iter_arg_s {
tsdn_t *tsdn;
write_cb_t *prof_dump_write;
void *cbopaque;
};
static prof_gctx_t * static prof_gctx_t *
prof_gctx_dump_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) { prof_gctx_dump_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) {
tsdn_t *tsdn = (tsdn_t *)opaque; prof_gctx_dump_iter_arg_t *arg = (prof_gctx_dump_iter_arg_t *)opaque;
malloc_mutex_lock(tsdn, gctx->lock); malloc_mutex_lock(arg->tsdn, gctx->lock);
prof_dump_gctx(tsdn, gctx, &gctx->bt, gctxs); prof_dump_gctx(arg->tsdn, arg->prof_dump_write, arg->cbopaque, gctx,
malloc_mutex_unlock(tsdn, gctx->lock); &gctx->bt, gctxs);
malloc_mutex_unlock(arg->tsdn, gctx->lock);
return NULL; return NULL;
} }
@ -904,18 +934,20 @@ prof_dump_prep(tsd_t *tsd, prof_tdata_t *tdata,
} }
void void
prof_dump_impl(tsd_t *tsd, prof_tdata_t *tdata, void (*write_cb)(const char *), prof_dump_impl(tsd_t *tsd, write_cb_t *prof_dump_write, void *cbopaque,
bool leakcheck) { prof_tdata_t *tdata, bool leakcheck) {
malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_dump_mtx); malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_dump_mtx);
prof_dump_write = write_cb;
prof_gctx_tree_t gctxs; prof_gctx_tree_t gctxs;
prof_tdata_merge_iter_arg_t prof_tdata_merge_iter_arg; prof_tdata_merge_iter_arg_t prof_tdata_merge_iter_arg;
prof_gctx_merge_iter_arg_t prof_gctx_merge_iter_arg; prof_gctx_merge_iter_arg_t prof_gctx_merge_iter_arg;
prof_dump_prep(tsd, tdata, &prof_tdata_merge_iter_arg, prof_dump_prep(tsd, tdata, &prof_tdata_merge_iter_arg,
&prof_gctx_merge_iter_arg, &gctxs); &prof_gctx_merge_iter_arg, &gctxs);
prof_dump_header(tsd_tsdn(tsd), &prof_tdata_merge_iter_arg.cnt_all); prof_dump_header(tsd_tsdn(tsd), prof_dump_write, cbopaque,
&prof_tdata_merge_iter_arg.cnt_all);
prof_gctx_dump_iter_arg_t prof_gctx_dump_iter_arg = {tsd_tsdn(tsd),
prof_dump_write, cbopaque};
gctx_tree_iter(&gctxs, NULL, prof_gctx_dump_iter, gctx_tree_iter(&gctxs, NULL, prof_gctx_dump_iter,
(void *)tsd_tsdn(tsd)); &prof_gctx_dump_iter_arg);
prof_gctx_finish(tsd, &gctxs); prof_gctx_finish(tsd, &gctxs);
if (leakcheck) { if (leakcheck) {
prof_leakcheck(&prof_tdata_merge_iter_arg.cnt_all, prof_leakcheck(&prof_tdata_merge_iter_arg.cnt_all,

View File

@ -388,11 +388,6 @@ prof_dump_flush(void *cbopaque, const char *s) {
} }
} }
static void
prof_dump_write(const char *s) {
buf_writer_cb(&prof_dump_buf_writer, s);
}
static void static void
prof_dump_close() { prof_dump_close() {
if (prof_dump_fd != -1) { if (prof_dump_fd != -1) {
@ -461,7 +456,7 @@ prof_dump_maps() {
return; return;
} }
prof_dump_write("\nMAPPED_LIBRARIES:\n"); buf_writer_cb(&prof_dump_buf_writer, "\nMAPPED_LIBRARIES:\n");
buf_writer_pipe(&prof_dump_buf_writer, prof_dump_read_maps_cb, &mfd); buf_writer_pipe(&prof_dump_buf_writer, prof_dump_read_maps_cb, &mfd);
close(mfd); close(mfd);
} }
@ -487,7 +482,8 @@ prof_dump(tsd_t *tsd, bool propagate_err, const char *filename,
bool err = buf_writer_init(tsd_tsdn(tsd), &prof_dump_buf_writer, bool err = buf_writer_init(tsd_tsdn(tsd), &prof_dump_buf_writer,
prof_dump_flush, NULL, prof_dump_buf, PROF_DUMP_BUFSIZE); prof_dump_flush, NULL, prof_dump_buf, PROF_DUMP_BUFSIZE);
assert(!err); assert(!err);
prof_dump_impl(tsd, tdata, prof_dump_write, leakcheck); prof_dump_impl(tsd, buf_writer_cb, &prof_dump_buf_writer, tdata,
leakcheck);
prof_dump_maps(); prof_dump_maps();
buf_writer_terminate(tsd_tsdn(tsd), &prof_dump_buf_writer); buf_writer_terminate(tsd_tsdn(tsd), &prof_dump_buf_writer);
prof_dump_close(); prof_dump_close();

View File

@ -87,7 +87,8 @@ TEST_END
bool prof_dump_header_intercepted = false; bool prof_dump_header_intercepted = false;
prof_cnt_t cnt_all_copy = {0, 0, 0, 0}; prof_cnt_t cnt_all_copy = {0, 0, 0, 0};
static void static void
prof_dump_header_intercept(tsdn_t *tsdn, const prof_cnt_t *cnt_all) { prof_dump_header_intercept(tsdn_t *tsdn, write_cb_t *cb, void *cbopaque,
const prof_cnt_t *cnt_all) {
prof_dump_header_intercepted = true; prof_dump_header_intercepted = true;
memcpy(&cnt_all_copy, cnt_all, sizeof(prof_cnt_t)); memcpy(&cnt_all_copy, cnt_all, sizeof(prof_cnt_t));
} }