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