diff options
Diffstat (limited to 'examples/redis-unstable/deps/jemalloc/test/unit/psset.c')
| -rw-r--r-- | examples/redis-unstable/deps/jemalloc/test/unit/psset.c | 748 |
1 files changed, 0 insertions, 748 deletions
diff --git a/examples/redis-unstable/deps/jemalloc/test/unit/psset.c b/examples/redis-unstable/deps/jemalloc/test/unit/psset.c deleted file mode 100644 index 6ff7201..0000000 --- a/examples/redis-unstable/deps/jemalloc/test/unit/psset.c +++ /dev/null @@ -1,748 +0,0 @@ -#include "test/jemalloc_test.h" - -#include "jemalloc/internal/psset.h" - -#define PAGESLAB_ADDR ((void *)(1234 * HUGEPAGE)) -#define PAGESLAB_AGE 5678 - -#define ALLOC_ARENA_IND 111 -#define ALLOC_ESN 222 - -static void -edata_init_test(edata_t *edata) { - memset(edata, 0, sizeof(*edata)); - edata_arena_ind_set(edata, ALLOC_ARENA_IND); - edata_esn_set(edata, ALLOC_ESN); -} - -static void -test_psset_fake_purge(hpdata_t *ps) { - hpdata_purge_state_t purge_state; - hpdata_alloc_allowed_set(ps, false); - hpdata_purge_begin(ps, &purge_state); - void *addr; - size_t size; - while (hpdata_purge_next(ps, &purge_state, &addr, &size)) { - } - hpdata_purge_end(ps, &purge_state); - hpdata_alloc_allowed_set(ps, true); -} - -static void -test_psset_alloc_new(psset_t *psset, hpdata_t *ps, edata_t *r_edata, - size_t size) { - hpdata_assert_empty(ps); - - test_psset_fake_purge(ps); - - psset_insert(psset, ps); - psset_update_begin(psset, ps); - - void *addr = hpdata_reserve_alloc(ps, size); - edata_init(r_edata, edata_arena_ind_get(r_edata), addr, size, - /* slab */ false, SC_NSIZES, /* sn */ 0, extent_state_active, - /* zeroed */ false, /* committed */ true, EXTENT_PAI_HPA, - EXTENT_NOT_HEAD); - edata_ps_set(r_edata, ps); - psset_update_end(psset, ps); -} - -static bool -test_psset_alloc_reuse(psset_t *psset, edata_t *r_edata, size_t size) { - hpdata_t *ps = psset_pick_alloc(psset, size); - if (ps == NULL) { - return true; - } - psset_update_begin(psset, ps); - void *addr = hpdata_reserve_alloc(ps, size); - edata_init(r_edata, edata_arena_ind_get(r_edata), addr, size, - /* slab */ false, SC_NSIZES, /* sn */ 0, extent_state_active, - /* zeroed */ false, /* committed */ true, EXTENT_PAI_HPA, - EXTENT_NOT_HEAD); - edata_ps_set(r_edata, ps); - psset_update_end(psset, ps); - return false; -} - -static hpdata_t * -test_psset_dalloc(psset_t *psset, edata_t *edata) { - hpdata_t *ps = edata_ps_get(edata); - psset_update_begin(psset, ps); - hpdata_unreserve(ps, edata_addr_get(edata), edata_size_get(edata)); - psset_update_end(psset, ps); - if (hpdata_empty(ps)) { - psset_remove(psset, ps); - return ps; - } else { - return NULL; - } -} - -static void -edata_expect(edata_t *edata, size_t page_offset, size_t page_cnt) { - /* - * Note that allocations should get the arena ind of their home - * arena, *not* the arena ind of the pageslab allocator. - */ - expect_u_eq(ALLOC_ARENA_IND, edata_arena_ind_get(edata), - "Arena ind changed"); - expect_ptr_eq( - (void *)((uintptr_t)PAGESLAB_ADDR + (page_offset << LG_PAGE)), - edata_addr_get(edata), "Didn't allocate in order"); - expect_zu_eq(page_cnt << LG_PAGE, edata_size_get(edata), ""); - expect_false(edata_slab_get(edata), ""); - expect_u_eq(SC_NSIZES, edata_szind_get_maybe_invalid(edata), - ""); - expect_u64_eq(0, edata_sn_get(edata), ""); - expect_d_eq(edata_state_get(edata), extent_state_active, ""); - expect_false(edata_zeroed_get(edata), ""); - expect_true(edata_committed_get(edata), ""); - expect_d_eq(EXTENT_PAI_HPA, edata_pai_get(edata), ""); - expect_false(edata_is_head_get(edata), ""); -} - -TEST_BEGIN(test_empty) { - bool err; - hpdata_t pageslab; - hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); - - edata_t alloc; - edata_init_test(&alloc); - - psset_t psset; - psset_init(&psset); - - /* Empty psset should return fail allocations. */ - err = test_psset_alloc_reuse(&psset, &alloc, PAGE); - expect_true(err, "Empty psset succeeded in an allocation."); -} -TEST_END - -TEST_BEGIN(test_fill) { - bool err; - - hpdata_t pageslab; - hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); - - edata_t alloc[HUGEPAGE_PAGES]; - - psset_t psset; - psset_init(&psset); - - edata_init_test(&alloc[0]); - test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); - for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { - edata_init_test(&alloc[i]); - err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); - expect_false(err, "Nonempty psset failed page allocation."); - } - - for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { - edata_t *edata = &alloc[i]; - edata_expect(edata, i, 1); - } - - /* The pageslab, and thus psset, should now have no allocations. */ - edata_t extra_alloc; - edata_init_test(&extra_alloc); - err = test_psset_alloc_reuse(&psset, &extra_alloc, PAGE); - expect_true(err, "Alloc succeeded even though psset should be empty"); -} -TEST_END - -TEST_BEGIN(test_reuse) { - bool err; - hpdata_t *ps; - - hpdata_t pageslab; - hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); - - edata_t alloc[HUGEPAGE_PAGES]; - - psset_t psset; - psset_init(&psset); - - edata_init_test(&alloc[0]); - test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); - for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { - edata_init_test(&alloc[i]); - err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); - expect_false(err, "Nonempty psset failed page allocation."); - } - - /* Free odd indices. */ - for (size_t i = 0; i < HUGEPAGE_PAGES; i ++) { - if (i % 2 == 0) { - continue; - } - ps = test_psset_dalloc(&psset, &alloc[i]); - expect_ptr_null(ps, "Nonempty pageslab evicted"); - } - /* Realloc into them. */ - for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { - if (i % 2 == 0) { - continue; - } - err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); - expect_false(err, "Nonempty psset failed page allocation."); - edata_expect(&alloc[i], i, 1); - } - /* Now, free the pages at indices 0 or 1 mod 2. */ - for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { - if (i % 4 > 1) { - continue; - } - ps = test_psset_dalloc(&psset, &alloc[i]); - expect_ptr_null(ps, "Nonempty pageslab evicted"); - } - /* And realloc 2-page allocations into them. */ - for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { - if (i % 4 != 0) { - continue; - } - err = test_psset_alloc_reuse(&psset, &alloc[i], 2 * PAGE); - expect_false(err, "Nonempty psset failed page allocation."); - edata_expect(&alloc[i], i, 2); - } - /* Free all the 2-page allocations. */ - for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { - if (i % 4 != 0) { - continue; - } - ps = test_psset_dalloc(&psset, &alloc[i]); - expect_ptr_null(ps, "Nonempty pageslab evicted"); - } - /* - * Free up a 1-page hole next to a 2-page hole, but somewhere in the - * middle of the pageslab. Index 11 should be right before such a hole - * (since 12 % 4 == 0). - */ - size_t index_of_3 = 11; - ps = test_psset_dalloc(&psset, &alloc[index_of_3]); - expect_ptr_null(ps, "Nonempty pageslab evicted"); - err = test_psset_alloc_reuse(&psset, &alloc[index_of_3], 3 * PAGE); - expect_false(err, "Should have been able to find alloc."); - edata_expect(&alloc[index_of_3], index_of_3, 3); - - /* - * Free up a 4-page hole at the end. Recall that the pages at offsets 0 - * and 1 mod 4 were freed above, so we just have to free the last - * allocations. - */ - ps = test_psset_dalloc(&psset, &alloc[HUGEPAGE_PAGES - 1]); - expect_ptr_null(ps, "Nonempty pageslab evicted"); - ps = test_psset_dalloc(&psset, &alloc[HUGEPAGE_PAGES - 2]); - expect_ptr_null(ps, "Nonempty pageslab evicted"); - - /* Make sure we can satisfy an allocation at the very end of a slab. */ - size_t index_of_4 = HUGEPAGE_PAGES - 4; - err = test_psset_alloc_reuse(&psset, &alloc[index_of_4], 4 * PAGE); - expect_false(err, "Should have been able to find alloc."); - edata_expect(&alloc[index_of_4], index_of_4, 4); -} -TEST_END - -TEST_BEGIN(test_evict) { - bool err; - hpdata_t *ps; - - hpdata_t pageslab; - hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); - - edata_t alloc[HUGEPAGE_PAGES]; - - psset_t psset; - psset_init(&psset); - - /* Alloc the whole slab. */ - edata_init_test(&alloc[0]); - test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); - for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { - edata_init_test(&alloc[i]); - err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); - expect_false(err, "Unxpected allocation failure"); - } - - /* Dealloc the whole slab, going forwards. */ - for (size_t i = 0; i < HUGEPAGE_PAGES - 1; i++) { - ps = test_psset_dalloc(&psset, &alloc[i]); - expect_ptr_null(ps, "Nonempty pageslab evicted"); - } - ps = test_psset_dalloc(&psset, &alloc[HUGEPAGE_PAGES - 1]); - expect_ptr_eq(&pageslab, ps, "Empty pageslab not evicted."); - - err = test_psset_alloc_reuse(&psset, &alloc[0], PAGE); - expect_true(err, "psset should be empty."); -} -TEST_END - -TEST_BEGIN(test_multi_pageslab) { - bool err; - hpdata_t *ps; - - hpdata_t pageslab[2]; - hpdata_init(&pageslab[0], PAGESLAB_ADDR, PAGESLAB_AGE); - hpdata_init(&pageslab[1], - (void *)((uintptr_t)PAGESLAB_ADDR + HUGEPAGE), - PAGESLAB_AGE + 1); - - edata_t alloc[2][HUGEPAGE_PAGES]; - - psset_t psset; - psset_init(&psset); - - /* Insert both slabs. */ - edata_init_test(&alloc[0][0]); - test_psset_alloc_new(&psset, &pageslab[0], &alloc[0][0], PAGE); - edata_init_test(&alloc[1][0]); - test_psset_alloc_new(&psset, &pageslab[1], &alloc[1][0], PAGE); - - /* Fill them both up; make sure we do so in first-fit order. */ - for (size_t i = 0; i < 2; i++) { - for (size_t j = 1; j < HUGEPAGE_PAGES; j++) { - edata_init_test(&alloc[i][j]); - err = test_psset_alloc_reuse(&psset, &alloc[i][j], PAGE); - expect_false(err, - "Nonempty psset failed page allocation."); - assert_ptr_eq(&pageslab[i], edata_ps_get(&alloc[i][j]), - "Didn't pick pageslabs in first-fit"); - } - } - - /* - * Free up a 2-page hole in the earlier slab, and a 1-page one in the - * later one. We should still pick the later one. - */ - ps = test_psset_dalloc(&psset, &alloc[0][0]); - expect_ptr_null(ps, "Unexpected eviction"); - ps = test_psset_dalloc(&psset, &alloc[0][1]); - expect_ptr_null(ps, "Unexpected eviction"); - ps = test_psset_dalloc(&psset, &alloc[1][0]); - expect_ptr_null(ps, "Unexpected eviction"); - err = test_psset_alloc_reuse(&psset, &alloc[0][0], PAGE); - expect_ptr_eq(&pageslab[1], edata_ps_get(&alloc[0][0]), - "Should have picked the fuller pageslab"); - - /* - * Now both slabs have 1-page holes. Free up a second one in the later - * slab. - */ - ps = test_psset_dalloc(&psset, &alloc[1][1]); - expect_ptr_null(ps, "Unexpected eviction"); - - /* - * We should be able to allocate a 2-page object, even though an earlier - * size class is nonempty. - */ - err = test_psset_alloc_reuse(&psset, &alloc[1][0], 2 * PAGE); - expect_false(err, "Allocation should have succeeded"); -} -TEST_END - -static void -stats_expect_empty(psset_bin_stats_t *stats) { - assert_zu_eq(0, stats->npageslabs, - "Supposedly empty bin had positive npageslabs"); - expect_zu_eq(0, stats->nactive, "Unexpected nonempty bin" - "Supposedly empty bin had positive nactive"); -} - -static void -stats_expect(psset_t *psset, size_t nactive) { - if (nactive == HUGEPAGE_PAGES) { - expect_zu_eq(1, psset->stats.full_slabs[0].npageslabs, - "Expected a full slab"); - expect_zu_eq(HUGEPAGE_PAGES, - psset->stats.full_slabs[0].nactive, - "Should have exactly filled the bin"); - } else { - stats_expect_empty(&psset->stats.full_slabs[0]); - } - size_t ninactive = HUGEPAGE_PAGES - nactive; - pszind_t nonempty_pind = PSSET_NPSIZES; - if (ninactive != 0 && ninactive < HUGEPAGE_PAGES) { - nonempty_pind = sz_psz2ind(sz_psz_quantize_floor( - ninactive << LG_PAGE)); - } - for (pszind_t i = 0; i < PSSET_NPSIZES; i++) { - if (i == nonempty_pind) { - assert_zu_eq(1, - psset->stats.nonfull_slabs[i][0].npageslabs, - "Should have found a slab"); - expect_zu_eq(nactive, - psset->stats.nonfull_slabs[i][0].nactive, - "Mismatch in active pages"); - } else { - stats_expect_empty(&psset->stats.nonfull_slabs[i][0]); - } - } - expect_zu_eq(nactive, psset_nactive(psset), ""); -} - -TEST_BEGIN(test_stats) { - bool err; - - hpdata_t pageslab; - hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); - - edata_t alloc[HUGEPAGE_PAGES]; - - psset_t psset; - psset_init(&psset); - stats_expect(&psset, 0); - - edata_init_test(&alloc[0]); - test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); - for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { - stats_expect(&psset, i); - edata_init_test(&alloc[i]); - err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); - expect_false(err, "Nonempty psset failed page allocation."); - } - stats_expect(&psset, HUGEPAGE_PAGES); - hpdata_t *ps; - for (ssize_t i = HUGEPAGE_PAGES - 1; i >= 0; i--) { - ps = test_psset_dalloc(&psset, &alloc[i]); - expect_true((ps == NULL) == (i != 0), - "test_psset_dalloc should only evict a slab on the last " - "free"); - stats_expect(&psset, i); - } - - test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); - stats_expect(&psset, 1); - psset_update_begin(&psset, &pageslab); - stats_expect(&psset, 0); - psset_update_end(&psset, &pageslab); - stats_expect(&psset, 1); -} -TEST_END - -/* - * Fills in and inserts two pageslabs, with the first better than the second, - * and each fully allocated (into the allocations in allocs and worse_allocs, - * each of which should be HUGEPAGE_PAGES long), except for a single free page - * at the end. - * - * (There's nothing magic about these numbers; it's just useful to share the - * setup between the oldest fit and the insert/remove test). - */ -static void -init_test_pageslabs(psset_t *psset, hpdata_t *pageslab, - hpdata_t *worse_pageslab, edata_t *alloc, edata_t *worse_alloc) { - bool err; - - hpdata_init(pageslab, (void *)(10 * HUGEPAGE), PAGESLAB_AGE); - /* - * This pageslab would be better from an address-first-fit POV, but - * worse from an age POV. - */ - hpdata_init(worse_pageslab, (void *)(9 * HUGEPAGE), PAGESLAB_AGE + 1); - - psset_init(psset); - - edata_init_test(&alloc[0]); - test_psset_alloc_new(psset, pageslab, &alloc[0], PAGE); - for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { - edata_init_test(&alloc[i]); - err = test_psset_alloc_reuse(psset, &alloc[i], PAGE); - expect_false(err, "Nonempty psset failed page allocation."); - expect_ptr_eq(pageslab, edata_ps_get(&alloc[i]), - "Allocated from the wrong pageslab"); - } - - edata_init_test(&worse_alloc[0]); - test_psset_alloc_new(psset, worse_pageslab, &worse_alloc[0], PAGE); - expect_ptr_eq(worse_pageslab, edata_ps_get(&worse_alloc[0]), - "Allocated from the wrong pageslab"); - /* - * Make the two pssets otherwise indistinguishable; all full except for - * a single page. - */ - for (size_t i = 1; i < HUGEPAGE_PAGES - 1; i++) { - edata_init_test(&worse_alloc[i]); - err = test_psset_alloc_reuse(psset, &alloc[i], PAGE); - expect_false(err, "Nonempty psset failed page allocation."); - expect_ptr_eq(worse_pageslab, edata_ps_get(&alloc[i]), - "Allocated from the wrong pageslab"); - } - - /* Deallocate the last page from the older pageslab. */ - hpdata_t *evicted = test_psset_dalloc(psset, - &alloc[HUGEPAGE_PAGES - 1]); - expect_ptr_null(evicted, "Unexpected eviction"); -} - -TEST_BEGIN(test_oldest_fit) { - bool err; - edata_t alloc[HUGEPAGE_PAGES]; - edata_t worse_alloc[HUGEPAGE_PAGES]; - - hpdata_t pageslab; - hpdata_t worse_pageslab; - - psset_t psset; - - init_test_pageslabs(&psset, &pageslab, &worse_pageslab, alloc, - worse_alloc); - - /* The edata should come from the better pageslab. */ - edata_t test_edata; - edata_init_test(&test_edata); - err = test_psset_alloc_reuse(&psset, &test_edata, PAGE); - expect_false(err, "Nonempty psset failed page allocation"); - expect_ptr_eq(&pageslab, edata_ps_get(&test_edata), - "Allocated from the wrong pageslab"); -} -TEST_END - -TEST_BEGIN(test_insert_remove) { - bool err; - hpdata_t *ps; - edata_t alloc[HUGEPAGE_PAGES]; - edata_t worse_alloc[HUGEPAGE_PAGES]; - - hpdata_t pageslab; - hpdata_t worse_pageslab; - - psset_t psset; - - init_test_pageslabs(&psset, &pageslab, &worse_pageslab, alloc, - worse_alloc); - - /* Remove better; should still be able to alloc from worse. */ - psset_update_begin(&psset, &pageslab); - err = test_psset_alloc_reuse(&psset, &worse_alloc[HUGEPAGE_PAGES - 1], - PAGE); - expect_false(err, "Removal should still leave an empty page"); - expect_ptr_eq(&worse_pageslab, - edata_ps_get(&worse_alloc[HUGEPAGE_PAGES - 1]), - "Allocated out of wrong ps"); - - /* - * After deallocating the previous alloc and reinserting better, it - * should be preferred for future allocations. - */ - ps = test_psset_dalloc(&psset, &worse_alloc[HUGEPAGE_PAGES - 1]); - expect_ptr_null(ps, "Incorrect eviction of nonempty pageslab"); - psset_update_end(&psset, &pageslab); - err = test_psset_alloc_reuse(&psset, &alloc[HUGEPAGE_PAGES - 1], PAGE); - expect_false(err, "psset should be nonempty"); - expect_ptr_eq(&pageslab, edata_ps_get(&alloc[HUGEPAGE_PAGES - 1]), - "Removal/reinsertion shouldn't change ordering"); - /* - * After deallocating and removing both, allocations should fail. - */ - ps = test_psset_dalloc(&psset, &alloc[HUGEPAGE_PAGES - 1]); - expect_ptr_null(ps, "Incorrect eviction"); - psset_update_begin(&psset, &pageslab); - psset_update_begin(&psset, &worse_pageslab); - err = test_psset_alloc_reuse(&psset, &alloc[HUGEPAGE_PAGES - 1], PAGE); - expect_true(err, "psset should be empty, but an alloc succeeded"); -} -TEST_END - -TEST_BEGIN(test_purge_prefers_nonhuge) { - /* - * All else being equal, we should prefer purging non-huge pages over - * huge ones for non-empty extents. - */ - - /* Nothing magic about this constant. */ - enum { - NHP = 23, - }; - hpdata_t *hpdata; - - psset_t psset; - psset_init(&psset); - - hpdata_t hpdata_huge[NHP]; - uintptr_t huge_begin = (uintptr_t)&hpdata_huge[0]; - uintptr_t huge_end = (uintptr_t)&hpdata_huge[NHP]; - hpdata_t hpdata_nonhuge[NHP]; - uintptr_t nonhuge_begin = (uintptr_t)&hpdata_nonhuge[0]; - uintptr_t nonhuge_end = (uintptr_t)&hpdata_nonhuge[NHP]; - - for (size_t i = 0; i < NHP; i++) { - hpdata_init(&hpdata_huge[i], (void *)((10 + i) * HUGEPAGE), - 123 + i); - psset_insert(&psset, &hpdata_huge[i]); - - hpdata_init(&hpdata_nonhuge[i], - (void *)((10 + NHP + i) * HUGEPAGE), - 456 + i); - psset_insert(&psset, &hpdata_nonhuge[i]); - - } - for (int i = 0; i < 2 * NHP; i++) { - hpdata = psset_pick_alloc(&psset, HUGEPAGE * 3 / 4); - psset_update_begin(&psset, hpdata); - void *ptr; - ptr = hpdata_reserve_alloc(hpdata, HUGEPAGE * 3 / 4); - /* Ignore the first alloc, which will stick around. */ - (void)ptr; - /* - * The second alloc is to dirty the pages; free it immediately - * after allocating. - */ - ptr = hpdata_reserve_alloc(hpdata, HUGEPAGE / 4); - hpdata_unreserve(hpdata, ptr, HUGEPAGE / 4); - - if (huge_begin <= (uintptr_t)hpdata - && (uintptr_t)hpdata < huge_end) { - hpdata_hugify(hpdata); - } - - hpdata_purge_allowed_set(hpdata, true); - psset_update_end(&psset, hpdata); - } - - /* - * We've got a bunch of 1/8th dirty hpdatas. It should give us all the - * non-huge ones to purge, then all the huge ones, then refuse to purge - * further. - */ - for (int i = 0; i < NHP; i++) { - hpdata = psset_pick_purge(&psset); - assert_true(nonhuge_begin <= (uintptr_t)hpdata - && (uintptr_t)hpdata < nonhuge_end, ""); - psset_update_begin(&psset, hpdata); - test_psset_fake_purge(hpdata); - hpdata_purge_allowed_set(hpdata, false); - psset_update_end(&psset, hpdata); - } - for (int i = 0; i < NHP; i++) { - hpdata = psset_pick_purge(&psset); - expect_true(huge_begin <= (uintptr_t)hpdata - && (uintptr_t)hpdata < huge_end, ""); - psset_update_begin(&psset, hpdata); - hpdata_dehugify(hpdata); - test_psset_fake_purge(hpdata); - hpdata_purge_allowed_set(hpdata, false); - psset_update_end(&psset, hpdata); - } -} -TEST_END - -TEST_BEGIN(test_purge_prefers_empty) { - void *ptr; - - psset_t psset; - psset_init(&psset); - - hpdata_t hpdata_empty; - hpdata_t hpdata_nonempty; - hpdata_init(&hpdata_empty, (void *)(10 * HUGEPAGE), 123); - psset_insert(&psset, &hpdata_empty); - hpdata_init(&hpdata_nonempty, (void *)(11 * HUGEPAGE), 456); - psset_insert(&psset, &hpdata_nonempty); - - psset_update_begin(&psset, &hpdata_empty); - ptr = hpdata_reserve_alloc(&hpdata_empty, PAGE); - expect_ptr_eq(hpdata_addr_get(&hpdata_empty), ptr, ""); - hpdata_unreserve(&hpdata_empty, ptr, PAGE); - hpdata_purge_allowed_set(&hpdata_empty, true); - psset_update_end(&psset, &hpdata_empty); - - psset_update_begin(&psset, &hpdata_nonempty); - ptr = hpdata_reserve_alloc(&hpdata_nonempty, 10 * PAGE); - expect_ptr_eq(hpdata_addr_get(&hpdata_nonempty), ptr, ""); - hpdata_unreserve(&hpdata_nonempty, ptr, 9 * PAGE); - hpdata_purge_allowed_set(&hpdata_nonempty, true); - psset_update_end(&psset, &hpdata_nonempty); - - /* - * The nonempty slab has 9 dirty pages, while the empty one has only 1. - * We should still pick the empty one for purging. - */ - hpdata_t *to_purge = psset_pick_purge(&psset); - expect_ptr_eq(&hpdata_empty, to_purge, ""); -} -TEST_END - -TEST_BEGIN(test_purge_prefers_empty_huge) { - void *ptr; - - psset_t psset; - psset_init(&psset); - - enum {NHP = 10 }; - - hpdata_t hpdata_huge[NHP]; - hpdata_t hpdata_nonhuge[NHP]; - - uintptr_t cur_addr = 100 * HUGEPAGE; - uint64_t cur_age = 123; - for (int i = 0; i < NHP; i++) { - hpdata_init(&hpdata_huge[i], (void *)cur_addr, cur_age); - cur_addr += HUGEPAGE; - cur_age++; - psset_insert(&psset, &hpdata_huge[i]); - - hpdata_init(&hpdata_nonhuge[i], (void *)cur_addr, cur_age); - cur_addr += HUGEPAGE; - cur_age++; - psset_insert(&psset, &hpdata_nonhuge[i]); - - /* - * Make the hpdata_huge[i] fully dirty, empty, purgable, and - * huge. - */ - psset_update_begin(&psset, &hpdata_huge[i]); - ptr = hpdata_reserve_alloc(&hpdata_huge[i], HUGEPAGE); - expect_ptr_eq(hpdata_addr_get(&hpdata_huge[i]), ptr, ""); - hpdata_hugify(&hpdata_huge[i]); - hpdata_unreserve(&hpdata_huge[i], ptr, HUGEPAGE); - hpdata_purge_allowed_set(&hpdata_huge[i], true); - psset_update_end(&psset, &hpdata_huge[i]); - - /* - * Make hpdata_nonhuge[i] fully dirty, empty, purgable, and - * non-huge. - */ - psset_update_begin(&psset, &hpdata_nonhuge[i]); - ptr = hpdata_reserve_alloc(&hpdata_nonhuge[i], HUGEPAGE); - expect_ptr_eq(hpdata_addr_get(&hpdata_nonhuge[i]), ptr, ""); - hpdata_unreserve(&hpdata_nonhuge[i], ptr, HUGEPAGE); - hpdata_purge_allowed_set(&hpdata_nonhuge[i], true); - psset_update_end(&psset, &hpdata_nonhuge[i]); - } - - /* - * We have a bunch of empty slabs, half huge, half nonhuge, inserted in - * alternating order. We should pop all the huge ones before popping - * any of the non-huge ones for purging. - */ - for (int i = 0; i < NHP; i++) { - hpdata_t *to_purge = psset_pick_purge(&psset); - expect_ptr_eq(&hpdata_huge[i], to_purge, ""); - psset_update_begin(&psset, to_purge); - hpdata_purge_allowed_set(to_purge, false); - psset_update_end(&psset, to_purge); - } - for (int i = 0; i < NHP; i++) { - hpdata_t *to_purge = psset_pick_purge(&psset); - expect_ptr_eq(&hpdata_nonhuge[i], to_purge, ""); - psset_update_begin(&psset, to_purge); - hpdata_purge_allowed_set(to_purge, false); - psset_update_end(&psset, to_purge); - } -} -TEST_END - -int -main(void) { - return test_no_reentrancy( - test_empty, - test_fill, - test_reuse, - test_evict, - test_multi_pageslab, - test_stats, - test_oldest_fit, - test_insert_remove, - test_purge_prefers_nonhuge, - test_purge_prefers_empty, - test_purge_prefers_empty_huge); -} |
