From e09eac1d4e9df2e889417e1cd3e56b451b959ba8 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Thu, 6 May 2021 13:47:01 -0700 Subject: [PATCH] Remove hpa_central. This is now dead code. --- Makefile.in | 2 - include/jemalloc/internal/hpa_central.h | 47 -- .../projects/vc2015/jemalloc/jemalloc.vcxproj | 1 - .../vc2015/jemalloc/jemalloc.vcxproj.filters | 3 - .../projects/vc2017/jemalloc/jemalloc.vcxproj | 1 - .../vc2017/jemalloc/jemalloc.vcxproj.filters | 3 - src/hpa_central.c | 192 -------- test/unit/hpa_central.c | 450 ------------------ 8 files changed, 699 deletions(-) delete mode 100644 include/jemalloc/internal/hpa_central.h delete mode 100644 src/hpa_central.c delete mode 100644 test/unit/hpa_central.c diff --git a/Makefile.in b/Makefile.in index abdf8004..286f7ea9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -121,7 +121,6 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/fxp.c \ $(srcroot)src/hook.c \ $(srcroot)src/hpa.c \ - $(srcroot)src/hpa_central.c \ $(srcroot)src/hpa_hooks.c \ $(srcroot)src/hpdata.c \ $(srcroot)src/inspect.c \ @@ -223,7 +222,6 @@ TESTS_UNIT := \ $(srcroot)test/unit/hook.c \ $(srcroot)test/unit/hpa.c \ $(srcroot)test/unit/hpa_background_thread.c \ - $(srcroot)test/unit/hpa_central.c \ $(srcroot)test/unit/hpdata.c \ $(srcroot)test/unit/huge.c \ $(srcroot)test/unit/inspect.c \ diff --git a/include/jemalloc/internal/hpa_central.h b/include/jemalloc/internal/hpa_central.h deleted file mode 100644 index 8659f712..00000000 --- a/include/jemalloc/internal/hpa_central.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_HPA_CENTRAL_H -#define JEMALLOC_INTERNAL_HPA_CENTRAL_H - -#include "jemalloc/internal/base.h" -#include "jemalloc/internal/emap.h" - -typedef struct hpa_central_s hpa_central_t; -struct hpa_central_s { - /* The emap we use for metadata operations. */ - emap_t *emap; - - edata_cache_small_t ecs; - eset_t eset; - - size_t sn_next; -}; - -void hpa_central_init(hpa_central_t *central, edata_cache_t *edata_cache, - emap_t *emap); -/* - * Tries to satisfy the given allocation request with an extent already given to - * central. - */ -edata_t *hpa_central_alloc_reuse(tsdn_t *tsdn, hpa_central_t *central, - size_t size_min, size_t size_goal); -/* - * Adds the given edata to the central allocator as a new allocation. The - * intent is that after a reuse attempt fails, the caller can allocate a new - * extent using whatever growth policy it prefers and allocate from that, giving - * the excess to the hpa_central_t (this is analogous to the - * extent_grow_retained functionality; we can allocate address space in - * exponentially growing chunks). - * - * The edata_t should come from the same base that this hpa was initialized - * with. Only complete extents should be added (i.e. those for which the head - * bit is true, and for which their successor is either not owned by jemalloc - * or also has a head bit of true). It should be active, large enough to - * satisfy the requested allocation, and not already in the emap. - * - * If this returns true, then we did not accept the extent, and took no action. - * Otherwise, modifies *edata to satisfy the allocation. - */ -bool hpa_central_alloc_grow(tsdn_t *tsdn, hpa_central_t *central, - size_t size, edata_t *to_add); -void hpa_central_dalloc(tsdn_t *tsdn, hpa_central_t *central, edata_t *edata); - -#endif /* JEMALLOC_INTERNAL_HPA_CENTRAL_H */ diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index f6fae7f2..597b247b 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -61,7 +61,6 @@ - diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index 800861d3..d063a019 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -67,9 +67,6 @@ Source Files - - Source Files - Source Files diff --git a/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj index 3d3e7174..46633e82 100644 --- a/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj @@ -61,7 +61,6 @@ - diff --git a/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj.filters index 800861d3..d063a019 100644 --- a/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj.filters @@ -67,9 +67,6 @@ Source Files - - Source Files - Source Files diff --git a/src/hpa_central.c b/src/hpa_central.c deleted file mode 100644 index 9e00dd64..00000000 --- a/src/hpa_central.c +++ /dev/null @@ -1,192 +0,0 @@ -#include "jemalloc/internal/jemalloc_preamble.h" -#include "jemalloc/internal/jemalloc_internal_includes.h" - -#include "jemalloc/internal/hpa_central.h" - -void -hpa_central_init(hpa_central_t *central, edata_cache_t *edata_cache, - emap_t *emap) { - central->emap = emap; - edata_cache_small_init(¢ral->ecs, edata_cache); - eset_init(¢ral->eset, extent_state_dirty); - central->sn_next = 0; -} - -/* - * Returns the trail, or NULL in case of failure (which can only occur in case - * of an emap operation failure; i.e. OOM). - */ -static edata_t * -hpa_central_split(tsdn_t *tsdn, hpa_central_t *central, edata_t *edata, - size_t size) { - edata_t *trail = edata_cache_small_get(tsdn, ¢ral->ecs); - if (trail == NULL) { - return NULL; - } - size_t cursize = edata_size_get(edata); - edata_init(trail, edata_arena_ind_get(edata), - (void *)((uintptr_t)edata_base_get(edata) + size), cursize - size, - /* slab */ false, SC_NSIZES, edata_sn_get(edata), - edata_state_get(edata), edata_zeroed_get(edata), - edata_committed_get(edata), EXTENT_PAI_HPA, EXTENT_NOT_HEAD); - - emap_prepare_t prepare; - bool err = emap_split_prepare(tsdn, central->emap, &prepare, edata, - size, trail, cursize - size); - assert(edata_state_get(edata) == edata_state_get(trail)); - if (err) { - edata_cache_small_put(tsdn, ¢ral->ecs, trail); - return NULL; - } - assert(edata_state_get(edata) == edata_state_get(trail)); - - edata_size_set(edata, size); - emap_split_commit(tsdn, central->emap, &prepare, edata, size, trail, - cursize - size); - - return trail; -} - -edata_t * -hpa_central_alloc_reuse(tsdn_t *tsdn, hpa_central_t *central, - size_t size_min, size_t size_goal) { - assert((size_min & PAGE_MASK) == 0); - assert((size_goal & PAGE_MASK) == 0); - - /* - * Fragmentation avoidance is more important in the HPA than giving the - * user their preferred amount of space, since we expect the average - * unused extent to be more costly (PAC extents can get purged away - * easily at any granularity; HPA extents are much more difficult to - * purge away if they get stranded). So we always search for the - * earliest (in first-fit ordering) extent that can satisfy the request, - * and use it, regardless of the goal size. - */ - edata_t *edata = eset_fit(¢ral->eset, size_min, PAGE, - /* exact_only */ false, /* lg_max_fit */ SC_PTR_BITS); - if (edata == NULL) { - return NULL; - } - - eset_remove(¢ral->eset, edata); - /* Maybe the first fit is also under the limit. */ - if (edata_size_get(edata) <= size_goal) { - goto label_success; - } - - /* Otherwise, split. */ - edata_t *trail = hpa_central_split(tsdn, central, edata, size_goal); - if (trail == NULL) { - eset_insert(¢ral->eset, edata); - return NULL; - } - emap_assert_mapped(tsdn, central->emap, trail); - eset_insert(¢ral->eset, trail); - -label_success: - emap_assert_mapped(tsdn, central->emap, edata); - assert(edata_size_get(edata) >= size_min); - /* - * We don't yet support purging in the hpa_central; everything should be - * dirty. - */ - assert(edata_state_get(edata) == extent_state_dirty); - assert(edata_base_get(edata) == edata_addr_get(edata)); - emap_update_edata_state(tsdn, central->emap, edata, - extent_state_active); - return edata; -} - -bool -hpa_central_alloc_grow(tsdn_t *tsdn, hpa_central_t *central, - size_t size, edata_t *edata) { - assert((size & PAGE_MASK) == 0); - assert(edata_base_get(edata) == edata_addr_get(edata)); - assert(edata_size_get(edata) >= size); - assert(edata_arena_ind_get(edata) - == base_ind_get(central->ecs.fallback->base)); - assert(edata_is_head_get(edata)); - assert(edata_state_get(edata) == extent_state_active); - assert(edata_pai_get(edata) == EXTENT_PAI_HPA); - assert(edata_slab_get(edata) == false); - assert(edata_szind_get_maybe_invalid(edata) == SC_NSIZES); - - /* edata should be a new alloc, and hence not already mapped. */ - emap_assert_not_mapped(tsdn, central->emap, edata); - - size_t cursize = edata_size_get(edata); - - bool err = emap_register_boundary(tsdn, central->emap, edata, SC_NSIZES, - /* slab */ false); - if (err) { - return true; - } - /* No splitting is necessary. */ - if (cursize == size) { - size_t sn = central->sn_next++; - edata_sn_set(edata, sn); - return false; - } - - /* We should split. */ - edata_t *trail = hpa_central_split(tsdn, central, edata, size); - if (trail == NULL) { - emap_deregister_boundary(tsdn, central->emap, NULL); - return true; - } - size_t sn = central->sn_next++; - edata_sn_set(edata, sn); - edata_sn_set(trail, sn); - - emap_update_edata_state(tsdn, central->emap, trail, extent_state_dirty); - eset_insert(¢ral->eset, trail); - return false; -} - -/* Merges b into a, freeing b back to the edata cache.. */ -static void -hpa_central_dalloc_merge(tsdn_t *tsdn, hpa_central_t *central, edata_t *a, - edata_t *b) { - assert(emap_edata_is_acquired(tsdn, central->emap, a)); - assert(emap_edata_is_acquired(tsdn, central->emap, b)); - - emap_prepare_t prepare; - emap_merge_prepare(tsdn, central->emap, &prepare, a, b); - edata_size_set(a, edata_size_get(a) + edata_size_get(b)); - emap_merge_commit(tsdn, central->emap, &prepare, a, b); - edata_cache_small_put(tsdn, ¢ral->ecs, b); -} - -void -hpa_central_dalloc(tsdn_t *tsdn, hpa_central_t *central, edata_t *edata) { - assert(edata_state_get(edata) == extent_state_active); - assert(edata_ps_get(edata) == NULL); - - /* - * These should really be called at the pa interface level, but - * currently they're not. - */ - edata_addr_set(edata, edata_base_get(edata)); - edata_zeroed_set(edata, false); - - /* - * Merge forward first, so that the original *edata stays active state - * for the second acquire (only necessary for sanity checking). - */ - edata_t *trail = emap_try_acquire_edata_neighbor(tsdn, central->emap, - edata, EXTENT_PAI_HPA, extent_state_dirty, /* forward */ true); - if (trail != NULL) { - eset_remove(¢ral->eset, trail); - hpa_central_dalloc_merge(tsdn, central, edata, trail); - } - edata_t *lead = emap_try_acquire_edata_neighbor(tsdn, central->emap, - edata, EXTENT_PAI_HPA, extent_state_dirty, /* forward */ false); - if (lead != NULL) { - eset_remove(¢ral->eset, lead); - hpa_central_dalloc_merge(tsdn, central, lead, edata); - edata = lead; - } - - emap_update_edata_state(tsdn, central->emap, edata, extent_state_dirty); - eset_insert(¢ral->eset, edata); -} diff --git a/test/unit/hpa_central.c b/test/unit/hpa_central.c deleted file mode 100644 index f90b6e3c..00000000 --- a/test/unit/hpa_central.c +++ /dev/null @@ -1,450 +0,0 @@ -#include "test/jemalloc_test.h" - -#include "jemalloc/internal/hpa_central.h" - -typedef struct test_data_s test_data_t; -struct test_data_s { - /* - * Must be the first member -- we convert back and forth between the - * test_data_t and the hpa_central_t; - */ - hpa_central_t central; - base_t *base; - edata_cache_t edata_cache; - emap_t emap; -}; - -void -create_test_data(hpa_central_t **r_central, base_t **r_base) { - bool err; - base_t *base = base_new(TSDN_NULL, /* ind */ 111, - &ehooks_default_extent_hooks); - assert_ptr_not_null(base, ""); - - test_data_t *test_data = malloc(sizeof(test_data_t)); - assert_ptr_not_null(test_data, ""); - - test_data->base = base; - - err = edata_cache_init(&test_data->edata_cache, base); - assert_false(err, ""); - - err = emap_init(&test_data->emap, test_data->base, - /* zeroed */ false); - assert_false(err, ""); - - hpa_central_init(&test_data->central, &test_data->edata_cache, - &test_data->emap); - - *r_central = (hpa_central_t *)test_data; - *r_base = base; -} - -static void -destroy_test_data(hpa_central_t *central) { - test_data_t *test_data = (test_data_t *)central; - base_delete(TSDN_NULL, test_data->base); - free(test_data); -} - -static edata_t * -test_edata(base_t *base, uintptr_t addr, size_t size) { - edata_t *edata = base_alloc_edata(TSDN_NULL, base); - assert_ptr_not_null(edata, ""); - edata_init(edata, base_ind_get(base), (void *)addr, - size, /* slab */ false, /* szind_t */ SC_NSIZES, /* sn */ 0, - extent_state_active, /* zeroed */ true, /* comitted */ true, - EXTENT_PAI_HPA, /* is_head */ true); - return edata; -} - -static void -edata_expect_alloc(base_t *base, edata_t *edata, uintptr_t addr, size_t size) { - expect_ptr_not_null(edata, "Alloc should have succeeded"); - expect_u_eq(base_ind_get(base), edata_arena_ind_get(edata), ""); - expect_u_eq(SC_NSIZES, edata_szind_get_maybe_invalid(edata), ""); - expect_d_eq(extent_state_active, edata_state_get(edata), ""); - assert_ptr_eq((void *)addr, edata_base_get(edata), ""); - assert_zu_eq(size, edata_size_get(edata), ""); -} - - -TEST_BEGIN(test_empty) { - hpa_central_t *central; - base_t *base; - create_test_data(¢ral, &base); - - edata_t *edata; - - edata = hpa_central_alloc_reuse(TSDN_NULL, central, PAGE, PAGE); - expect_ptr_null(edata, "Empty allocator succeed in its allocation"); - - edata = hpa_central_alloc_reuse(TSDN_NULL, central, PAGE, 2 * PAGE); - expect_ptr_null(edata, "Empty allocator succeed in its allocation"); - - edata = hpa_central_alloc_reuse(TSDN_NULL, central, PAGE, 8 * PAGE); - expect_ptr_null(edata, "Empty allocator succeed in its allocation"); - - edata = hpa_central_alloc_reuse(TSDN_NULL, central, 4 * PAGE, 8 * PAGE); - expect_ptr_null(edata, "Empty allocator succeed in its allocation"); - - destroy_test_data(central); -} -TEST_END - -TEST_BEGIN(test_first_fit_simple) { - hpa_central_t *central; - base_t *base; - create_test_data(¢ral, &base); - - edata_t *edata1 = test_edata(base, 10 * PAGE, 10 * PAGE); - bool err = hpa_central_alloc_grow(TSDN_NULL, central, PAGE, edata1); - expect_false(err, "Unexpected grow failure"); - edata_expect_alloc(base, edata1, 10 * PAGE, PAGE); - - edata_t *edata2 = test_edata(base, 4 * PAGE, 1 * PAGE); - err = hpa_central_alloc_grow(TSDN_NULL, central, PAGE, edata2); - expect_false(err, "Unexpected grow failure"); - edata_expect_alloc(base, edata2, 4 * PAGE, PAGE); - - hpa_central_dalloc(TSDN_NULL, central, edata2); - - /* - * Even though there's a lower-addressed extent that a by-size search - * will find earlier, we should still pick the earlier one. - */ - edata_t *edata3 = hpa_central_alloc_reuse(TSDN_NULL, central, PAGE, PAGE); - /* - * Recall there's still an active page at the beginning of the extent - * added at 10 * PAGE; the next allocation from it should be at 11 * - * PAGE. - */ - edata_expect_alloc(base, edata3, 11 * PAGE, PAGE); - - destroy_test_data(central); -} -TEST_END - -TEST_BEGIN(test_first_fit_large_goal) { - /* - * See the comment in hpa_central_alloc_reuse; we should prefer an - * earlier allocation over a later one, even if it means we fall short - * of the goal size. - */ - hpa_central_t *central; - base_t *base; - create_test_data(¢ral, &base); - - edata_t *edata1 = test_edata(base, 10 * PAGE, 10 * PAGE); - bool err = hpa_central_alloc_grow(TSDN_NULL, central, 2 * PAGE, edata1); - expect_false(err, "Unexpected grow failure"); - edata_expect_alloc(base, edata1, 10 * PAGE, 2 * PAGE); - - /* We need a page, but would like 2. */ - edata_t *edata2 = hpa_central_alloc_reuse(TSDN_NULL, central, PAGE, - 2 * PAGE); - edata_expect_alloc(base, edata2, 12 * PAGE, 2 * PAGE); - - hpa_central_dalloc(TSDN_NULL, central, edata1); - - /* - * Now, we have a 2-page inactive extent, then a 2-page active extent, - * then a 6-page inactive extent. If our minimum size is 2 but the goal - * size is 4, we should still pick the first hole rather than the - * second. - */ - edata1 = hpa_central_alloc_reuse(TSDN_NULL, central, 2 * PAGE, 4 * PAGE); - edata_expect_alloc(base, edata1, 10 * PAGE, 2 * PAGE); - - /* - * Make sure we didn't succeed only by forgetting about that last range - * or something. - */ - edata_t *edata3 = hpa_central_alloc_reuse(TSDN_NULL, central, 4 * PAGE, - 4 * PAGE); - edata_expect_alloc(base, edata3, 14 * PAGE, 4 * PAGE); - - destroy_test_data(central); -} -TEST_END - -TEST_BEGIN(test_merging) { - hpa_central_t *central; - base_t *base; - create_test_data(¢ral, &base); - - /* Test an exact match */ - bool err; - edata_t *edata1 = test_edata(base, 10 * PAGE, PAGE); - err = hpa_central_alloc_grow(TSDN_NULL, central, PAGE, edata1); - expect_false(err, "Alloc should have succeeded"); - edata_expect_alloc(base, edata1, 10 * PAGE, PAGE); - - edata_t *edata2 = hpa_central_alloc_reuse(TSDN_NULL, central, PAGE, - PAGE); - expect_ptr_null(edata2, "Allocation should have failed"); - - /* - * Create two more regions; one immediately before the first and one - * immediately after. The extents shouldn't get merged. - */ - edata2 = test_edata(base, 11 * PAGE, PAGE); - err = hpa_central_alloc_grow(TSDN_NULL, central, PAGE, edata2); - edata_expect_alloc(base, edata2, 11 * PAGE, PAGE); - - edata_t *edata3 = test_edata(base, 12 * PAGE, 20 * PAGE); - err = hpa_central_alloc_grow(TSDN_NULL, central, PAGE, edata3); - edata_expect_alloc(base, edata3, 12 * PAGE, PAGE); - - /* - * OK, we've got 3 contiguous ranges; [10, 11), [11, 12), and [12, 22). - * They shouldn't get merged though, even once freed. We free the - * middle range last to test merging (or rather, the lack thereof) in - * both directions. - */ - hpa_central_dalloc(TSDN_NULL, central, edata1); - hpa_central_dalloc(TSDN_NULL, central, edata3); - hpa_central_dalloc(TSDN_NULL, central, edata2); - - /* - * A two-page range should only be satisfied by the third added region. - */ - edata_t *edata = hpa_central_alloc_reuse(TSDN_NULL, central, 2 * PAGE, - 2 * PAGE); - edata_expect_alloc(base, edata, 12 * PAGE, 2 * PAGE); - hpa_central_dalloc(TSDN_NULL, central, edata); - - /* Same with a three-page range. */ - edata = hpa_central_alloc_reuse(TSDN_NULL, central, 3 * PAGE, 3 * PAGE); - edata_expect_alloc(base, edata, 12 * PAGE, 3 * PAGE); - hpa_central_dalloc(TSDN_NULL, central, edata); - - /* Let's try some cases that *should* get merged. */ - edata1 = hpa_central_alloc_reuse(TSDN_NULL, central, 2 * PAGE, 2 * PAGE); - edata_expect_alloc(base, edata1, 12 * PAGE, 2 * PAGE); - edata2 = hpa_central_alloc_reuse(TSDN_NULL, central, 2 * PAGE, 2 * PAGE); - edata_expect_alloc(base, edata2, 14 * PAGE, 2 * PAGE); - edata3 = hpa_central_alloc_reuse(TSDN_NULL, central, 2 * PAGE, 2 * PAGE); - edata_expect_alloc(base, edata3, 16 * PAGE, 2 * PAGE); - - /* Merge with predecessor. */ - hpa_central_dalloc(TSDN_NULL, central, edata1); - hpa_central_dalloc(TSDN_NULL, central, edata2); - edata1 = hpa_central_alloc_reuse(TSDN_NULL, central, 4 * PAGE, - 4 * PAGE); - edata_expect_alloc(base, edata1, 12 * PAGE, 4 * PAGE); - - /* Merge with successor */ - hpa_central_dalloc(TSDN_NULL, central, edata3); - hpa_central_dalloc(TSDN_NULL, central, edata1); - edata1 = hpa_central_alloc_reuse(TSDN_NULL, central, 6 * PAGE, - 6 * PAGE); - edata_expect_alloc(base, edata1, 12 * PAGE, 6 * PAGE); - hpa_central_dalloc(TSDN_NULL, central, edata1); - - /* - * Let's try merging with both. We need to get three adjacent - * allocations again; do it the same way as before. - */ - edata1 = hpa_central_alloc_reuse(TSDN_NULL, central, 2 * PAGE, 2 * PAGE); - edata_expect_alloc(base, edata1, 12 * PAGE, 2 * PAGE); - edata2 = hpa_central_alloc_reuse(TSDN_NULL, central, 2 * PAGE, 2 * PAGE); - edata_expect_alloc(base, edata2, 14 * PAGE, 2 * PAGE); - edata3 = hpa_central_alloc_reuse(TSDN_NULL, central, 2 * PAGE, 2 * PAGE); - edata_expect_alloc(base, edata3, 16 * PAGE, 2 * PAGE); - - hpa_central_dalloc(TSDN_NULL, central, edata1); - hpa_central_dalloc(TSDN_NULL, central, edata3); - hpa_central_dalloc(TSDN_NULL, central, edata2); - - edata1 = hpa_central_alloc_reuse(TSDN_NULL, central, 6 * PAGE, - 6 * PAGE); - edata_expect_alloc(base, edata1, 12 * PAGE, 6 * PAGE); - - destroy_test_data(central); -} -TEST_END - -TEST_BEGIN(test_stress_simple) { - hpa_central_t *central; - base_t *base; - create_test_data(¢ral, &base); - - enum { - range_base = 1024 * PAGE, - range_pages = 256, - range_size = range_pages * PAGE - }; - - edata_t *edatas[range_pages]; - - bool err; - edata_t *range = test_edata(base, range_base, range_size); - err = hpa_central_alloc_grow(TSDN_NULL, central, PAGE, range); - expect_false(err, "Unexpected grow failure"); - hpa_central_dalloc(TSDN_NULL, central, range); - - for (size_t i = 0; i < range_pages; i++) { - edatas[i] = hpa_central_alloc_reuse(TSDN_NULL, central, PAGE, - PAGE); - edata_expect_alloc(base, edatas[i], range_base + i * PAGE, - PAGE); - } - /* Free up the odd indices. */ - for (size_t i = 0; i < range_pages; i++) { - if (i % 2 == 0) { - continue; - } - hpa_central_dalloc(TSDN_NULL, central, edatas[i]); - } - /* - * Reallocate them again. Try it with a goal size that can't be - * satisfied. - */ - for (size_t i = 0; i < range_pages; i++) { - if (i % 2 == 0) { - continue; - } - edatas[i] = hpa_central_alloc_reuse(TSDN_NULL, central, PAGE, - PAGE); - edata_expect_alloc(base, edatas[i], range_base + i * PAGE, - PAGE); - } - /* - * In each batch of 8, create a free range of 4 pages and a free range - * of 2 pages. - */ - for (size_t i = 0; i < range_pages; i += 8) { - hpa_central_dalloc(TSDN_NULL, central, edatas[i + 1]); - hpa_central_dalloc(TSDN_NULL, central, edatas[i + 2]); - hpa_central_dalloc(TSDN_NULL, central, edatas[i + 3]); - hpa_central_dalloc(TSDN_NULL, central, edatas[i + 4]); - - hpa_central_dalloc(TSDN_NULL, central, edatas[i + 6]); - hpa_central_dalloc(TSDN_NULL, central, edatas[i + 7]); - } - - /* - * And allocate 3 pages into the first, and 2 pages into the second. To - * mix things up a little, lets get those amounts via goal sizes - * instead. - */ - for (size_t i = 0; i < range_pages; i += 8) { - edatas[i + 1] = hpa_central_alloc_reuse(TSDN_NULL, central, - 2 * PAGE, 3 * PAGE); - edata_expect_alloc(base, edatas[i + 1], - range_base + (i + 1) * PAGE, 3 * PAGE); - - edatas[i + 6] = hpa_central_alloc_reuse(TSDN_NULL, central, - 2 * PAGE, 4 * PAGE); - edata_expect_alloc(base, edatas[i + 6], - range_base + (i + 6) * PAGE, 2 * PAGE); - } - - edata_t *edata = hpa_central_alloc_reuse(TSDN_NULL, central, 2 * PAGE, - 2 * PAGE); - expect_ptr_null(edata, "Should be no free ranges of 2 pages"); - - destroy_test_data(central); -} -TEST_END - -TEST_BEGIN(test_stress_random) { - const size_t range_length = 32 * PAGE; - const size_t range_base = 100 * PAGE; - const size_t size_max_pages = 16; - - hpa_central_t *central; - base_t *base; - create_test_data(¢ral, &base); - - /* - * We loop through this once per some operations, so we don't want it to - * get too big. - */ - const size_t nlive_edatas_max = 100; - size_t nlive_edatas = 0; - edata_t **live_edatas = calloc(nlive_edatas_max, sizeof(edata_t *)); - size_t nranges = 0; - - /* - * Nothing special about this constant; we're only fixing it for - * consistency across runs. - */ - size_t prng_state = (size_t)0x76999ffb014df07c; - for (size_t i = 0; i < 100 * 1000; i++) { - size_t operation = prng_range_zu(&prng_state, 2); - if (operation == 0) { - /* Do an alloc. */ - if (nlive_edatas == nlive_edatas_max) { - continue; - } - size_t min_pages = 1 + prng_range_zu( - &prng_state, size_max_pages); - size_t goal_pages = min_pages + prng_range_zu( - &prng_state, size_max_pages - min_pages + 1); - edata_t *edata = hpa_central_alloc_reuse(TSDN_NULL, - central, min_pages * PAGE, goal_pages * PAGE); - if (edata == NULL) { - edata = test_edata(base, - range_base + range_length * nranges, - range_length); - bool err = hpa_central_alloc_grow(TSDN_NULL, - central, goal_pages * PAGE, edata); - assert_false(err, "Unexpected grow failure"); - nranges++; - } - uintptr_t begin = (uintptr_t)edata_base_get(edata); - uintptr_t end = (uintptr_t)edata_last_get(edata); - size_t range_begin = (begin - range_base) / range_length; - size_t range_end = (end - range_base) / range_length; - expect_zu_eq(range_begin, range_end, - "Should not have allocations spanning " - "multiple ranges"); - expect_zu_ge(begin, range_base, - "Gave back a pointer outside of the reserved " - "range"); - expect_zu_lt(end, range_base + range_length * nranges, - "Gave back a pointer outside of the reserved " - "range"); - for (size_t j = 0; j < nlive_edatas; j++) { - edata_t *other = live_edatas[j]; - uintptr_t other_begin = - (uintptr_t)edata_base_get(other); - uintptr_t other_end = - (uintptr_t)edata_last_get(other); - expect_true( - (begin < other_begin && end < other_begin) - || (begin > other_end), - "Gave back two extents that overlap"); - } - live_edatas[nlive_edatas] = edata; - nlive_edatas++; - } else { - /* Do a free. */ - if (nlive_edatas == 0) { - continue; - } - size_t victim = prng_range_zu(&prng_state, - nlive_edatas); - edata_t *to_free = live_edatas[victim]; - live_edatas[victim] = live_edatas[nlive_edatas - 1]; - nlive_edatas--; - hpa_central_dalloc(TSDN_NULL, central, to_free); - } - } - - free(live_edatas); - destroy_test_data(central); -} -TEST_END - -int main(void) { - return test_no_reentrancy( - test_empty, - test_first_fit_simple, - test_first_fit_large_goal, - test_merging, - test_stress_simple, - test_stress_random); -}