Add output argument to hpa_purge_begin to count dirty ranges

This commit is contained in:
Slobodan Predolac
2025-04-08 10:49:05 -07:00
committed by Qi Wang
parent cfa90dfd80
commit 0dfb4a5a1a
5 changed files with 27 additions and 9 deletions

View File

@@ -395,9 +395,11 @@ struct hpdata_purge_state_s {
* until you're done, and then end. Allocating out of an hpdata undergoing * until you're done, and then end. Allocating out of an hpdata undergoing
* purging is not allowed. * purging is not allowed.
* *
* Returns the number of dirty pages that will be purged. * Returns the number of dirty pages that will be purged and sets nranges
* to number of ranges with dirty pages that will be purged.
*/ */
size_t hpdata_purge_begin(hpdata_t *hpdata, hpdata_purge_state_t *purge_state); size_t hpdata_purge_begin(hpdata_t *hpdata, hpdata_purge_state_t *purge_state,
size_t *nranges);
/* /*
* If there are more extents to purge, sets *r_purge_addr and *r_purge_size to * If there are more extents to purge, sets *r_purge_addr and *r_purge_size to

View File

@@ -465,8 +465,10 @@ hpa_try_purge(tsdn_t *tsdn, hpa_shard_t *shard) {
/* Gather all the metadata we'll need during the purge. */ /* Gather all the metadata we'll need during the purge. */
bool dehugify = hpdata_huge_get(to_purge); bool dehugify = hpdata_huge_get(to_purge);
size_t nranges;
hpdata_purge_state_t purge_state; hpdata_purge_state_t purge_state;
size_t num_to_purge = hpdata_purge_begin(to_purge, &purge_state); size_t num_to_purge = hpdata_purge_begin(to_purge, &purge_state, &nranges);
(void) nranges; /*not used yet */
shard->npending_purge += num_to_purge; shard->npending_purge += num_to_purge;

View File

@@ -164,7 +164,8 @@ hpdata_unreserve(hpdata_t *hpdata, void *addr, size_t sz) {
} }
size_t size_t
hpdata_purge_begin(hpdata_t *hpdata, hpdata_purge_state_t *purge_state) { hpdata_purge_begin(hpdata_t *hpdata, hpdata_purge_state_t *purge_state,
size_t *nranges) {
hpdata_assert_consistent(hpdata); hpdata_assert_consistent(hpdata);
/* /*
* See the comment below; we might purge any inactive extent, so it's * See the comment below; we might purge any inactive extent, so it's
@@ -216,6 +217,7 @@ hpdata_purge_begin(hpdata_t *hpdata, hpdata_purge_state_t *purge_state) {
fb_init(purge_state->to_purge, HUGEPAGE_PAGES); fb_init(purge_state->to_purge, HUGEPAGE_PAGES);
size_t next_bit = 0; size_t next_bit = 0;
*nranges = 0;
while (next_bit < HUGEPAGE_PAGES) { while (next_bit < HUGEPAGE_PAGES) {
size_t next_dirty = fb_ffs(dirty_pages, HUGEPAGE_PAGES, size_t next_dirty = fb_ffs(dirty_pages, HUGEPAGE_PAGES,
next_bit); next_bit);
@@ -239,6 +241,7 @@ hpdata_purge_begin(hpdata_t *hpdata, hpdata_purge_state_t *purge_state) {
fb_set_range(purge_state->to_purge, HUGEPAGE_PAGES, next_dirty, fb_set_range(purge_state->to_purge, HUGEPAGE_PAGES, next_dirty,
last_dirty - next_dirty + 1); last_dirty - next_dirty + 1);
(*nranges)++;
next_bit = next_active + 1; next_bit = next_active + 1;
} }
@@ -249,6 +252,8 @@ hpdata_purge_begin(hpdata_t *hpdata, hpdata_purge_state_t *purge_state) {
purge_state->to_purge, HUGEPAGE_PAGES, 0, HUGEPAGE_PAGES)); purge_state->to_purge, HUGEPAGE_PAGES, 0, HUGEPAGE_PAGES));
assert(ndirty == fb_scount(dirty_pages, HUGEPAGE_PAGES, 0, assert(ndirty == fb_scount(dirty_pages, HUGEPAGE_PAGES, 0,
HUGEPAGE_PAGES)); HUGEPAGE_PAGES));
assert(*nranges <= ndirty);
assert(ndirty == 0 || *nranges > 0);
hpdata_assert_consistent(hpdata); hpdata_assert_consistent(hpdata);

View File

@@ -69,8 +69,10 @@ TEST_BEGIN(test_purge_simple) {
hpdata_alloc_allowed_set(&hpdata, false); hpdata_alloc_allowed_set(&hpdata, false);
hpdata_purge_state_t purge_state; hpdata_purge_state_t purge_state;
size_t to_purge = hpdata_purge_begin(&hpdata, &purge_state); size_t nranges;
size_t to_purge = hpdata_purge_begin(&hpdata, &purge_state, &nranges);
expect_zu_eq(HUGEPAGE_PAGES / 4, to_purge, ""); expect_zu_eq(HUGEPAGE_PAGES / 4, to_purge, "");
expect_zu_eq(1, nranges, "All dirty pages in a single range");
void *purge_addr; void *purge_addr;
size_t purge_size; size_t purge_size;
@@ -113,8 +115,10 @@ TEST_BEGIN(test_purge_intervening_dalloc) {
hpdata_alloc_allowed_set(&hpdata, false); hpdata_alloc_allowed_set(&hpdata, false);
hpdata_purge_state_t purge_state; hpdata_purge_state_t purge_state;
size_t to_purge = hpdata_purge_begin(&hpdata, &purge_state); size_t nranges;
size_t to_purge = hpdata_purge_begin(&hpdata, &purge_state, &nranges);
expect_zu_eq(HUGEPAGE_PAGES / 2, to_purge, ""); expect_zu_eq(HUGEPAGE_PAGES / 2, to_purge, "");
expect_zu_eq(2, nranges, "First quarter and last half");
void *purge_addr; void *purge_addr;
size_t purge_size; size_t purge_size;
@@ -171,8 +175,10 @@ TEST_BEGIN(test_purge_over_retained) {
/* Purge the second quarter. */ /* Purge the second quarter. */
hpdata_alloc_allowed_set(&hpdata, false); hpdata_alloc_allowed_set(&hpdata, false);
hpdata_purge_state_t purge_state; hpdata_purge_state_t purge_state;
size_t to_purge_dirty = hpdata_purge_begin(&hpdata, &purge_state); size_t nranges;
size_t to_purge_dirty = hpdata_purge_begin(&hpdata, &purge_state, &nranges);
expect_zu_eq(HUGEPAGE_PAGES / 4, to_purge_dirty, ""); expect_zu_eq(HUGEPAGE_PAGES / 4, to_purge_dirty, "");
expect_zu_eq(1, nranges, "Second quarter only");
bool got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr, bool got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
&purge_size); &purge_size);
@@ -199,8 +205,9 @@ TEST_BEGIN(test_purge_over_retained) {
* re-purge it. We expect a single purge of 3/4 of the hugepage, * re-purge it. We expect a single purge of 3/4 of the hugepage,
* purging half its pages. * purging half its pages.
*/ */
to_purge_dirty = hpdata_purge_begin(&hpdata, &purge_state); to_purge_dirty = hpdata_purge_begin(&hpdata, &purge_state, &nranges);
expect_zu_eq(HUGEPAGE_PAGES / 2, to_purge_dirty, ""); expect_zu_eq(HUGEPAGE_PAGES / 2, to_purge_dirty, "");
expect_zu_eq(1, nranges, "Single range expected");
got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr, got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
&purge_size); &purge_size);

View File

@@ -19,7 +19,9 @@ static void
test_psset_fake_purge(hpdata_t *ps) { test_psset_fake_purge(hpdata_t *ps) {
hpdata_purge_state_t purge_state; hpdata_purge_state_t purge_state;
hpdata_alloc_allowed_set(ps, false); hpdata_alloc_allowed_set(ps, false);
hpdata_purge_begin(ps, &purge_state); size_t nranges;
hpdata_purge_begin(ps, &purge_state, &nranges);
(void) nranges;
void *addr; void *addr;
size_t size; size_t size;
while (hpdata_purge_next(ps, &purge_state, &addr, &size)) { while (hpdata_purge_next(ps, &purge_state, &addr, &size)) {