123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- #ifndef ARENA_RESET_PROF_C_
- #include "test/jemalloc_test.h"
- #endif
- #include "jemalloc/internal/extent_mmap.h"
- #include "jemalloc/internal/rtree.h"
- #include "test/extent_hooks.h"
- static unsigned
- get_nsizes_impl(const char *cmd) {
- unsigned ret;
- size_t z;
- z = sizeof(unsigned);
- expect_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
- "Unexpected mallctl(\"%s\", ...) failure", cmd);
- return ret;
- }
- static unsigned
- get_nsmall(void) {
- return get_nsizes_impl("arenas.nbins");
- }
- static unsigned
- get_nlarge(void) {
- return get_nsizes_impl("arenas.nlextents");
- }
- static size_t
- get_size_impl(const char *cmd, size_t ind) {
- size_t ret;
- size_t z;
- size_t mib[4];
- size_t miblen = 4;
- z = sizeof(size_t);
- expect_d_eq(mallctlnametomib(cmd, mib, &miblen),
- 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
- mib[2] = ind;
- z = sizeof(size_t);
- expect_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
- 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
- return ret;
- }
- static size_t
- get_small_size(size_t ind) {
- return get_size_impl("arenas.bin.0.size", ind);
- }
- static size_t
- get_large_size(size_t ind) {
- return get_size_impl("arenas.lextent.0.size", ind);
- }
- /* Like ivsalloc(), but safe to call on discarded allocations. */
- static size_t
- vsalloc(tsdn_t *tsdn, const void *ptr) {
- emap_full_alloc_ctx_t full_alloc_ctx;
- bool missing = emap_full_alloc_ctx_try_lookup(tsdn, &arena_emap_global,
- ptr, &full_alloc_ctx);
- if (missing) {
- return 0;
- }
- if (full_alloc_ctx.edata == NULL) {
- return 0;
- }
- if (edata_state_get(full_alloc_ctx.edata) != extent_state_active) {
- return 0;
- }
- if (full_alloc_ctx.szind == SC_NSIZES) {
- return 0;
- }
- return sz_index2size(full_alloc_ctx.szind);
- }
- static unsigned
- do_arena_create(extent_hooks_t *h) {
- unsigned arena_ind;
- size_t sz = sizeof(unsigned);
- expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz,
- (void *)(h != NULL ? &h : NULL), (h != NULL ? sizeof(h) : 0)), 0,
- "Unexpected mallctl() failure");
- return arena_ind;
- }
- static void
- do_arena_reset_pre(unsigned arena_ind, void ***ptrs, unsigned *nptrs) {
- #define NLARGE 32
- unsigned nsmall, nlarge, i;
- size_t sz;
- int flags;
- tsdn_t *tsdn;
- flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE;
- nsmall = get_nsmall();
- nlarge = get_nlarge() > NLARGE ? NLARGE : get_nlarge();
- *nptrs = nsmall + nlarge;
- *ptrs = (void **)malloc(*nptrs * sizeof(void *));
- expect_ptr_not_null(*ptrs, "Unexpected malloc() failure");
- /* Allocate objects with a wide range of sizes. */
- for (i = 0; i < nsmall; i++) {
- sz = get_small_size(i);
- (*ptrs)[i] = mallocx(sz, flags);
- expect_ptr_not_null((*ptrs)[i],
- "Unexpected mallocx(%zu, %#x) failure", sz, flags);
- }
- for (i = 0; i < nlarge; i++) {
- sz = get_large_size(i);
- (*ptrs)[nsmall + i] = mallocx(sz, flags);
- expect_ptr_not_null((*ptrs)[i],
- "Unexpected mallocx(%zu, %#x) failure", sz, flags);
- }
- tsdn = tsdn_fetch();
- /* Verify allocations. */
- for (i = 0; i < *nptrs; i++) {
- expect_zu_gt(ivsalloc(tsdn, (*ptrs)[i]), 0,
- "Allocation should have queryable size");
- }
- }
- static void
- do_arena_reset_post(void **ptrs, unsigned nptrs, unsigned arena_ind) {
- tsdn_t *tsdn;
- unsigned i;
- tsdn = tsdn_fetch();
- if (have_background_thread) {
- malloc_mutex_lock(tsdn,
- &background_thread_info_get(arena_ind)->mtx);
- }
- /* Verify allocations no longer exist. */
- for (i = 0; i < nptrs; i++) {
- expect_zu_eq(vsalloc(tsdn, ptrs[i]), 0,
- "Allocation should no longer exist");
- }
- if (have_background_thread) {
- malloc_mutex_unlock(tsdn,
- &background_thread_info_get(arena_ind)->mtx);
- }
- free(ptrs);
- }
- static void
- do_arena_reset_destroy(const char *name, unsigned arena_ind) {
- size_t mib[3];
- size_t miblen;
- miblen = sizeof(mib)/sizeof(size_t);
- expect_d_eq(mallctlnametomib(name, mib, &miblen), 0,
- "Unexpected mallctlnametomib() failure");
- mib[1] = (size_t)arena_ind;
- expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
- "Unexpected mallctlbymib() failure");
- }
- static void
- do_arena_reset(unsigned arena_ind) {
- do_arena_reset_destroy("arena.0.reset", arena_ind);
- }
- static void
- do_arena_destroy(unsigned arena_ind) {
- do_arena_reset_destroy("arena.0.destroy", arena_ind);
- }
- TEST_BEGIN(test_arena_reset) {
- unsigned arena_ind;
- void **ptrs;
- unsigned nptrs;
- arena_ind = do_arena_create(NULL);
- do_arena_reset_pre(arena_ind, &ptrs, &nptrs);
- do_arena_reset(arena_ind);
- do_arena_reset_post(ptrs, nptrs, arena_ind);
- }
- TEST_END
- static bool
- arena_i_initialized(unsigned arena_ind, bool refresh) {
- bool initialized;
- size_t mib[3];
- size_t miblen, sz;
- if (refresh) {
- uint64_t epoch = 1;
- expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
- sizeof(epoch)), 0, "Unexpected mallctl() failure");
- }
- miblen = sizeof(mib)/sizeof(size_t);
- expect_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0,
- "Unexpected mallctlnametomib() failure");
- mib[1] = (size_t)arena_ind;
- sz = sizeof(initialized);
- expect_d_eq(mallctlbymib(mib, miblen, (void *)&initialized, &sz, NULL,
- 0), 0, "Unexpected mallctlbymib() failure");
- return initialized;
- }
- TEST_BEGIN(test_arena_destroy_initial) {
- expect_false(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false),
- "Destroyed arena stats should not be initialized");
- }
- TEST_END
- TEST_BEGIN(test_arena_destroy_hooks_default) {
- unsigned arena_ind, arena_ind_another, arena_ind_prev;
- void **ptrs;
- unsigned nptrs;
- arena_ind = do_arena_create(NULL);
- do_arena_reset_pre(arena_ind, &ptrs, &nptrs);
- expect_false(arena_i_initialized(arena_ind, false),
- "Arena stats should not be initialized");
- expect_true(arena_i_initialized(arena_ind, true),
- "Arena stats should be initialized");
- /*
- * Create another arena before destroying one, to better verify arena
- * index reuse.
- */
- arena_ind_another = do_arena_create(NULL);
- do_arena_destroy(arena_ind);
- expect_false(arena_i_initialized(arena_ind, true),
- "Arena stats should not be initialized");
- expect_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false),
- "Destroyed arena stats should be initialized");
- do_arena_reset_post(ptrs, nptrs, arena_ind);
- arena_ind_prev = arena_ind;
- arena_ind = do_arena_create(NULL);
- do_arena_reset_pre(arena_ind, &ptrs, &nptrs);
- expect_u_eq(arena_ind, arena_ind_prev,
- "Arena index should have been recycled");
- do_arena_destroy(arena_ind);
- do_arena_reset_post(ptrs, nptrs, arena_ind);
- do_arena_destroy(arena_ind_another);
- /* Try arena.create with custom hooks. */
- size_t sz = sizeof(extent_hooks_t *);
- extent_hooks_t *a0_default_hooks;
- expect_d_eq(mallctl("arena.0.extent_hooks", (void *)&a0_default_hooks,
- &sz, NULL, 0), 0, "Unexpected mallctlnametomib() failure");
- /* Default impl; but wrapped as "customized". */
- extent_hooks_t new_hooks = *a0_default_hooks;
- extent_hooks_t *hook = &new_hooks;
- sz = sizeof(unsigned);
- expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz,
- (void *)&hook, sizeof(void *)), 0,
- "Unexpected mallctl() failure");
- do_arena_destroy(arena_ind);
- }
- TEST_END
- /*
- * Actually unmap extents, regardless of opt_retain, so that attempts to access
- * a destroyed arena's memory will segfault.
- */
- static bool
- extent_dalloc_unmap(extent_hooks_t *extent_hooks, void *addr, size_t size,
- bool committed, unsigned arena_ind) {
- TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, "
- "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ?
- "true" : "false", arena_ind);
- expect_ptr_eq(extent_hooks, &hooks,
- "extent_hooks should be same as pointer used to set hooks");
- expect_ptr_eq(extent_hooks->dalloc, extent_dalloc_unmap,
- "Wrong hook function");
- called_dalloc = true;
- if (!try_dalloc) {
- return true;
- }
- did_dalloc = true;
- if (!maps_coalesce && opt_retain) {
- return true;
- }
- pages_unmap(addr, size);
- return false;
- }
- static extent_hooks_t hooks_orig;
- static extent_hooks_t hooks_unmap = {
- extent_alloc_hook,
- extent_dalloc_unmap, /* dalloc */
- extent_destroy_hook,
- extent_commit_hook,
- extent_decommit_hook,
- extent_purge_lazy_hook,
- extent_purge_forced_hook,
- extent_split_hook,
- extent_merge_hook
- };
- TEST_BEGIN(test_arena_destroy_hooks_unmap) {
- unsigned arena_ind;
- void **ptrs;
- unsigned nptrs;
- extent_hooks_prep();
- if (maps_coalesce) {
- try_decommit = false;
- }
- memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t));
- memcpy(&hooks, &hooks_unmap, sizeof(extent_hooks_t));
- did_alloc = false;
- arena_ind = do_arena_create(&hooks);
- do_arena_reset_pre(arena_ind, &ptrs, &nptrs);
- expect_true(did_alloc, "Expected alloc");
- expect_false(arena_i_initialized(arena_ind, false),
- "Arena stats should not be initialized");
- expect_true(arena_i_initialized(arena_ind, true),
- "Arena stats should be initialized");
- did_dalloc = false;
- do_arena_destroy(arena_ind);
- expect_true(did_dalloc, "Expected dalloc");
- expect_false(arena_i_initialized(arena_ind, true),
- "Arena stats should not be initialized");
- expect_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false),
- "Destroyed arena stats should be initialized");
- do_arena_reset_post(ptrs, nptrs, arena_ind);
- memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t));
- }
- TEST_END
- int
- main(void) {
- return test(
- test_arena_reset,
- test_arena_destroy_initial,
- test_arena_destroy_hooks_default,
- test_arena_destroy_hooks_unmap);
- }
|