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