1a0698ed9Schristos #include "test/jemalloc_test.h" 2a0698ed9Schristos 3*7bdf38e5Schristos #include "jemalloc/internal/prof_data.h" 4*7bdf38e5Schristos #include "jemalloc/internal/prof_sys.h" 5*7bdf38e5Schristos 6a0698ed9Schristos static int 7*7bdf38e5Schristos prof_dump_open_file_intercept(const char *filename, int mode) { 8a0698ed9Schristos int fd; 9a0698ed9Schristos 10a0698ed9Schristos fd = open("/dev/null", O_WRONLY); 11a0698ed9Schristos assert_d_ne(fd, -1, "Unexpected open() failure"); 12a0698ed9Schristos 13a0698ed9Schristos return fd; 14a0698ed9Schristos } 15a0698ed9Schristos 16a0698ed9Schristos static void 17a0698ed9Schristos set_prof_active(bool active) { 18*7bdf38e5Schristos expect_d_eq(mallctl("prof.active", NULL, NULL, (void *)&active, 19a0698ed9Schristos sizeof(active)), 0, "Unexpected mallctl failure"); 20a0698ed9Schristos } 21a0698ed9Schristos 22a0698ed9Schristos static size_t 23a0698ed9Schristos get_lg_prof_sample(void) { 24*7bdf38e5Schristos size_t ret; 25a0698ed9Schristos size_t sz = sizeof(size_t); 26a0698ed9Schristos 27*7bdf38e5Schristos expect_d_eq(mallctl("prof.lg_sample", (void *)&ret, &sz, NULL, 0), 0, 28a0698ed9Schristos "Unexpected mallctl failure while reading profiling sample rate"); 29*7bdf38e5Schristos return ret; 30a0698ed9Schristos } 31a0698ed9Schristos 32a0698ed9Schristos static void 33*7bdf38e5Schristos do_prof_reset(size_t lg_prof_sample_input) { 34*7bdf38e5Schristos expect_d_eq(mallctl("prof.reset", NULL, NULL, 35*7bdf38e5Schristos (void *)&lg_prof_sample_input, sizeof(size_t)), 0, 36a0698ed9Schristos "Unexpected mallctl failure while resetting profile data"); 37*7bdf38e5Schristos expect_zu_eq(lg_prof_sample_input, get_lg_prof_sample(), 38a0698ed9Schristos "Expected profile sample rate change"); 39a0698ed9Schristos } 40a0698ed9Schristos 41a0698ed9Schristos TEST_BEGIN(test_prof_reset_basic) { 42*7bdf38e5Schristos size_t lg_prof_sample_orig, lg_prof_sample_cur, lg_prof_sample_next; 43a0698ed9Schristos size_t sz; 44a0698ed9Schristos unsigned i; 45a0698ed9Schristos 46a0698ed9Schristos test_skip_if(!config_prof); 47a0698ed9Schristos 48a0698ed9Schristos sz = sizeof(size_t); 49*7bdf38e5Schristos expect_d_eq(mallctl("opt.lg_prof_sample", (void *)&lg_prof_sample_orig, 50a0698ed9Schristos &sz, NULL, 0), 0, 51a0698ed9Schristos "Unexpected mallctl failure while reading profiling sample rate"); 52*7bdf38e5Schristos expect_zu_eq(lg_prof_sample_orig, 0, 53a0698ed9Schristos "Unexpected profiling sample rate"); 54*7bdf38e5Schristos lg_prof_sample_cur = get_lg_prof_sample(); 55*7bdf38e5Schristos expect_zu_eq(lg_prof_sample_orig, lg_prof_sample_cur, 56a0698ed9Schristos "Unexpected disagreement between \"opt.lg_prof_sample\" and " 57a0698ed9Schristos "\"prof.lg_sample\""); 58a0698ed9Schristos 59a0698ed9Schristos /* Test simple resets. */ 60a0698ed9Schristos for (i = 0; i < 2; i++) { 61*7bdf38e5Schristos expect_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0, 62a0698ed9Schristos "Unexpected mallctl failure while resetting profile data"); 63*7bdf38e5Schristos lg_prof_sample_cur = get_lg_prof_sample(); 64*7bdf38e5Schristos expect_zu_eq(lg_prof_sample_orig, lg_prof_sample_cur, 65a0698ed9Schristos "Unexpected profile sample rate change"); 66a0698ed9Schristos } 67a0698ed9Schristos 68a0698ed9Schristos /* Test resets with prof.lg_sample changes. */ 69a0698ed9Schristos lg_prof_sample_next = 1; 70a0698ed9Schristos for (i = 0; i < 2; i++) { 71a0698ed9Schristos do_prof_reset(lg_prof_sample_next); 72*7bdf38e5Schristos lg_prof_sample_cur = get_lg_prof_sample(); 73*7bdf38e5Schristos expect_zu_eq(lg_prof_sample_cur, lg_prof_sample_next, 74a0698ed9Schristos "Expected profile sample rate change"); 75a0698ed9Schristos lg_prof_sample_next = lg_prof_sample_orig; 76a0698ed9Schristos } 77a0698ed9Schristos 78a0698ed9Schristos /* Make sure the test code restored prof.lg_sample. */ 79*7bdf38e5Schristos lg_prof_sample_cur = get_lg_prof_sample(); 80*7bdf38e5Schristos expect_zu_eq(lg_prof_sample_orig, lg_prof_sample_cur, 81a0698ed9Schristos "Unexpected disagreement between \"opt.lg_prof_sample\" and " 82a0698ed9Schristos "\"prof.lg_sample\""); 83a0698ed9Schristos } 84a0698ed9Schristos TEST_END 85a0698ed9Schristos 86a0698ed9Schristos TEST_BEGIN(test_prof_reset_cleanup) { 87a0698ed9Schristos test_skip_if(!config_prof); 88a0698ed9Schristos 89a0698ed9Schristos set_prof_active(true); 90a0698ed9Schristos 91*7bdf38e5Schristos expect_zu_eq(prof_bt_count(), 0, "Expected 0 backtraces"); 92*7bdf38e5Schristos void *p = mallocx(1, 0); 93*7bdf38e5Schristos expect_ptr_not_null(p, "Unexpected mallocx() failure"); 94*7bdf38e5Schristos expect_zu_eq(prof_bt_count(), 1, "Expected 1 backtrace"); 95a0698ed9Schristos 96*7bdf38e5Schristos prof_cnt_t cnt_all; 97*7bdf38e5Schristos prof_cnt_all(&cnt_all); 98*7bdf38e5Schristos expect_u64_eq(cnt_all.curobjs, 1, "Expected 1 allocation"); 99a0698ed9Schristos 100*7bdf38e5Schristos expect_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0, 101a0698ed9Schristos "Unexpected error while resetting heap profile data"); 102*7bdf38e5Schristos prof_cnt_all(&cnt_all); 103*7bdf38e5Schristos expect_u64_eq(cnt_all.curobjs, 0, "Expected 0 allocations"); 104*7bdf38e5Schristos expect_zu_eq(prof_bt_count(), 1, "Expected 1 backtrace"); 105a0698ed9Schristos 106a0698ed9Schristos dallocx(p, 0); 107*7bdf38e5Schristos expect_zu_eq(prof_bt_count(), 0, "Expected 0 backtraces"); 108a0698ed9Schristos 109a0698ed9Schristos set_prof_active(false); 110a0698ed9Schristos } 111a0698ed9Schristos TEST_END 112a0698ed9Schristos 113a0698ed9Schristos #define NTHREADS 4 114a0698ed9Schristos #define NALLOCS_PER_THREAD (1U << 13) 115a0698ed9Schristos #define OBJ_RING_BUF_COUNT 1531 116a0698ed9Schristos #define RESET_INTERVAL (1U << 10) 117a0698ed9Schristos #define DUMP_INTERVAL 3677 118a0698ed9Schristos static void * 119a0698ed9Schristos thd_start(void *varg) { 120a0698ed9Schristos unsigned thd_ind = *(unsigned *)varg; 121a0698ed9Schristos unsigned i; 122a0698ed9Schristos void *objs[OBJ_RING_BUF_COUNT]; 123a0698ed9Schristos 124a0698ed9Schristos memset(objs, 0, sizeof(objs)); 125a0698ed9Schristos 126a0698ed9Schristos for (i = 0; i < NALLOCS_PER_THREAD; i++) { 127a0698ed9Schristos if (i % RESET_INTERVAL == 0) { 128*7bdf38e5Schristos expect_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 129a0698ed9Schristos 0, "Unexpected error while resetting heap profile " 130a0698ed9Schristos "data"); 131a0698ed9Schristos } 132a0698ed9Schristos 133a0698ed9Schristos if (i % DUMP_INTERVAL == 0) { 134*7bdf38e5Schristos expect_d_eq(mallctl("prof.dump", NULL, NULL, NULL, 0), 135a0698ed9Schristos 0, "Unexpected error while dumping heap profile"); 136a0698ed9Schristos } 137a0698ed9Schristos 138a0698ed9Schristos { 139a0698ed9Schristos void **pp = &objs[i % OBJ_RING_BUF_COUNT]; 140a0698ed9Schristos if (*pp != NULL) { 141a0698ed9Schristos dallocx(*pp, 0); 142a0698ed9Schristos *pp = NULL; 143a0698ed9Schristos } 144a0698ed9Schristos *pp = btalloc(1, thd_ind*NALLOCS_PER_THREAD + i); 145*7bdf38e5Schristos expect_ptr_not_null(*pp, 146a0698ed9Schristos "Unexpected btalloc() failure"); 147a0698ed9Schristos } 148a0698ed9Schristos } 149a0698ed9Schristos 150a0698ed9Schristos /* Clean up any remaining objects. */ 151a0698ed9Schristos for (i = 0; i < OBJ_RING_BUF_COUNT; i++) { 152a0698ed9Schristos void **pp = &objs[i % OBJ_RING_BUF_COUNT]; 153a0698ed9Schristos if (*pp != NULL) { 154a0698ed9Schristos dallocx(*pp, 0); 155a0698ed9Schristos *pp = NULL; 156a0698ed9Schristos } 157a0698ed9Schristos } 158a0698ed9Schristos 159a0698ed9Schristos return NULL; 160a0698ed9Schristos } 161a0698ed9Schristos 162a0698ed9Schristos TEST_BEGIN(test_prof_reset) { 163a0698ed9Schristos size_t lg_prof_sample_orig; 164a0698ed9Schristos thd_t thds[NTHREADS]; 165a0698ed9Schristos unsigned thd_args[NTHREADS]; 166a0698ed9Schristos unsigned i; 167a0698ed9Schristos size_t bt_count, tdata_count; 168a0698ed9Schristos 169a0698ed9Schristos test_skip_if(!config_prof); 170a0698ed9Schristos 171a0698ed9Schristos bt_count = prof_bt_count(); 172*7bdf38e5Schristos expect_zu_eq(bt_count, 0, 173a0698ed9Schristos "Unexpected pre-existing tdata structures"); 174a0698ed9Schristos tdata_count = prof_tdata_count(); 175a0698ed9Schristos 176a0698ed9Schristos lg_prof_sample_orig = get_lg_prof_sample(); 177a0698ed9Schristos do_prof_reset(5); 178a0698ed9Schristos 179a0698ed9Schristos set_prof_active(true); 180a0698ed9Schristos 181a0698ed9Schristos for (i = 0; i < NTHREADS; i++) { 182a0698ed9Schristos thd_args[i] = i; 183a0698ed9Schristos thd_create(&thds[i], thd_start, (void *)&thd_args[i]); 184a0698ed9Schristos } 185a0698ed9Schristos for (i = 0; i < NTHREADS; i++) { 186a0698ed9Schristos thd_join(thds[i], NULL); 187a0698ed9Schristos } 188a0698ed9Schristos 189*7bdf38e5Schristos expect_zu_eq(prof_bt_count(), bt_count, 190a0698ed9Schristos "Unexpected bactrace count change"); 191*7bdf38e5Schristos expect_zu_eq(prof_tdata_count(), tdata_count, 192a0698ed9Schristos "Unexpected remaining tdata structures"); 193a0698ed9Schristos 194a0698ed9Schristos set_prof_active(false); 195a0698ed9Schristos 196a0698ed9Schristos do_prof_reset(lg_prof_sample_orig); 197a0698ed9Schristos } 198a0698ed9Schristos TEST_END 199a0698ed9Schristos #undef NTHREADS 200a0698ed9Schristos #undef NALLOCS_PER_THREAD 201a0698ed9Schristos #undef OBJ_RING_BUF_COUNT 202a0698ed9Schristos #undef RESET_INTERVAL 203a0698ed9Schristos #undef DUMP_INTERVAL 204a0698ed9Schristos 205a0698ed9Schristos /* Test sampling at the same allocation site across resets. */ 206a0698ed9Schristos #define NITER 10 207a0698ed9Schristos TEST_BEGIN(test_xallocx) { 208a0698ed9Schristos size_t lg_prof_sample_orig; 209a0698ed9Schristos unsigned i; 210a0698ed9Schristos void *ptrs[NITER]; 211a0698ed9Schristos 212a0698ed9Schristos test_skip_if(!config_prof); 213a0698ed9Schristos 214a0698ed9Schristos lg_prof_sample_orig = get_lg_prof_sample(); 215a0698ed9Schristos set_prof_active(true); 216a0698ed9Schristos 217a0698ed9Schristos /* Reset profiling. */ 218a0698ed9Schristos do_prof_reset(0); 219a0698ed9Schristos 220a0698ed9Schristos for (i = 0; i < NITER; i++) { 221a0698ed9Schristos void *p; 222a0698ed9Schristos size_t sz, nsz; 223a0698ed9Schristos 224a0698ed9Schristos /* Reset profiling. */ 225a0698ed9Schristos do_prof_reset(0); 226a0698ed9Schristos 227a0698ed9Schristos /* Allocate small object (which will be promoted). */ 228a0698ed9Schristos p = ptrs[i] = mallocx(1, 0); 229*7bdf38e5Schristos expect_ptr_not_null(p, "Unexpected mallocx() failure"); 230a0698ed9Schristos 231a0698ed9Schristos /* Reset profiling. */ 232a0698ed9Schristos do_prof_reset(0); 233a0698ed9Schristos 234a0698ed9Schristos /* Perform successful xallocx(). */ 235a0698ed9Schristos sz = sallocx(p, 0); 236*7bdf38e5Schristos expect_zu_eq(xallocx(p, sz, 0, 0), sz, 237a0698ed9Schristos "Unexpected xallocx() failure"); 238a0698ed9Schristos 239a0698ed9Schristos /* Perform unsuccessful xallocx(). */ 240a0698ed9Schristos nsz = nallocx(sz+1, 0); 241*7bdf38e5Schristos expect_zu_eq(xallocx(p, nsz, 0, 0), sz, 242a0698ed9Schristos "Unexpected xallocx() success"); 243a0698ed9Schristos } 244a0698ed9Schristos 245a0698ed9Schristos for (i = 0; i < NITER; i++) { 246a0698ed9Schristos /* dallocx. */ 247a0698ed9Schristos dallocx(ptrs[i], 0); 248a0698ed9Schristos } 249a0698ed9Schristos 250a0698ed9Schristos set_prof_active(false); 251a0698ed9Schristos do_prof_reset(lg_prof_sample_orig); 252a0698ed9Schristos } 253a0698ed9Schristos TEST_END 254a0698ed9Schristos #undef NITER 255a0698ed9Schristos 256a0698ed9Schristos int 257a0698ed9Schristos main(void) { 258a0698ed9Schristos /* Intercept dumping prior to running any tests. */ 259*7bdf38e5Schristos prof_dump_open_file = prof_dump_open_file_intercept; 260a0698ed9Schristos 261a0698ed9Schristos return test_no_reentrancy( 262a0698ed9Schristos test_prof_reset_basic, 263a0698ed9Schristos test_prof_reset_cleanup, 264a0698ed9Schristos test_prof_reset, 265a0698ed9Schristos test_xallocx); 266a0698ed9Schristos } 267