diff options
Diffstat (limited to 'examples/redis-unstable/deps/jemalloc/test/unit/arena_reset.c')
| -rw-r--r-- | examples/redis-unstable/deps/jemalloc/test/unit/arena_reset.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/examples/redis-unstable/deps/jemalloc/test/unit/arena_reset.c b/examples/redis-unstable/deps/jemalloc/test/unit/arena_reset.c new file mode 100644 index 0000000..8ef0786 --- /dev/null +++ b/examples/redis-unstable/deps/jemalloc/test/unit/arena_reset.c | |||
| @@ -0,0 +1,361 @@ | |||
| 1 | #ifndef ARENA_RESET_PROF_C_ | ||
| 2 | #include "test/jemalloc_test.h" | ||
| 3 | #endif | ||
| 4 | |||
| 5 | #include "jemalloc/internal/extent_mmap.h" | ||
| 6 | #include "jemalloc/internal/rtree.h" | ||
| 7 | |||
| 8 | #include "test/extent_hooks.h" | ||
| 9 | |||
| 10 | static unsigned | ||
| 11 | get_nsizes_impl(const char *cmd) { | ||
| 12 | unsigned ret; | ||
| 13 | size_t z; | ||
| 14 | |||
| 15 | z = sizeof(unsigned); | ||
| 16 | expect_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, | ||
| 17 | "Unexpected mallctl(\"%s\", ...) failure", cmd); | ||
| 18 | |||
| 19 | return ret; | ||
| 20 | } | ||
| 21 | |||
| 22 | static unsigned | ||
| 23 | get_nsmall(void) { | ||
| 24 | return get_nsizes_impl("arenas.nbins"); | ||
| 25 | } | ||
| 26 | |||
| 27 | static unsigned | ||
| 28 | get_nlarge(void) { | ||
| 29 | return get_nsizes_impl("arenas.nlextents"); | ||
| 30 | } | ||
| 31 | |||
| 32 | static size_t | ||
| 33 | get_size_impl(const char *cmd, size_t ind) { | ||
| 34 | size_t ret; | ||
| 35 | size_t z; | ||
| 36 | size_t mib[4]; | ||
| 37 | size_t miblen = 4; | ||
| 38 | |||
| 39 | z = sizeof(size_t); | ||
| 40 | expect_d_eq(mallctlnametomib(cmd, mib, &miblen), | ||
| 41 | 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); | ||
| 42 | mib[2] = ind; | ||
| 43 | z = sizeof(size_t); | ||
| 44 | expect_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), | ||
| 45 | 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); | ||
| 46 | |||
| 47 | return ret; | ||
| 48 | } | ||
| 49 | |||
| 50 | static size_t | ||
| 51 | get_small_size(size_t ind) { | ||
| 52 | return get_size_impl("arenas.bin.0.size", ind); | ||
| 53 | } | ||
| 54 | |||
| 55 | static size_t | ||
| 56 | get_large_size(size_t ind) { | ||
| 57 | return get_size_impl("arenas.lextent.0.size", ind); | ||
| 58 | } | ||
| 59 | |||
| 60 | /* Like ivsalloc(), but safe to call on discarded allocations. */ | ||
| 61 | static size_t | ||
| 62 | vsalloc(tsdn_t *tsdn, const void *ptr) { | ||
| 63 | emap_full_alloc_ctx_t full_alloc_ctx; | ||
| 64 | bool missing = emap_full_alloc_ctx_try_lookup(tsdn, &arena_emap_global, | ||
| 65 | ptr, &full_alloc_ctx); | ||
| 66 | if (missing) { | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | if (full_alloc_ctx.edata == NULL) { | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | if (edata_state_get(full_alloc_ctx.edata) != extent_state_active) { | ||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | if (full_alloc_ctx.szind == SC_NSIZES) { | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | return sz_index2size(full_alloc_ctx.szind); | ||
| 82 | } | ||
| 83 | |||
| 84 | static unsigned | ||
| 85 | do_arena_create(extent_hooks_t *h) { | ||
| 86 | unsigned arena_ind; | ||
| 87 | size_t sz = sizeof(unsigned); | ||
| 88 | expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, | ||
| 89 | (void *)(h != NULL ? &h : NULL), (h != NULL ? sizeof(h) : 0)), 0, | ||
| 90 | "Unexpected mallctl() failure"); | ||
| 91 | return arena_ind; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void | ||
| 95 | do_arena_reset_pre(unsigned arena_ind, void ***ptrs, unsigned *nptrs) { | ||
| 96 | #define NLARGE 32 | ||
| 97 | unsigned nsmall, nlarge, i; | ||
| 98 | size_t sz; | ||
| 99 | int flags; | ||
| 100 | tsdn_t *tsdn; | ||
| 101 | |||
| 102 | flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; | ||
| 103 | |||
| 104 | nsmall = get_nsmall(); | ||
| 105 | nlarge = get_nlarge() > NLARGE ? NLARGE : get_nlarge(); | ||
| 106 | *nptrs = nsmall + nlarge; | ||
| 107 | *ptrs = (void **)malloc(*nptrs * sizeof(void *)); | ||
| 108 | expect_ptr_not_null(*ptrs, "Unexpected malloc() failure"); | ||
| 109 | |||
| 110 | /* Allocate objects with a wide range of sizes. */ | ||
| 111 | for (i = 0; i < nsmall; i++) { | ||
| 112 | sz = get_small_size(i); | ||
| 113 | (*ptrs)[i] = mallocx(sz, flags); | ||
| 114 | expect_ptr_not_null((*ptrs)[i], | ||
| 115 | "Unexpected mallocx(%zu, %#x) failure", sz, flags); | ||
| 116 | } | ||
| 117 | for (i = 0; i < nlarge; i++) { | ||
| 118 | sz = get_large_size(i); | ||
| 119 | (*ptrs)[nsmall + i] = mallocx(sz, flags); | ||
| 120 | expect_ptr_not_null((*ptrs)[i], | ||
| 121 | "Unexpected mallocx(%zu, %#x) failure", sz, flags); | ||
| 122 | } | ||
| 123 | |||
| 124 | tsdn = tsdn_fetch(); | ||
| 125 | |||
| 126 | /* Verify allocations. */ | ||
| 127 | for (i = 0; i < *nptrs; i++) { | ||
| 128 | expect_zu_gt(ivsalloc(tsdn, (*ptrs)[i]), 0, | ||
| 129 | "Allocation should have queryable size"); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | static void | ||
| 134 | do_arena_reset_post(void **ptrs, unsigned nptrs, unsigned arena_ind) { | ||
| 135 | tsdn_t *tsdn; | ||
| 136 | unsigned i; | ||
| 137 | |||
| 138 | tsdn = tsdn_fetch(); | ||
| 139 | |||
| 140 | if (have_background_thread) { | ||
| 141 | malloc_mutex_lock(tsdn, | ||
| 142 | &background_thread_info_get(arena_ind)->mtx); | ||
| 143 | } | ||
| 144 | /* Verify allocations no longer exist. */ | ||
| 145 | for (i = 0; i < nptrs; i++) { | ||
| 146 | expect_zu_eq(vsalloc(tsdn, ptrs[i]), 0, | ||
| 147 | "Allocation should no longer exist"); | ||
| 148 | } | ||
| 149 | if (have_background_thread) { | ||
| 150 | malloc_mutex_unlock(tsdn, | ||
| 151 | &background_thread_info_get(arena_ind)->mtx); | ||
| 152 | } | ||
| 153 | |||
| 154 | free(ptrs); | ||
| 155 | } | ||
| 156 | |||
| 157 | static void | ||
| 158 | do_arena_reset_destroy(const char *name, unsigned arena_ind) { | ||
| 159 | size_t mib[3]; | ||
| 160 | size_t miblen; | ||
| 161 | |||
| 162 | miblen = sizeof(mib)/sizeof(size_t); | ||
| 163 | expect_d_eq(mallctlnametomib(name, mib, &miblen), 0, | ||
| 164 | "Unexpected mallctlnametomib() failure"); | ||
| 165 | mib[1] = (size_t)arena_ind; | ||
| 166 | expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, | ||
| 167 | "Unexpected mallctlbymib() failure"); | ||
| 168 | } | ||
| 169 | |||
| 170 | static void | ||
| 171 | do_arena_reset(unsigned arena_ind) { | ||
| 172 | do_arena_reset_destroy("arena.0.reset", arena_ind); | ||
| 173 | } | ||
| 174 | |||
| 175 | static void | ||
| 176 | do_arena_destroy(unsigned arena_ind) { | ||
| 177 | do_arena_reset_destroy("arena.0.destroy", arena_ind); | ||
| 178 | } | ||
| 179 | |||
| 180 | TEST_BEGIN(test_arena_reset) { | ||
| 181 | unsigned arena_ind; | ||
| 182 | void **ptrs; | ||
| 183 | unsigned nptrs; | ||
| 184 | |||
| 185 | arena_ind = do_arena_create(NULL); | ||
| 186 | do_arena_reset_pre(arena_ind, &ptrs, &nptrs); | ||
| 187 | do_arena_reset(arena_ind); | ||
| 188 | do_arena_reset_post(ptrs, nptrs, arena_ind); | ||
| 189 | } | ||
| 190 | TEST_END | ||
| 191 | |||
| 192 | static bool | ||
| 193 | arena_i_initialized(unsigned arena_ind, bool refresh) { | ||
| 194 | bool initialized; | ||
| 195 | size_t mib[3]; | ||
| 196 | size_t miblen, sz; | ||
| 197 | |||
| 198 | if (refresh) { | ||
| 199 | uint64_t epoch = 1; | ||
| 200 | expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, | ||
| 201 | sizeof(epoch)), 0, "Unexpected mallctl() failure"); | ||
| 202 | } | ||
| 203 | |||
| 204 | miblen = sizeof(mib)/sizeof(size_t); | ||
| 205 | expect_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0, | ||
| 206 | "Unexpected mallctlnametomib() failure"); | ||
| 207 | mib[1] = (size_t)arena_ind; | ||
| 208 | sz = sizeof(initialized); | ||
| 209 | expect_d_eq(mallctlbymib(mib, miblen, (void *)&initialized, &sz, NULL, | ||
| 210 | 0), 0, "Unexpected mallctlbymib() failure"); | ||
| 211 | |||
| 212 | return initialized; | ||
| 213 | } | ||
| 214 | |||
| 215 | TEST_BEGIN(test_arena_destroy_initial) { | ||
| 216 | expect_false(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), | ||
| 217 | "Destroyed arena stats should not be initialized"); | ||
| 218 | } | ||
| 219 | TEST_END | ||
| 220 | |||
| 221 | TEST_BEGIN(test_arena_destroy_hooks_default) { | ||
| 222 | unsigned arena_ind, arena_ind_another, arena_ind_prev; | ||
| 223 | void **ptrs; | ||
| 224 | unsigned nptrs; | ||
| 225 | |||
| 226 | arena_ind = do_arena_create(NULL); | ||
| 227 | do_arena_reset_pre(arena_ind, &ptrs, &nptrs); | ||
| 228 | |||
| 229 | expect_false(arena_i_initialized(arena_ind, false), | ||
| 230 | "Arena stats should not be initialized"); | ||
| 231 | expect_true(arena_i_initialized(arena_ind, true), | ||
| 232 | "Arena stats should be initialized"); | ||
| 233 | |||
| 234 | /* | ||
| 235 | * Create another arena before destroying one, to better verify arena | ||
| 236 | * index reuse. | ||
| 237 | */ | ||
| 238 | arena_ind_another = do_arena_create(NULL); | ||
| 239 | |||
| 240 | do_arena_destroy(arena_ind); | ||
| 241 | |||
| 242 | expect_false(arena_i_initialized(arena_ind, true), | ||
| 243 | "Arena stats should not be initialized"); | ||
| 244 | expect_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), | ||
| 245 | "Destroyed arena stats should be initialized"); | ||
| 246 | |||
| 247 | do_arena_reset_post(ptrs, nptrs, arena_ind); | ||
| 248 | |||
| 249 | arena_ind_prev = arena_ind; | ||
| 250 | arena_ind = do_arena_create(NULL); | ||
| 251 | do_arena_reset_pre(arena_ind, &ptrs, &nptrs); | ||
| 252 | expect_u_eq(arena_ind, arena_ind_prev, | ||
| 253 | "Arena index should have been recycled"); | ||
| 254 | do_arena_destroy(arena_ind); | ||
| 255 | do_arena_reset_post(ptrs, nptrs, arena_ind); | ||
| 256 | |||
| 257 | do_arena_destroy(arena_ind_another); | ||
| 258 | |||
| 259 | /* Try arena.create with custom hooks. */ | ||
| 260 | size_t sz = sizeof(extent_hooks_t *); | ||
| 261 | extent_hooks_t *a0_default_hooks; | ||
| 262 | expect_d_eq(mallctl("arena.0.extent_hooks", (void *)&a0_default_hooks, | ||
| 263 | &sz, NULL, 0), 0, "Unexpected mallctlnametomib() failure"); | ||
| 264 | |||
| 265 | /* Default impl; but wrapped as "customized". */ | ||
| 266 | extent_hooks_t new_hooks = *a0_default_hooks; | ||
| 267 | extent_hooks_t *hook = &new_hooks; | ||
| 268 | sz = sizeof(unsigned); | ||
| 269 | expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, | ||
| 270 | (void *)&hook, sizeof(void *)), 0, | ||
| 271 | "Unexpected mallctl() failure"); | ||
| 272 | do_arena_destroy(arena_ind); | ||
| 273 | } | ||
| 274 | TEST_END | ||
| 275 | |||
| 276 | /* | ||
| 277 | * Actually unmap extents, regardless of opt_retain, so that attempts to access | ||
| 278 | * a destroyed arena's memory will segfault. | ||
| 279 | */ | ||
| 280 | static bool | ||
| 281 | extent_dalloc_unmap(extent_hooks_t *extent_hooks, void *addr, size_t size, | ||
| 282 | bool committed, unsigned arena_ind) { | ||
| 283 | TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " | ||
| 284 | "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? | ||
| 285 | "true" : "false", arena_ind); | ||
| 286 | expect_ptr_eq(extent_hooks, &hooks, | ||
| 287 | "extent_hooks should be same as pointer used to set hooks"); | ||
| 288 | expect_ptr_eq(extent_hooks->dalloc, extent_dalloc_unmap, | ||
| 289 | "Wrong hook function"); | ||
| 290 | called_dalloc = true; | ||
| 291 | if (!try_dalloc) { | ||
| 292 | return true; | ||
| 293 | } | ||
| 294 | did_dalloc = true; | ||
| 295 | if (!maps_coalesce && opt_retain) { | ||
| 296 | return true; | ||
| 297 | } | ||
| 298 | pages_unmap(addr, size); | ||
| 299 | return false; | ||
| 300 | } | ||
| 301 | |||
| 302 | static extent_hooks_t hooks_orig; | ||
| 303 | |||
| 304 | static extent_hooks_t hooks_unmap = { | ||
| 305 | extent_alloc_hook, | ||
| 306 | extent_dalloc_unmap, /* dalloc */ | ||
| 307 | extent_destroy_hook, | ||
| 308 | extent_commit_hook, | ||
| 309 | extent_decommit_hook, | ||
| 310 | extent_purge_lazy_hook, | ||
| 311 | extent_purge_forced_hook, | ||
| 312 | extent_split_hook, | ||
| 313 | extent_merge_hook | ||
| 314 | }; | ||
| 315 | |||
| 316 | TEST_BEGIN(test_arena_destroy_hooks_unmap) { | ||
| 317 | unsigned arena_ind; | ||
| 318 | void **ptrs; | ||
| 319 | unsigned nptrs; | ||
| 320 | |||
| 321 | extent_hooks_prep(); | ||
| 322 | if (maps_coalesce) { | ||
| 323 | try_decommit = false; | ||
| 324 | } | ||
| 325 | memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t)); | ||
| 326 | memcpy(&hooks, &hooks_unmap, sizeof(extent_hooks_t)); | ||
| 327 | |||
| 328 | did_alloc = false; | ||
| 329 | arena_ind = do_arena_create(&hooks); | ||
| 330 | do_arena_reset_pre(arena_ind, &ptrs, &nptrs); | ||
| 331 | |||
| 332 | expect_true(did_alloc, "Expected alloc"); | ||
| 333 | |||
| 334 | expect_false(arena_i_initialized(arena_ind, false), | ||
| 335 | "Arena stats should not be initialized"); | ||
| 336 | expect_true(arena_i_initialized(arena_ind, true), | ||
| 337 | "Arena stats should be initialized"); | ||
| 338 | |||
| 339 | did_dalloc = false; | ||
| 340 | do_arena_destroy(arena_ind); | ||
| 341 | expect_true(did_dalloc, "Expected dalloc"); | ||
| 342 | |||
| 343 | expect_false(arena_i_initialized(arena_ind, true), | ||
| 344 | "Arena stats should not be initialized"); | ||
| 345 | expect_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), | ||
| 346 | "Destroyed arena stats should be initialized"); | ||
| 347 | |||
| 348 | do_arena_reset_post(ptrs, nptrs, arena_ind); | ||
| 349 | |||
| 350 | memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t)); | ||
| 351 | } | ||
| 352 | TEST_END | ||
| 353 | |||
| 354 | int | ||
| 355 | main(void) { | ||
| 356 | return test( | ||
| 357 | test_arena_reset, | ||
| 358 | test_arena_destroy_initial, | ||
| 359 | test_arena_destroy_hooks_default, | ||
| 360 | test_arena_destroy_hooks_unmap); | ||
| 361 | } | ||
