Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace purges_old_accounts by a boolean field in CleaningInfo #2566

Merged
merged 6 commits into from
Aug 14, 2024

Conversation

dmakarov
Copy link

@dmakarov dmakarov commented Aug 12, 2024

Problem

Cleaning empty accounts from accounts index uses a lot of memory by copying large amounts of data.

Summary of Changes

Further reduce memory use in clean_accounts by keeping information about cleaning candidates in a single data structure instead of copying it to multiple containers. This PR removes purges_old_accounts vector and replaces it with a boolean field should_purge in CleaningInfo structure.

@dmakarov dmakarov marked this pull request as ready for review August 12, 2024 22:37
accounts-db/src/accounts_db.rs Outdated Show resolved Hide resolved
accounts-db/src/accounts_db.rs Outdated Show resolved Hide resolved
brooksprumo
brooksprumo previously approved these changes Aug 13, 2024
Copy link

@brooksprumo brooksprumo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

Removing the separate purges_old_accounts vec in favor of tracking purgeables within the candidates info looks good to me.

Comment on lines +2718 to +2720
let reclaim_vecs = candidates
.par_iter()
.filter_map(|candidates_bin| {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:chefs-kiss:

max_clean_root_inclusive: Option<Slot>,
ancient_account_cleans: &AtomicU64,
epoch_schedule: &EpochSchedule,
) -> (ReclaimResult, PubkeysRemovedFromAccountsIndex) {
let pubkeys_removed_from_accounts_index = HashSet::default();
if purges.is_empty() {
// return early if there are no old accounts to purge
if !candidates
Copy link

@jeffwashington jeffwashington Aug 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be very expensive and I think will scan all bins every time. I'd prefer to see a bool set at the caller that knows if there were any should_purge accounts. You could set a local atomic in the index scan in the calling fn if any account is set to should_purge. That could be passed to this fn or this fn could just assume that there is at least one should_purge entry if it is called with candidates. This first check is really just a cya to make sure that we know the behavior if there are no should_purge accounts. So, we could probably get rid of it in any case if we are careful of what the resulting behavior would be. I acknowledge that this code is a correct drop in replacement for purges before.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the check to the caller and used an atomic bool to record whether any purgeable candidate exists.

@jeffwashington
Copy link

Yes! I love this. ty!

accounts-db/src/accounts_db.rs Outdated Show resolved Hide resolved
accounts-db/src/accounts_db.rs Outdated Show resolved Hide resolved
let mut not_found_on_fork = 0;
let mut missing = 0;
let mut useful = 0;
let mut exist_purgeable_accounts_local = false;
Copy link

@jeffwashington jeffwashington Aug 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry to go round and round. Let's simplify this. In practice, there are ALWAYS a non zero # of accounts to clean.
image

so, no need to check. Just always call the fn. And make sure it handles no accounts, but that is easy to do on inspection.
btw, this graph is min, so there are never 0 entries.

Copy link
Author

@dmakarov dmakarov Aug 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the check. From what I can tell the function should return empty ReclaimResult and an empty HashSet for pubkeys_removed_from_accounts_index if there were no purgeable accounts.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i read through it as well. it appears as if it will do the right thing.

@jeffwashington jeffwashington self-requested a review August 13, 2024 16:53
@brooksprumo brooksprumo self-requested a review August 13, 2024 17:06
Copy link

@brooksprumo brooksprumo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

Copy link

@jeffwashington jeffwashington left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. I'm not detecting a reduction in memory allocation, which surprises me.

here is mem vs ledger tool. the red boxes are when clean is active.
image

in bottom, red is prior to this change (I think), blue is this change.
we max out at 252GB.

@dmakarov
Copy link
Author

lgtm. I'm not detecting a reduction in memory allocation, which surprises me.

We added 4 bytes (a bool) for every candidate, which I guess are in millions, maybe? If purges_old_accounts were less than 1/8 of all candidates (32-byte pubkey v. 4-byte boolean field) we might increase memory use, not reduce it. It still may be better to use the field than to copy many pubkeys. I can add another stats number, number of purges_old_accounts, and see how many there are versus total number of candidates.

@jeffwashington
Copy link

We added 4 bytes (a bool) for every candidate

yep, I thought about the 4 bytes. i expected a different curve. doesn't mean this is right or wrong - just surprising.

@jeffwashington
Copy link

I can add another stats number, number of purges_old_accounts, and see how many there are versus total number of candidates.

I think this is a good idea anyway.

@jeffwashington
Copy link

I can add another stats number, number of purges_old_accounts, and see how many there are versus total number of candidates.

I think this is a good idea anyway.

do this separately. this pr is ready imo

@jeffwashington
Copy link

do this separately. this pr is ready imo

unless we can think of a clever way to store the bit in what we're already storing.

@dmakarov
Copy link
Author

do this separately. this pr is ready imo

unless we can think of a clever way to store the bit in what we're already storing.

Let's merge this for now, and I'll think how it might be improved.

Copy link

@HaoranYi HaoranYi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the idea.
lgtm!

@dmakarov dmakarov merged commit e2b7d0f into anza-xyz:master Aug 14, 2024
39 of 41 checks passed
@dmakarov dmakarov deleted the oom branch August 14, 2024 13:18
ray-kast pushed a commit to abklabs/agave that referenced this pull request Nov 27, 2024
…xyz#2566)

* Replace purges_old_accounts by a boolean field in CleaningInfo

* comments

* Move check for purgeable accounts existence to caller

* Corrections to Atomic

* correction.

* Remove checks for no-existent purge old accounts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants