1*7bdf38e5Schristos #include "test/jemalloc_test.h" 2*7bdf38e5Schristos 3*7bdf38e5Schristos #define BATCH_MAX ((1U << 16) + 1024) 4*7bdf38e5Schristos static void *global_ptrs[BATCH_MAX]; 5*7bdf38e5Schristos 6*7bdf38e5Schristos #define PAGE_ALIGNED(ptr) (((uintptr_t)ptr & PAGE_MASK) == 0) 7*7bdf38e5Schristos 8*7bdf38e5Schristos static void 9*7bdf38e5Schristos verify_batch_basic(tsd_t *tsd, void **ptrs, size_t batch, size_t usize, 10*7bdf38e5Schristos bool zero) { 11*7bdf38e5Schristos for (size_t i = 0; i < batch; ++i) { 12*7bdf38e5Schristos void *p = ptrs[i]; 13*7bdf38e5Schristos expect_zu_eq(isalloc(tsd_tsdn(tsd), p), usize, ""); 14*7bdf38e5Schristos if (zero) { 15*7bdf38e5Schristos for (size_t k = 0; k < usize; ++k) { 16*7bdf38e5Schristos expect_true(*((unsigned char *)p + k) == 0, ""); 17*7bdf38e5Schristos } 18*7bdf38e5Schristos } 19*7bdf38e5Schristos } 20*7bdf38e5Schristos } 21*7bdf38e5Schristos 22*7bdf38e5Schristos static void 23*7bdf38e5Schristos verify_batch_locality(tsd_t *tsd, void **ptrs, size_t batch, size_t usize, 24*7bdf38e5Schristos arena_t *arena, unsigned nregs) { 25*7bdf38e5Schristos if (config_prof && opt_prof) { 26*7bdf38e5Schristos /* 27*7bdf38e5Schristos * Checking batch locality when prof is on is feasible but 28*7bdf38e5Schristos * complicated, while checking the non-prof case suffices for 29*7bdf38e5Schristos * unit-test purpose. 30*7bdf38e5Schristos */ 31*7bdf38e5Schristos return; 32*7bdf38e5Schristos } 33*7bdf38e5Schristos for (size_t i = 0, j = 0; i < batch; ++i, ++j) { 34*7bdf38e5Schristos if (j == nregs) { 35*7bdf38e5Schristos j = 0; 36*7bdf38e5Schristos } 37*7bdf38e5Schristos if (j == 0 && batch - i < nregs) { 38*7bdf38e5Schristos break; 39*7bdf38e5Schristos } 40*7bdf38e5Schristos void *p = ptrs[i]; 41*7bdf38e5Schristos expect_ptr_eq(iaalloc(tsd_tsdn(tsd), p), arena, ""); 42*7bdf38e5Schristos if (j == 0) { 43*7bdf38e5Schristos expect_true(PAGE_ALIGNED(p), ""); 44*7bdf38e5Schristos continue; 45*7bdf38e5Schristos } 46*7bdf38e5Schristos assert(i > 0); 47*7bdf38e5Schristos void *q = ptrs[i - 1]; 48*7bdf38e5Schristos expect_true((uintptr_t)p > (uintptr_t)q 49*7bdf38e5Schristos && (size_t)((uintptr_t)p - (uintptr_t)q) == usize, ""); 50*7bdf38e5Schristos } 51*7bdf38e5Schristos } 52*7bdf38e5Schristos 53*7bdf38e5Schristos static void 54*7bdf38e5Schristos release_batch(void **ptrs, size_t batch, size_t size) { 55*7bdf38e5Schristos for (size_t i = 0; i < batch; ++i) { 56*7bdf38e5Schristos sdallocx(ptrs[i], size, 0); 57*7bdf38e5Schristos } 58*7bdf38e5Schristos } 59*7bdf38e5Schristos 60*7bdf38e5Schristos typedef struct batch_alloc_packet_s batch_alloc_packet_t; 61*7bdf38e5Schristos struct batch_alloc_packet_s { 62*7bdf38e5Schristos void **ptrs; 63*7bdf38e5Schristos size_t num; 64*7bdf38e5Schristos size_t size; 65*7bdf38e5Schristos int flags; 66*7bdf38e5Schristos }; 67*7bdf38e5Schristos 68*7bdf38e5Schristos static size_t 69*7bdf38e5Schristos batch_alloc_wrapper(void **ptrs, size_t num, size_t size, int flags) { 70*7bdf38e5Schristos batch_alloc_packet_t batch_alloc_packet = {ptrs, num, size, flags}; 71*7bdf38e5Schristos size_t filled; 72*7bdf38e5Schristos size_t len = sizeof(size_t); 73*7bdf38e5Schristos assert_d_eq(mallctl("experimental.batch_alloc", &filled, &len, 74*7bdf38e5Schristos &batch_alloc_packet, sizeof(batch_alloc_packet)), 0, ""); 75*7bdf38e5Schristos return filled; 76*7bdf38e5Schristos } 77*7bdf38e5Schristos 78*7bdf38e5Schristos static void 79*7bdf38e5Schristos test_wrapper(size_t size, size_t alignment, bool zero, unsigned arena_flag) { 80*7bdf38e5Schristos tsd_t *tsd = tsd_fetch(); 81*7bdf38e5Schristos assert(tsd != NULL); 82*7bdf38e5Schristos const size_t usize = 83*7bdf38e5Schristos (alignment != 0 ? sz_sa2u(size, alignment) : sz_s2u(size)); 84*7bdf38e5Schristos const szind_t ind = sz_size2index(usize); 85*7bdf38e5Schristos const bin_info_t *bin_info = &bin_infos[ind]; 86*7bdf38e5Schristos const unsigned nregs = bin_info->nregs; 87*7bdf38e5Schristos assert(nregs > 0); 88*7bdf38e5Schristos arena_t *arena; 89*7bdf38e5Schristos if (arena_flag != 0) { 90*7bdf38e5Schristos arena = arena_get(tsd_tsdn(tsd), MALLOCX_ARENA_GET(arena_flag), 91*7bdf38e5Schristos false); 92*7bdf38e5Schristos } else { 93*7bdf38e5Schristos arena = arena_choose(tsd, NULL); 94*7bdf38e5Schristos } 95*7bdf38e5Schristos assert(arena != NULL); 96*7bdf38e5Schristos int flags = arena_flag; 97*7bdf38e5Schristos if (alignment != 0) { 98*7bdf38e5Schristos flags |= MALLOCX_ALIGN(alignment); 99*7bdf38e5Schristos } 100*7bdf38e5Schristos if (zero) { 101*7bdf38e5Schristos flags |= MALLOCX_ZERO; 102*7bdf38e5Schristos } 103*7bdf38e5Schristos 104*7bdf38e5Schristos /* 105*7bdf38e5Schristos * Allocate for the purpose of bootstrapping arena_tdata, so that the 106*7bdf38e5Schristos * change in bin stats won't contaminate the stats to be verified below. 107*7bdf38e5Schristos */ 108*7bdf38e5Schristos void *p = mallocx(size, flags | MALLOCX_TCACHE_NONE); 109*7bdf38e5Schristos 110*7bdf38e5Schristos for (size_t i = 0; i < 4; ++i) { 111*7bdf38e5Schristos size_t base = 0; 112*7bdf38e5Schristos if (i == 1) { 113*7bdf38e5Schristos base = nregs; 114*7bdf38e5Schristos } else if (i == 2) { 115*7bdf38e5Schristos base = nregs * 2; 116*7bdf38e5Schristos } else if (i == 3) { 117*7bdf38e5Schristos base = (1 << 16); 118*7bdf38e5Schristos } 119*7bdf38e5Schristos for (int j = -1; j <= 1; ++j) { 120*7bdf38e5Schristos if (base == 0 && j == -1) { 121*7bdf38e5Schristos continue; 122*7bdf38e5Schristos } 123*7bdf38e5Schristos size_t batch = base + (size_t)j; 124*7bdf38e5Schristos assert(batch < BATCH_MAX); 125*7bdf38e5Schristos size_t filled = batch_alloc_wrapper(global_ptrs, batch, 126*7bdf38e5Schristos size, flags); 127*7bdf38e5Schristos assert_zu_eq(filled, batch, ""); 128*7bdf38e5Schristos verify_batch_basic(tsd, global_ptrs, batch, usize, 129*7bdf38e5Schristos zero); 130*7bdf38e5Schristos verify_batch_locality(tsd, global_ptrs, batch, usize, 131*7bdf38e5Schristos arena, nregs); 132*7bdf38e5Schristos release_batch(global_ptrs, batch, usize); 133*7bdf38e5Schristos } 134*7bdf38e5Schristos } 135*7bdf38e5Schristos 136*7bdf38e5Schristos free(p); 137*7bdf38e5Schristos } 138*7bdf38e5Schristos 139*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc) { 140*7bdf38e5Schristos test_wrapper(11, 0, false, 0); 141*7bdf38e5Schristos } 142*7bdf38e5Schristos TEST_END 143*7bdf38e5Schristos 144*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc_zero) { 145*7bdf38e5Schristos test_wrapper(11, 0, true, 0); 146*7bdf38e5Schristos } 147*7bdf38e5Schristos TEST_END 148*7bdf38e5Schristos 149*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc_aligned) { 150*7bdf38e5Schristos test_wrapper(7, 16, false, 0); 151*7bdf38e5Schristos } 152*7bdf38e5Schristos TEST_END 153*7bdf38e5Schristos 154*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc_manual_arena) { 155*7bdf38e5Schristos unsigned arena_ind; 156*7bdf38e5Schristos size_t len_unsigned = sizeof(unsigned); 157*7bdf38e5Schristos assert_d_eq(mallctl("arenas.create", &arena_ind, &len_unsigned, NULL, 158*7bdf38e5Schristos 0), 0, ""); 159*7bdf38e5Schristos test_wrapper(11, 0, false, MALLOCX_ARENA(arena_ind)); 160*7bdf38e5Schristos } 161*7bdf38e5Schristos TEST_END 162*7bdf38e5Schristos 163*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc_large) { 164*7bdf38e5Schristos size_t size = SC_LARGE_MINCLASS; 165*7bdf38e5Schristos for (size_t batch = 0; batch < 4; ++batch) { 166*7bdf38e5Schristos assert(batch < BATCH_MAX); 167*7bdf38e5Schristos size_t filled = batch_alloc(global_ptrs, batch, size, 0); 168*7bdf38e5Schristos assert_zu_eq(filled, batch, ""); 169*7bdf38e5Schristos release_batch(global_ptrs, batch, size); 170*7bdf38e5Schristos } 171*7bdf38e5Schristos size = tcache_maxclass + 1; 172*7bdf38e5Schristos for (size_t batch = 0; batch < 4; ++batch) { 173*7bdf38e5Schristos assert(batch < BATCH_MAX); 174*7bdf38e5Schristos size_t filled = batch_alloc(global_ptrs, batch, size, 0); 175*7bdf38e5Schristos assert_zu_eq(filled, batch, ""); 176*7bdf38e5Schristos release_batch(global_ptrs, batch, size); 177*7bdf38e5Schristos } 178*7bdf38e5Schristos } 179*7bdf38e5Schristos TEST_END 180*7bdf38e5Schristos 181*7bdf38e5Schristos int 182*7bdf38e5Schristos main(void) { 183*7bdf38e5Schristos return test( 184*7bdf38e5Schristos test_batch_alloc, 185*7bdf38e5Schristos test_batch_alloc_zero, 186*7bdf38e5Schristos test_batch_alloc_aligned, 187*7bdf38e5Schristos test_batch_alloc_manual_arena, 188*7bdf38e5Schristos test_batch_alloc_large); 189*7bdf38e5Schristos } 190