1 1.1 christos #include "test/jemalloc_test.h" 2 1.1 christos 3 1.1 christos #include "test/extent_hooks.h" 4 1.1 christos 5 1.1.1.2 christos #include "jemalloc/internal/arena_types.h" 6 1.1 christos 7 1.1 christos static void 8 1.1 christos test_extent_body(unsigned arena_ind) { 9 1.1.1.3 christos void *p; 10 1.1 christos size_t large0, large1, large2, sz; 11 1.1 christos size_t purge_mib[3]; 12 1.1 christos size_t purge_miblen; 13 1.1.1.3 christos int flags; 14 1.1.1.3 christos bool xallocx_success_a, xallocx_success_b, xallocx_success_c; 15 1.1 christos 16 1.1 christos flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; 17 1.1 christos 18 1.1 christos /* Get large size classes. */ 19 1.1 christos sz = sizeof(size_t); 20 1.1.1.3 christos expect_d_eq( 21 1.1.1.3 christos mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL, 0), 0, 22 1.1.1.3 christos "Unexpected arenas.lextent.0.size failure"); 23 1.1.1.3 christos expect_d_eq( 24 1.1.1.3 christos mallctl("arenas.lextent.1.size", (void *)&large1, &sz, NULL, 0), 0, 25 1.1.1.3 christos "Unexpected arenas.lextent.1.size failure"); 26 1.1.1.3 christos expect_d_eq( 27 1.1.1.3 christos mallctl("arenas.lextent.2.size", (void *)&large2, &sz, NULL, 0), 0, 28 1.1.1.3 christos "Unexpected arenas.lextent.2.size failure"); 29 1.1 christos 30 1.1 christos /* Test dalloc/decommit/purge cascade. */ 31 1.1.1.3 christos purge_miblen = sizeof(purge_mib) / sizeof(size_t); 32 1.1.1.2 christos expect_d_eq(mallctlnametomib("arena.0.purge", purge_mib, &purge_miblen), 33 1.1 christos 0, "Unexpected mallctlnametomib() failure"); 34 1.1 christos purge_mib[1] = (size_t)arena_ind; 35 1.1 christos called_alloc = false; 36 1.1 christos try_alloc = true; 37 1.1 christos try_dalloc = false; 38 1.1 christos try_decommit = false; 39 1.1 christos p = mallocx(large0 * 2, flags); 40 1.1.1.2 christos expect_ptr_not_null(p, "Unexpected mallocx() error"); 41 1.1.1.2 christos expect_true(called_alloc, "Expected alloc call"); 42 1.1 christos called_dalloc = false; 43 1.1 christos called_decommit = false; 44 1.1 christos did_purge_lazy = false; 45 1.1 christos did_purge_forced = false; 46 1.1 christos called_split = false; 47 1.1 christos xallocx_success_a = (xallocx(p, large0, 0, flags) == large0); 48 1.1.1.2 christos expect_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), 49 1.1 christos 0, "Unexpected arena.%u.purge error", arena_ind); 50 1.1 christos if (xallocx_success_a) { 51 1.1.1.2 christos expect_true(called_dalloc, "Expected dalloc call"); 52 1.1.1.2 christos expect_true(called_decommit, "Expected decommit call"); 53 1.1.1.3 christos expect_true( 54 1.1.1.3 christos did_purge_lazy || did_purge_forced, "Expected purge"); 55 1.1.1.2 christos expect_true(called_split, "Expected split call"); 56 1.1 christos } 57 1.1 christos dallocx(p, flags); 58 1.1 christos try_dalloc = true; 59 1.1 christos 60 1.1 christos /* Test decommit/commit and observe split/merge. */ 61 1.1 christos try_dalloc = false; 62 1.1 christos try_decommit = true; 63 1.1 christos p = mallocx(large0 * 2, flags); 64 1.1.1.2 christos expect_ptr_not_null(p, "Unexpected mallocx() error"); 65 1.1 christos did_decommit = false; 66 1.1 christos did_commit = false; 67 1.1 christos called_split = false; 68 1.1 christos did_split = false; 69 1.1 christos did_merge = false; 70 1.1 christos xallocx_success_b = (xallocx(p, large0, 0, flags) == large0); 71 1.1.1.2 christos expect_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), 72 1.1 christos 0, "Unexpected arena.%u.purge error", arena_ind); 73 1.1 christos if (xallocx_success_b) { 74 1.1.1.2 christos expect_true(did_split, "Expected split"); 75 1.1 christos } 76 1.1 christos xallocx_success_c = (xallocx(p, large0 * 2, 0, flags) == large0 * 2); 77 1.1 christos if (did_split) { 78 1.1.1.3 christos expect_b_eq( 79 1.1.1.3 christos did_decommit, did_commit, "Expected decommit/commit match"); 80 1.1 christos } 81 1.1 christos if (xallocx_success_b && xallocx_success_c) { 82 1.1.1.2 christos expect_true(did_merge, "Expected merge"); 83 1.1 christos } 84 1.1 christos dallocx(p, flags); 85 1.1 christos try_dalloc = true; 86 1.1 christos try_decommit = false; 87 1.1 christos 88 1.1 christos /* Make sure non-large allocation succeeds. */ 89 1.1 christos p = mallocx(42, flags); 90 1.1.1.2 christos expect_ptr_not_null(p, "Unexpected mallocx() error"); 91 1.1 christos dallocx(p, flags); 92 1.1 christos } 93 1.1 christos 94 1.1 christos static void 95 1.1 christos test_manual_hook_auto_arena(void) { 96 1.1.1.3 christos unsigned narenas; 97 1.1.1.3 christos size_t old_size, new_size, sz; 98 1.1.1.3 christos size_t hooks_mib[3]; 99 1.1.1.3 christos size_t hooks_miblen; 100 1.1 christos extent_hooks_t *new_hooks, *old_hooks; 101 1.1 christos 102 1.1 christos extent_hooks_prep(); 103 1.1 christos 104 1.1 christos sz = sizeof(unsigned); 105 1.1 christos /* Get number of auto arenas. */ 106 1.1.1.3 christos expect_d_eq(mallctl("opt.narenas", (void *)&narenas, &sz, NULL, 0), 0, 107 1.1.1.3 christos "Unexpected mallctl() failure"); 108 1.1 christos if (narenas == 1) { 109 1.1 christos return; 110 1.1 christos } 111 1.1 christos 112 1.1 christos /* Install custom extent hooks on arena 1 (might not be initialized). */ 113 1.1.1.3 christos hooks_miblen = sizeof(hooks_mib) / sizeof(size_t); 114 1.1.1.3 christos expect_d_eq( 115 1.1.1.3 christos mallctlnametomib("arena.0.extent_hooks", hooks_mib, &hooks_miblen), 116 1.1.1.3 christos 0, "Unexpected mallctlnametomib() failure"); 117 1.1 christos hooks_mib[1] = 1; 118 1.1 christos old_size = sizeof(extent_hooks_t *); 119 1.1 christos new_hooks = &hooks; 120 1.1 christos new_size = sizeof(extent_hooks_t *); 121 1.1.1.2 christos expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks, 122 1.1.1.3 christos &old_size, (void *)&new_hooks, new_size), 123 1.1.1.3 christos 0, "Unexpected extent_hooks error"); 124 1.1 christos static bool auto_arena_created = false; 125 1.1 christos if (old_hooks != &hooks) { 126 1.1.1.2 christos expect_b_eq(auto_arena_created, false, 127 1.1 christos "Expected auto arena 1 created only once."); 128 1.1 christos auto_arena_created = true; 129 1.1 christos } 130 1.1 christos } 131 1.1 christos 132 1.1 christos static void 133 1.1 christos test_manual_hook_body(void) { 134 1.1.1.3 christos unsigned arena_ind; 135 1.1.1.3 christos size_t old_size, new_size, sz; 136 1.1.1.3 christos size_t hooks_mib[3]; 137 1.1.1.3 christos size_t hooks_miblen; 138 1.1 christos extent_hooks_t *new_hooks, *old_hooks; 139 1.1 christos 140 1.1 christos extent_hooks_prep(); 141 1.1 christos 142 1.1 christos sz = sizeof(unsigned); 143 1.1.1.2 christos expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), 144 1.1 christos 0, "Unexpected mallctl() failure"); 145 1.1 christos 146 1.1 christos /* Install custom extent hooks. */ 147 1.1.1.3 christos hooks_miblen = sizeof(hooks_mib) / sizeof(size_t); 148 1.1.1.3 christos expect_d_eq( 149 1.1.1.3 christos mallctlnametomib("arena.0.extent_hooks", hooks_mib, &hooks_miblen), 150 1.1.1.3 christos 0, "Unexpected mallctlnametomib() failure"); 151 1.1 christos hooks_mib[1] = (size_t)arena_ind; 152 1.1 christos old_size = sizeof(extent_hooks_t *); 153 1.1 christos new_hooks = &hooks; 154 1.1 christos new_size = sizeof(extent_hooks_t *); 155 1.1.1.2 christos expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks, 156 1.1.1.3 christos &old_size, (void *)&new_hooks, new_size), 157 1.1.1.3 christos 0, "Unexpected extent_hooks error"); 158 1.1.1.2 christos expect_ptr_ne(old_hooks->alloc, extent_alloc_hook, 159 1.1 christos "Unexpected extent_hooks error"); 160 1.1.1.2 christos expect_ptr_ne(old_hooks->dalloc, extent_dalloc_hook, 161 1.1 christos "Unexpected extent_hooks error"); 162 1.1.1.2 christos expect_ptr_ne(old_hooks->commit, extent_commit_hook, 163 1.1 christos "Unexpected extent_hooks error"); 164 1.1.1.2 christos expect_ptr_ne(old_hooks->decommit, extent_decommit_hook, 165 1.1 christos "Unexpected extent_hooks error"); 166 1.1.1.2 christos expect_ptr_ne(old_hooks->purge_lazy, extent_purge_lazy_hook, 167 1.1 christos "Unexpected extent_hooks error"); 168 1.1.1.2 christos expect_ptr_ne(old_hooks->purge_forced, extent_purge_forced_hook, 169 1.1 christos "Unexpected extent_hooks error"); 170 1.1.1.2 christos expect_ptr_ne(old_hooks->split, extent_split_hook, 171 1.1 christos "Unexpected extent_hooks error"); 172 1.1.1.2 christos expect_ptr_ne(old_hooks->merge, extent_merge_hook, 173 1.1 christos "Unexpected extent_hooks error"); 174 1.1 christos 175 1.1.1.2 christos if (!is_background_thread_enabled()) { 176 1.1 christos test_extent_body(arena_ind); 177 1.1 christos } 178 1.1 christos 179 1.1 christos /* Restore extent hooks. */ 180 1.1.1.2 christos expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, NULL, NULL, 181 1.1.1.3 christos (void *)&old_hooks, new_size), 182 1.1.1.3 christos 0, "Unexpected extent_hooks error"); 183 1.1.1.2 christos expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks, 184 1.1.1.3 christos &old_size, NULL, 0), 185 1.1.1.3 christos 0, "Unexpected extent_hooks error"); 186 1.1.1.3 christos expect_ptr_eq( 187 1.1.1.3 christos old_hooks, default_hooks, "Unexpected extent_hooks error"); 188 1.1.1.2 christos expect_ptr_eq(old_hooks->alloc, default_hooks->alloc, 189 1.1 christos "Unexpected extent_hooks error"); 190 1.1.1.2 christos expect_ptr_eq(old_hooks->dalloc, default_hooks->dalloc, 191 1.1 christos "Unexpected extent_hooks error"); 192 1.1.1.2 christos expect_ptr_eq(old_hooks->commit, default_hooks->commit, 193 1.1 christos "Unexpected extent_hooks error"); 194 1.1.1.2 christos expect_ptr_eq(old_hooks->decommit, default_hooks->decommit, 195 1.1 christos "Unexpected extent_hooks error"); 196 1.1.1.2 christos expect_ptr_eq(old_hooks->purge_lazy, default_hooks->purge_lazy, 197 1.1 christos "Unexpected extent_hooks error"); 198 1.1.1.2 christos expect_ptr_eq(old_hooks->purge_forced, default_hooks->purge_forced, 199 1.1 christos "Unexpected extent_hooks error"); 200 1.1.1.2 christos expect_ptr_eq(old_hooks->split, default_hooks->split, 201 1.1 christos "Unexpected extent_hooks error"); 202 1.1.1.2 christos expect_ptr_eq(old_hooks->merge, default_hooks->merge, 203 1.1 christos "Unexpected extent_hooks error"); 204 1.1 christos } 205 1.1 christos 206 1.1 christos TEST_BEGIN(test_extent_manual_hook) { 207 1.1 christos test_manual_hook_auto_arena(); 208 1.1 christos test_manual_hook_body(); 209 1.1 christos 210 1.1 christos /* Test failure paths. */ 211 1.1 christos try_split = false; 212 1.1 christos test_manual_hook_body(); 213 1.1 christos try_merge = false; 214 1.1 christos test_manual_hook_body(); 215 1.1 christos try_purge_lazy = false; 216 1.1 christos try_purge_forced = false; 217 1.1 christos test_manual_hook_body(); 218 1.1 christos 219 1.1 christos try_split = try_merge = try_purge_lazy = try_purge_forced = true; 220 1.1 christos } 221 1.1 christos TEST_END 222 1.1 christos 223 1.1 christos TEST_BEGIN(test_extent_auto_hook) { 224 1.1.1.3 christos unsigned arena_ind; 225 1.1.1.3 christos size_t new_size, sz; 226 1.1 christos extent_hooks_t *new_hooks; 227 1.1 christos 228 1.1 christos extent_hooks_prep(); 229 1.1 christos 230 1.1 christos sz = sizeof(unsigned); 231 1.1 christos new_hooks = &hooks; 232 1.1 christos new_size = sizeof(extent_hooks_t *); 233 1.1.1.2 christos expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, 234 1.1.1.3 christos (void *)&new_hooks, new_size), 235 1.1.1.3 christos 0, "Unexpected mallctl() failure"); 236 1.1 christos 237 1.1.1.2 christos test_skip_if(is_background_thread_enabled()); 238 1.1 christos test_extent_body(arena_ind); 239 1.1 christos } 240 1.1 christos TEST_END 241 1.1 christos 242 1.1.1.2 christos static void 243 1.1.1.3 christos test_arenas_create_ext_base( 244 1.1.1.3 christos arena_config_t config, bool expect_hook_data, bool expect_hook_metadata) { 245 1.1.1.2 christos unsigned arena, arena1; 246 1.1.1.3 christos void *ptr; 247 1.1.1.3 christos size_t sz = sizeof(unsigned); 248 1.1.1.2 christos 249 1.1.1.2 christos extent_hooks_prep(); 250 1.1.1.2 christos 251 1.1.1.2 christos called_alloc = false; 252 1.1.1.3 christos expect_d_eq(mallctl("experimental.arenas_create_ext", (void *)&arena, 253 1.1.1.3 christos &sz, &config, sizeof(arena_config_t)), 254 1.1.1.3 christos 0, "Unexpected mallctl() failure"); 255 1.1.1.2 christos expect_b_eq(called_alloc, expect_hook_metadata, 256 1.1.1.2 christos "expected hook metadata alloc mismatch"); 257 1.1.1.2 christos 258 1.1.1.2 christos called_alloc = false; 259 1.1.1.2 christos ptr = mallocx(42, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE); 260 1.1.1.2 christos expect_b_eq(called_alloc, expect_hook_data, 261 1.1.1.2 christos "expected hook data alloc mismatch"); 262 1.1.1.2 christos 263 1.1.1.2 christos expect_ptr_not_null(ptr, "Unexpected mallocx() failure"); 264 1.1.1.2 christos expect_d_eq(mallctl("arenas.lookup", &arena1, &sz, &ptr, sizeof(ptr)), 265 1.1.1.2 christos 0, "Unexpected mallctl() failure"); 266 1.1.1.2 christos expect_u_eq(arena, arena1, "Unexpected arena index"); 267 1.1.1.2 christos dallocx(ptr, 0); 268 1.1.1.2 christos } 269 1.1.1.2 christos 270 1.1.1.2 christos TEST_BEGIN(test_arenas_create_ext_with_ehooks_no_metadata) { 271 1.1.1.2 christos arena_config_t config; 272 1.1.1.2 christos config.extent_hooks = &hooks; 273 1.1.1.2 christos config.metadata_use_hooks = false; 274 1.1.1.2 christos 275 1.1.1.2 christos test_arenas_create_ext_base(config, true, false); 276 1.1.1.2 christos } 277 1.1.1.2 christos TEST_END 278 1.1.1.2 christos 279 1.1.1.2 christos TEST_BEGIN(test_arenas_create_ext_with_ehooks_with_metadata) { 280 1.1.1.2 christos arena_config_t config; 281 1.1.1.2 christos config.extent_hooks = &hooks; 282 1.1.1.2 christos config.metadata_use_hooks = true; 283 1.1.1.2 christos 284 1.1.1.2 christos test_arenas_create_ext_base(config, true, true); 285 1.1.1.2 christos } 286 1.1.1.2 christos TEST_END 287 1.1.1.2 christos 288 1.1 christos int 289 1.1 christos main(void) { 290 1.1.1.3 christos return test(test_extent_manual_hook, test_extent_auto_hook, 291 1.1.1.2 christos test_arenas_create_ext_with_ehooks_no_metadata, 292 1.1.1.2 christos test_arenas_create_ext_with_ehooks_with_metadata); 293 1.1 christos } 294