-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Only keep track of recently used stacks in memory. #2591
base: staging
Are you sure you want to change the base?
Conversation
This should - as far as we know - eliminate unbounded memory growth. To avoid memory leaks, we only evict "root" stacks from the cache.
6c990e8
to
44fc174
Compare
Co-authored-by: ljedrz <[email protected]> Signed-off-by: vicsn <[email protected]>
Co-authored-by: ljedrz <[email protected]> Signed-off-by: vicsn <[email protected]>
Co-authored-by: ljedrz <[email protected]> Signed-off-by: vicsn <[email protected]>
let credits_id = self | ||
.credits | ||
.as_ref() | ||
.map_or(ProgramID::<N>::from_str("credits.aleo").unwrap(), |stack| *stack.program_id()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.map_or(ProgramID::<N>::from_str("credits.aleo").unwrap(), |stack| *stack.program_id()); | |
.map_or_else(|| ProgramID::<N>::from_str("credits.aleo").unwrap(), |stack| *stack.program_id()); |
(to avoid eager evaluation)
let programs_to_add = programs_to_add | ||
.into_iter() | ||
.chain(std::iter::once((*stack.program_id(), stack))) // add the root stack. | ||
.unique_by(|(id, _)|*id) // don't add duplicates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.unique_by(|(id, _)|*id) // don't add duplicates. | |
.unique_by(|(id, _)| *id) // don't add duplicates. |
tiny nit, rustfmt
might have missed it
let mut process = Self { | ||
universal_srs: Arc::new(UniversalSRS::load()?), | ||
credits: None, | ||
stacks: Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(N::MAX_STACKS).unwrap()))), | ||
store: None, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mut process = Self { | |
universal_srs: Arc::new(UniversalSRS::load()?), | |
credits: None, | |
stacks: Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(N::MAX_STACKS).unwrap()))), | |
store: None, | |
}; | |
let mut process = Self::load_no_storage()?; |
let mut process = Self { | ||
universal_srs: Arc::new(UniversalSRS::load()?), | ||
credits: None, | ||
stacks: Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(N::MAX_STACKS).unwrap()))), | ||
store: Some(store), | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mut process = Self { | |
universal_srs: Arc::new(UniversalSRS::load()?), | |
credits: None, | |
stacks: Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(N::MAX_STACKS).unwrap()))), | |
store: Some(store), | |
}; | |
let mut process = Self::load_no_storage()?; | |
process.store = Some(store); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2nd review pass complete, left a few comments; also, it seems like one of the new tests is currently failing.
Motivation
RSS growth is correlated with deployments. By lazy loading deployments, hopefully unbounded memory growth is eliminated.
The cache will take up at most MAX_PROGRAM_DEPTH x MAX_IMPORTS x 100kb x 10 ~= 4GB of data.
Note that programs, represented as
Stack
s, have imports. This means the cache is essentially a DAG with multiple roots. To avoid memory leaks, we only evict root stacks from the cache. In the following diagram, you can see in the call graph below where the cache is (temporarily) locked and updated. The "long" loop has some nasty edge cases, it would be better to pass all imports directly intoload_deployment
andStack::new
, but that would be a much bigger refactor.Test Plan
test_real_example_cache_evict
test.Related PRs
#2519
#2553
#2578