2020-12-02 23:04:01 +08:00
|
|
|
#include "test/jemalloc_test.h"
|
|
|
|
|
|
|
|
#define HPDATA_ADDR ((void *)(10 * HUGEPAGE))
|
|
|
|
#define HPDATA_AGE 123
|
|
|
|
|
|
|
|
TEST_BEGIN(test_reserve_alloc) {
|
|
|
|
hpdata_t hpdata;
|
|
|
|
hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
|
|
|
|
|
|
|
|
/* Allocating a page at a time, we should do first fit. */
|
|
|
|
for (size_t i = 0; i < HUGEPAGE_PAGES; i++) {
|
|
|
|
expect_true(hpdata_consistent(&hpdata), "");
|
|
|
|
expect_zu_eq(HUGEPAGE_PAGES - i,
|
|
|
|
hpdata_longest_free_range_get(&hpdata), "");
|
|
|
|
void *alloc = hpdata_reserve_alloc(&hpdata, PAGE);
|
|
|
|
expect_ptr_eq((char *)HPDATA_ADDR + i * PAGE, alloc, "");
|
|
|
|
expect_true(hpdata_consistent(&hpdata), "");
|
|
|
|
}
|
|
|
|
expect_true(hpdata_consistent(&hpdata), "");
|
|
|
|
expect_zu_eq(0, hpdata_longest_free_range_get(&hpdata), "");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build up a bigger free-range, 2 pages at a time, until we've got 6
|
|
|
|
* adjacent free pages total. Pages 8-13 should be unreserved after
|
|
|
|
* this.
|
|
|
|
*/
|
|
|
|
hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 10 * PAGE, 2 * PAGE);
|
|
|
|
expect_true(hpdata_consistent(&hpdata), "");
|
|
|
|
expect_zu_eq(2, hpdata_longest_free_range_get(&hpdata), "");
|
|
|
|
|
|
|
|
hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 12 * PAGE, 2 * PAGE);
|
|
|
|
expect_true(hpdata_consistent(&hpdata), "");
|
|
|
|
expect_zu_eq(4, hpdata_longest_free_range_get(&hpdata), "");
|
|
|
|
|
|
|
|
hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 8 * PAGE, 2 * PAGE);
|
|
|
|
expect_true(hpdata_consistent(&hpdata), "");
|
|
|
|
expect_zu_eq(6, hpdata_longest_free_range_get(&hpdata), "");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Leave page 14 reserved, but free page 15 (this test the case where
|
|
|
|
* unreserving combines two ranges).
|
|
|
|
*/
|
|
|
|
hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 15 * PAGE, PAGE);
|
|
|
|
/*
|
|
|
|
* Longest free range shouldn't change; we've got a free range of size
|
|
|
|
* 6, then a reserved page, then another free range.
|
|
|
|
*/
|
|
|
|
expect_true(hpdata_consistent(&hpdata), "");
|
|
|
|
expect_zu_eq(6, hpdata_longest_free_range_get(&hpdata), "");
|
|
|
|
|
|
|
|
/* After freeing page 14, the two ranges get combined. */
|
|
|
|
hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 14 * PAGE, PAGE);
|
|
|
|
expect_true(hpdata_consistent(&hpdata), "");
|
|
|
|
expect_zu_eq(8, hpdata_longest_free_range_get(&hpdata), "");
|
|
|
|
}
|
|
|
|
TEST_END
|
|
|
|
|
2020-12-03 10:44:34 +08:00
|
|
|
TEST_BEGIN(test_purge_simple) {
|
|
|
|
hpdata_t hpdata;
|
|
|
|
hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
|
|
|
|
|
|
|
|
void *alloc = hpdata_reserve_alloc(&hpdata, HUGEPAGE_PAGES / 2 * PAGE);
|
|
|
|
expect_ptr_eq(alloc, HPDATA_ADDR, "");
|
|
|
|
|
|
|
|
/* Create HUGEPAGE_PAGES / 4 dirty inactive pages at the beginning. */
|
|
|
|
hpdata_unreserve(&hpdata, alloc, HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
|
2020-12-04 10:58:58 +08:00
|
|
|
expect_zu_eq(hpdata_ntouched_get(&hpdata), HUGEPAGE_PAGES / 2, "");
|
2020-12-03 10:44:34 +08:00
|
|
|
|
2021-06-04 04:29:02 +08:00
|
|
|
hpdata_alloc_allowed_set(&hpdata, false);
|
2020-12-03 10:44:34 +08:00
|
|
|
hpdata_purge_state_t purge_state;
|
2020-12-07 05:16:51 +08:00
|
|
|
size_t to_purge = hpdata_purge_begin(&hpdata, &purge_state);
|
|
|
|
expect_zu_eq(HUGEPAGE_PAGES / 4, to_purge, "");
|
2020-12-03 10:44:34 +08:00
|
|
|
|
|
|
|
void *purge_addr;
|
|
|
|
size_t purge_size;
|
|
|
|
bool got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
|
|
|
|
&purge_size);
|
|
|
|
expect_true(got_result, "");
|
|
|
|
expect_ptr_eq(HPDATA_ADDR, purge_addr, "");
|
|
|
|
expect_zu_eq(HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
|
|
|
|
|
|
|
|
got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
|
|
|
|
&purge_size);
|
|
|
|
expect_false(got_result, "Unexpected additional purge range: "
|
|
|
|
"extent at %p of size %zu", purge_addr, purge_size);
|
|
|
|
|
|
|
|
hpdata_purge_end(&hpdata, &purge_state);
|
2020-12-04 10:58:58 +08:00
|
|
|
expect_zu_eq(hpdata_ntouched_get(&hpdata), HUGEPAGE_PAGES / 4, "");
|
2020-12-03 10:44:34 +08:00
|
|
|
}
|
|
|
|
TEST_END
|
|
|
|
|
|
|
|
/*
|
2021-06-04 04:29:02 +08:00
|
|
|
* We only test intervening dalloc's not intervening allocs; the latter are
|
|
|
|
* disallowed as a purging precondition (because they interfere with purging
|
|
|
|
* across a retained extent, saving a purge call).
|
2020-12-03 10:44:34 +08:00
|
|
|
*/
|
|
|
|
TEST_BEGIN(test_purge_intervening_dalloc) {
|
|
|
|
hpdata_t hpdata;
|
|
|
|
hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
|
|
|
|
|
|
|
|
/* Allocate the first 3/4 of the pages. */
|
|
|
|
void *alloc = hpdata_reserve_alloc(&hpdata, 3 * HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
expect_ptr_eq(alloc, HPDATA_ADDR, "");
|
|
|
|
|
|
|
|
/* Free the first 1/4 and the third 1/4 of the pages. */
|
|
|
|
hpdata_unreserve(&hpdata, alloc, HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
hpdata_unreserve(&hpdata,
|
|
|
|
(void *)((uintptr_t)alloc + 2 * HUGEPAGE_PAGES / 4 * PAGE),
|
|
|
|
HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
|
2020-12-04 10:58:58 +08:00
|
|
|
expect_zu_eq(hpdata_ntouched_get(&hpdata), 3 * HUGEPAGE_PAGES / 4, "");
|
2020-12-03 10:44:34 +08:00
|
|
|
|
2021-06-04 04:29:02 +08:00
|
|
|
hpdata_alloc_allowed_set(&hpdata, false);
|
2020-12-03 10:44:34 +08:00
|
|
|
hpdata_purge_state_t purge_state;
|
2020-12-07 05:16:51 +08:00
|
|
|
size_t to_purge = hpdata_purge_begin(&hpdata, &purge_state);
|
|
|
|
expect_zu_eq(HUGEPAGE_PAGES / 2, to_purge, "");
|
2020-12-03 10:44:34 +08:00
|
|
|
|
|
|
|
void *purge_addr;
|
|
|
|
size_t purge_size;
|
|
|
|
/* First purge. */
|
|
|
|
bool got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
|
|
|
|
&purge_size);
|
|
|
|
expect_true(got_result, "");
|
|
|
|
expect_ptr_eq(HPDATA_ADDR, purge_addr, "");
|
|
|
|
expect_zu_eq(HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
|
|
|
|
|
|
|
|
/* Deallocate the second 1/4 before the second purge occurs. */
|
|
|
|
hpdata_unreserve(&hpdata,
|
|
|
|
(void *)((uintptr_t)alloc + 1 * HUGEPAGE_PAGES / 4 * PAGE),
|
|
|
|
HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
|
|
|
|
/* Now continue purging. */
|
|
|
|
got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
|
|
|
|
&purge_size);
|
|
|
|
expect_true(got_result, "");
|
|
|
|
expect_ptr_eq(
|
|
|
|
(void *)((uintptr_t)alloc + 2 * HUGEPAGE_PAGES / 4 * PAGE),
|
|
|
|
purge_addr, "");
|
2021-06-04 04:29:02 +08:00
|
|
|
expect_zu_ge(HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
|
2020-12-03 10:44:34 +08:00
|
|
|
|
|
|
|
got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
|
|
|
|
&purge_size);
|
|
|
|
expect_false(got_result, "Unexpected additional purge range: "
|
|
|
|
"extent at %p of size %zu", purge_addr, purge_size);
|
|
|
|
|
|
|
|
hpdata_purge_end(&hpdata, &purge_state);
|
|
|
|
|
2020-12-04 10:58:58 +08:00
|
|
|
expect_zu_eq(hpdata_ntouched_get(&hpdata), HUGEPAGE_PAGES / 4, "");
|
2020-12-03 10:44:34 +08:00
|
|
|
}
|
|
|
|
TEST_END
|
|
|
|
|
2021-06-04 04:29:02 +08:00
|
|
|
TEST_BEGIN(test_purge_over_retained) {
|
|
|
|
void *purge_addr;
|
|
|
|
size_t purge_size;
|
|
|
|
|
|
|
|
hpdata_t hpdata;
|
|
|
|
hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
|
|
|
|
|
|
|
|
/* Allocate the first 3/4 of the pages. */
|
|
|
|
void *alloc = hpdata_reserve_alloc(&hpdata, 3 * HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
expect_ptr_eq(alloc, HPDATA_ADDR, "");
|
|
|
|
|
|
|
|
/* Free the second quarter. */
|
|
|
|
void *second_quarter =
|
|
|
|
(void *)((uintptr_t)alloc + HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
hpdata_unreserve(&hpdata, second_quarter, HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
|
|
|
|
expect_zu_eq(hpdata_ntouched_get(&hpdata), 3 * HUGEPAGE_PAGES / 4, "");
|
|
|
|
|
|
|
|
/* Purge the second quarter. */
|
|
|
|
hpdata_alloc_allowed_set(&hpdata, false);
|
|
|
|
hpdata_purge_state_t purge_state;
|
|
|
|
size_t to_purge_dirty = hpdata_purge_begin(&hpdata, &purge_state);
|
|
|
|
expect_zu_eq(HUGEPAGE_PAGES / 4, to_purge_dirty, "");
|
|
|
|
|
|
|
|
bool got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
|
|
|
|
&purge_size);
|
|
|
|
expect_true(got_result, "");
|
|
|
|
expect_ptr_eq(second_quarter, purge_addr, "");
|
|
|
|
expect_zu_eq(HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
|
|
|
|
|
|
|
|
got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
|
|
|
|
&purge_size);
|
|
|
|
expect_false(got_result, "Unexpected additional purge range: "
|
|
|
|
"extent at %p of size %zu", purge_addr, purge_size);
|
|
|
|
hpdata_purge_end(&hpdata, &purge_state);
|
|
|
|
|
|
|
|
expect_zu_eq(hpdata_ntouched_get(&hpdata), HUGEPAGE_PAGES / 2, "");
|
|
|
|
|
|
|
|
/* Free the first and third quarter. */
|
|
|
|
hpdata_unreserve(&hpdata, HPDATA_ADDR, HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
hpdata_unreserve(&hpdata,
|
|
|
|
(void *)((uintptr_t)alloc + 2 * HUGEPAGE_PAGES / 4 * PAGE),
|
|
|
|
HUGEPAGE_PAGES / 4 * PAGE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Purge again. The second quarter is retained, so we can safely
|
|
|
|
* re-purge it. We expect a single purge of 3/4 of the hugepage,
|
|
|
|
* purging half its pages.
|
|
|
|
*/
|
|
|
|
to_purge_dirty = hpdata_purge_begin(&hpdata, &purge_state);
|
|
|
|
expect_zu_eq(HUGEPAGE_PAGES / 2, to_purge_dirty, "");
|
|
|
|
|
|
|
|
got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
|
|
|
|
&purge_size);
|
|
|
|
expect_true(got_result, "");
|
|
|
|
expect_ptr_eq(HPDATA_ADDR, purge_addr, "");
|
|
|
|
expect_zu_eq(3 * HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
|
|
|
|
|
|
|
|
got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
|
|
|
|
&purge_size);
|
|
|
|
expect_false(got_result, "Unexpected additional purge range: "
|
|
|
|
"extent at %p of size %zu", purge_addr, purge_size);
|
|
|
|
hpdata_purge_end(&hpdata, &purge_state);
|
|
|
|
|
|
|
|
expect_zu_eq(hpdata_ntouched_get(&hpdata), 0, "");
|
|
|
|
}
|
|
|
|
TEST_END
|
|
|
|
|
2020-12-03 10:44:34 +08:00
|
|
|
TEST_BEGIN(test_hugify) {
|
|
|
|
hpdata_t hpdata;
|
|
|
|
hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
|
|
|
|
|
|
|
|
void *alloc = hpdata_reserve_alloc(&hpdata, HUGEPAGE / 2);
|
|
|
|
expect_ptr_eq(alloc, HPDATA_ADDR, "");
|
|
|
|
|
2020-12-04 10:58:58 +08:00
|
|
|
expect_zu_eq(HUGEPAGE_PAGES / 2, hpdata_ntouched_get(&hpdata), "");
|
2020-12-03 10:44:34 +08:00
|
|
|
|
2020-12-07 01:49:26 +08:00
|
|
|
hpdata_hugify(&hpdata);
|
2020-12-03 10:44:34 +08:00
|
|
|
|
|
|
|
/* Hugeifying should have increased the dirty page count. */
|
2020-12-04 10:58:58 +08:00
|
|
|
expect_zu_eq(HUGEPAGE_PAGES, hpdata_ntouched_get(&hpdata), "");
|
2020-12-03 10:44:34 +08:00
|
|
|
}
|
|
|
|
TEST_END
|
|
|
|
|
2020-12-02 23:04:01 +08:00
|
|
|
int main(void) {
|
|
|
|
return test_no_reentrancy(
|
2020-12-03 10:44:34 +08:00
|
|
|
test_reserve_alloc,
|
|
|
|
test_purge_simple,
|
|
|
|
test_purge_intervening_dalloc,
|
2021-06-04 04:29:02 +08:00
|
|
|
test_purge_over_retained,
|
2020-12-03 10:44:34 +08:00
|
|
|
test_hugify);
|
2020-12-02 23:04:01 +08:00
|
|
|
}
|