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