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