1*8e33eff8Schristos #include "test/jemalloc_test.h" 2*8e33eff8Schristos 3*8e33eff8Schristos #include "test/extent_hooks.h" 4*8e33eff8Schristos 5*8e33eff8Schristos static extent_hooks_t hooks_null = { 6*8e33eff8Schristos extent_alloc_hook, 7*8e33eff8Schristos NULL, /* dalloc */ 8*8e33eff8Schristos NULL, /* destroy */ 9*8e33eff8Schristos NULL, /* commit */ 10*8e33eff8Schristos NULL, /* decommit */ 11*8e33eff8Schristos NULL, /* purge_lazy */ 12*8e33eff8Schristos NULL, /* purge_forced */ 13*8e33eff8Schristos NULL, /* split */ 14*8e33eff8Schristos NULL /* merge */ 15*8e33eff8Schristos }; 16*8e33eff8Schristos 17*8e33eff8Schristos static extent_hooks_t hooks_not_null = { 18*8e33eff8Schristos extent_alloc_hook, 19*8e33eff8Schristos extent_dalloc_hook, 20*8e33eff8Schristos extent_destroy_hook, 21*8e33eff8Schristos NULL, /* commit */ 22*8e33eff8Schristos extent_decommit_hook, 23*8e33eff8Schristos extent_purge_lazy_hook, 24*8e33eff8Schristos extent_purge_forced_hook, 25*8e33eff8Schristos NULL, /* split */ 26*8e33eff8Schristos NULL /* merge */ 27*8e33eff8Schristos }; 28*8e33eff8Schristos 29*8e33eff8Schristos TEST_BEGIN(test_base_hooks_default) { 30*8e33eff8Schristos base_t *base; 31*8e33eff8Schristos size_t allocated0, allocated1, resident, mapped, n_thp; 32*8e33eff8Schristos 33*8e33eff8Schristos tsdn_t *tsdn = tsd_tsdn(tsd_fetch()); 34*8e33eff8Schristos base = base_new(tsdn, 0, (extent_hooks_t *)&extent_hooks_default); 35*8e33eff8Schristos 36*8e33eff8Schristos if (config_stats) { 37*8e33eff8Schristos base_stats_get(tsdn, base, &allocated0, &resident, &mapped, 38*8e33eff8Schristos &n_thp); 39*8e33eff8Schristos assert_zu_ge(allocated0, sizeof(base_t), 40*8e33eff8Schristos "Base header should count as allocated"); 41*8e33eff8Schristos if (opt_metadata_thp == metadata_thp_always) { 42*8e33eff8Schristos assert_zu_gt(n_thp, 0, 43*8e33eff8Schristos "Base should have 1 THP at least."); 44*8e33eff8Schristos } 45*8e33eff8Schristos } 46*8e33eff8Schristos 47*8e33eff8Schristos assert_ptr_not_null(base_alloc(tsdn, base, 42, 1), 48*8e33eff8Schristos "Unexpected base_alloc() failure"); 49*8e33eff8Schristos 50*8e33eff8Schristos if (config_stats) { 51*8e33eff8Schristos base_stats_get(tsdn, base, &allocated1, &resident, &mapped, 52*8e33eff8Schristos &n_thp); 53*8e33eff8Schristos assert_zu_ge(allocated1 - allocated0, 42, 54*8e33eff8Schristos "At least 42 bytes were allocated by base_alloc()"); 55*8e33eff8Schristos } 56*8e33eff8Schristos 57*8e33eff8Schristos base_delete(tsdn, base); 58*8e33eff8Schristos } 59*8e33eff8Schristos TEST_END 60*8e33eff8Schristos 61*8e33eff8Schristos TEST_BEGIN(test_base_hooks_null) { 62*8e33eff8Schristos extent_hooks_t hooks_orig; 63*8e33eff8Schristos base_t *base; 64*8e33eff8Schristos size_t allocated0, allocated1, resident, mapped, n_thp; 65*8e33eff8Schristos 66*8e33eff8Schristos extent_hooks_prep(); 67*8e33eff8Schristos try_dalloc = false; 68*8e33eff8Schristos try_destroy = true; 69*8e33eff8Schristos try_decommit = false; 70*8e33eff8Schristos try_purge_lazy = false; 71*8e33eff8Schristos try_purge_forced = false; 72*8e33eff8Schristos memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t)); 73*8e33eff8Schristos memcpy(&hooks, &hooks_null, sizeof(extent_hooks_t)); 74*8e33eff8Schristos 75*8e33eff8Schristos tsdn_t *tsdn = tsd_tsdn(tsd_fetch()); 76*8e33eff8Schristos base = base_new(tsdn, 0, &hooks); 77*8e33eff8Schristos assert_ptr_not_null(base, "Unexpected base_new() failure"); 78*8e33eff8Schristos 79*8e33eff8Schristos if (config_stats) { 80*8e33eff8Schristos base_stats_get(tsdn, base, &allocated0, &resident, &mapped, 81*8e33eff8Schristos &n_thp); 82*8e33eff8Schristos assert_zu_ge(allocated0, sizeof(base_t), 83*8e33eff8Schristos "Base header should count as allocated"); 84*8e33eff8Schristos if (opt_metadata_thp == metadata_thp_always) { 85*8e33eff8Schristos assert_zu_gt(n_thp, 0, 86*8e33eff8Schristos "Base should have 1 THP at least."); 87*8e33eff8Schristos } 88*8e33eff8Schristos } 89*8e33eff8Schristos 90*8e33eff8Schristos assert_ptr_not_null(base_alloc(tsdn, base, 42, 1), 91*8e33eff8Schristos "Unexpected base_alloc() failure"); 92*8e33eff8Schristos 93*8e33eff8Schristos if (config_stats) { 94*8e33eff8Schristos base_stats_get(tsdn, base, &allocated1, &resident, &mapped, 95*8e33eff8Schristos &n_thp); 96*8e33eff8Schristos assert_zu_ge(allocated1 - allocated0, 42, 97*8e33eff8Schristos "At least 42 bytes were allocated by base_alloc()"); 98*8e33eff8Schristos } 99*8e33eff8Schristos 100*8e33eff8Schristos base_delete(tsdn, base); 101*8e33eff8Schristos 102*8e33eff8Schristos memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t)); 103*8e33eff8Schristos } 104*8e33eff8Schristos TEST_END 105*8e33eff8Schristos 106*8e33eff8Schristos TEST_BEGIN(test_base_hooks_not_null) { 107*8e33eff8Schristos extent_hooks_t hooks_orig; 108*8e33eff8Schristos base_t *base; 109*8e33eff8Schristos void *p, *q, *r, *r_exp; 110*8e33eff8Schristos 111*8e33eff8Schristos extent_hooks_prep(); 112*8e33eff8Schristos try_dalloc = false; 113*8e33eff8Schristos try_destroy = true; 114*8e33eff8Schristos try_decommit = false; 115*8e33eff8Schristos try_purge_lazy = false; 116*8e33eff8Schristos try_purge_forced = false; 117*8e33eff8Schristos memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t)); 118*8e33eff8Schristos memcpy(&hooks, &hooks_not_null, sizeof(extent_hooks_t)); 119*8e33eff8Schristos 120*8e33eff8Schristos tsdn_t *tsdn = tsd_tsdn(tsd_fetch()); 121*8e33eff8Schristos did_alloc = false; 122*8e33eff8Schristos base = base_new(tsdn, 0, &hooks); 123*8e33eff8Schristos assert_ptr_not_null(base, "Unexpected base_new() failure"); 124*8e33eff8Schristos assert_true(did_alloc, "Expected alloc"); 125*8e33eff8Schristos 126*8e33eff8Schristos /* 127*8e33eff8Schristos * Check for tight packing at specified alignment under simple 128*8e33eff8Schristos * conditions. 129*8e33eff8Schristos */ 130*8e33eff8Schristos { 131*8e33eff8Schristos const size_t alignments[] = { 132*8e33eff8Schristos 1, 133*8e33eff8Schristos QUANTUM, 134*8e33eff8Schristos QUANTUM << 1, 135*8e33eff8Schristos CACHELINE, 136*8e33eff8Schristos CACHELINE << 1, 137*8e33eff8Schristos }; 138*8e33eff8Schristos unsigned i; 139*8e33eff8Schristos 140*8e33eff8Schristos for (i = 0; i < sizeof(alignments) / sizeof(size_t); i++) { 141*8e33eff8Schristos size_t alignment = alignments[i]; 142*8e33eff8Schristos size_t align_ceil = ALIGNMENT_CEILING(alignment, 143*8e33eff8Schristos QUANTUM); 144*8e33eff8Schristos p = base_alloc(tsdn, base, 1, alignment); 145*8e33eff8Schristos assert_ptr_not_null(p, 146*8e33eff8Schristos "Unexpected base_alloc() failure"); 147*8e33eff8Schristos assert_ptr_eq(p, 148*8e33eff8Schristos (void *)(ALIGNMENT_CEILING((uintptr_t)p, 149*8e33eff8Schristos alignment)), "Expected quantum alignment"); 150*8e33eff8Schristos q = base_alloc(tsdn, base, alignment, alignment); 151*8e33eff8Schristos assert_ptr_not_null(q, 152*8e33eff8Schristos "Unexpected base_alloc() failure"); 153*8e33eff8Schristos assert_ptr_eq((void *)((uintptr_t)p + align_ceil), q, 154*8e33eff8Schristos "Minimal allocation should take up %zu bytes", 155*8e33eff8Schristos align_ceil); 156*8e33eff8Schristos r = base_alloc(tsdn, base, 1, alignment); 157*8e33eff8Schristos assert_ptr_not_null(r, 158*8e33eff8Schristos "Unexpected base_alloc() failure"); 159*8e33eff8Schristos assert_ptr_eq((void *)((uintptr_t)q + align_ceil), r, 160*8e33eff8Schristos "Minimal allocation should take up %zu bytes", 161*8e33eff8Schristos align_ceil); 162*8e33eff8Schristos } 163*8e33eff8Schristos } 164*8e33eff8Schristos 165*8e33eff8Schristos /* 166*8e33eff8Schristos * Allocate an object that cannot fit in the first block, then verify 167*8e33eff8Schristos * that the first block's remaining space is considered for subsequent 168*8e33eff8Schristos * allocation. 169*8e33eff8Schristos */ 170*8e33eff8Schristos assert_zu_ge(extent_bsize_get(&base->blocks->extent), QUANTUM, 171*8e33eff8Schristos "Remainder insufficient for test"); 172*8e33eff8Schristos /* Use up all but one quantum of block. */ 173*8e33eff8Schristos while (extent_bsize_get(&base->blocks->extent) > QUANTUM) { 174*8e33eff8Schristos p = base_alloc(tsdn, base, QUANTUM, QUANTUM); 175*8e33eff8Schristos assert_ptr_not_null(p, "Unexpected base_alloc() failure"); 176*8e33eff8Schristos } 177*8e33eff8Schristos r_exp = extent_addr_get(&base->blocks->extent); 178*8e33eff8Schristos assert_zu_eq(base->extent_sn_next, 1, "One extant block expected"); 179*8e33eff8Schristos q = base_alloc(tsdn, base, QUANTUM + 1, QUANTUM); 180*8e33eff8Schristos assert_ptr_not_null(q, "Unexpected base_alloc() failure"); 181*8e33eff8Schristos assert_ptr_ne(q, r_exp, "Expected allocation from new block"); 182*8e33eff8Schristos assert_zu_eq(base->extent_sn_next, 2, "Two extant blocks expected"); 183*8e33eff8Schristos r = base_alloc(tsdn, base, QUANTUM, QUANTUM); 184*8e33eff8Schristos assert_ptr_not_null(r, "Unexpected base_alloc() failure"); 185*8e33eff8Schristos assert_ptr_eq(r, r_exp, "Expected allocation from first block"); 186*8e33eff8Schristos assert_zu_eq(base->extent_sn_next, 2, "Two extant blocks expected"); 187*8e33eff8Schristos 188*8e33eff8Schristos /* 189*8e33eff8Schristos * Check for proper alignment support when normal blocks are too small. 190*8e33eff8Schristos */ 191*8e33eff8Schristos { 192*8e33eff8Schristos const size_t alignments[] = { 193*8e33eff8Schristos HUGEPAGE, 194*8e33eff8Schristos HUGEPAGE << 1 195*8e33eff8Schristos }; 196*8e33eff8Schristos unsigned i; 197*8e33eff8Schristos 198*8e33eff8Schristos for (i = 0; i < sizeof(alignments) / sizeof(size_t); i++) { 199*8e33eff8Schristos size_t alignment = alignments[i]; 200*8e33eff8Schristos p = base_alloc(tsdn, base, QUANTUM, alignment); 201*8e33eff8Schristos assert_ptr_not_null(p, 202*8e33eff8Schristos "Unexpected base_alloc() failure"); 203*8e33eff8Schristos assert_ptr_eq(p, 204*8e33eff8Schristos (void *)(ALIGNMENT_CEILING((uintptr_t)p, 205*8e33eff8Schristos alignment)), "Expected %zu-byte alignment", 206*8e33eff8Schristos alignment); 207*8e33eff8Schristos } 208*8e33eff8Schristos } 209*8e33eff8Schristos 210*8e33eff8Schristos called_dalloc = called_destroy = called_decommit = called_purge_lazy = 211*8e33eff8Schristos called_purge_forced = false; 212*8e33eff8Schristos base_delete(tsdn, base); 213*8e33eff8Schristos assert_true(called_dalloc, "Expected dalloc call"); 214*8e33eff8Schristos assert_true(!called_destroy, "Unexpected destroy call"); 215*8e33eff8Schristos assert_true(called_decommit, "Expected decommit call"); 216*8e33eff8Schristos assert_true(called_purge_lazy, "Expected purge_lazy call"); 217*8e33eff8Schristos assert_true(called_purge_forced, "Expected purge_forced call"); 218*8e33eff8Schristos 219*8e33eff8Schristos try_dalloc = true; 220*8e33eff8Schristos try_destroy = true; 221*8e33eff8Schristos try_decommit = true; 222*8e33eff8Schristos try_purge_lazy = true; 223*8e33eff8Schristos try_purge_forced = true; 224*8e33eff8Schristos memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t)); 225*8e33eff8Schristos } 226*8e33eff8Schristos TEST_END 227*8e33eff8Schristos 228*8e33eff8Schristos int 229*8e33eff8Schristos main(void) { 230*8e33eff8Schristos return test( 231*8e33eff8Schristos test_base_hooks_default, 232*8e33eff8Schristos test_base_hooks_null, 233*8e33eff8Schristos test_base_hooks_not_null); 234*8e33eff8Schristos } 235