456b313665
## Issue Addressed NA ## Proposed Changes Modify the configuration of [GNU malloc](https://www.gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html) to reduce memory footprint. - Set `M_ARENA_MAX` to 4. - This reduces memory fragmentation at the cost of contention between threads. - Set `M_MMAP_THRESHOLD` to 2mb - This means that any allocation >= 2mb is allocated via an anonymous mmap, instead of on the heap/arena. This reduces memory fragmentation since we don't need to keep growing the heap to find big contiguous slabs of free memory. - ~~Run `malloc_trim` every 60 seconds.~~ - ~~This shaves unused memory from the top of the heap, preventing the heap from constantly growing.~~ - Removed, see: https://github.com/sigp/lighthouse/pull/2299#issuecomment-825322646 *Note: this only provides memory savings on the Linux (glibc) platform.* ## Additional Info I'm going to close #2288 in favor of this for the following reasons: - I've managed to get the memory footprint *smaller* here than with jemalloc. - This PR seems to be less of a dramatic change than bringing in the jemalloc dep. - The changes in this PR are strictly runtime changes, so we can create CLI flags which disable them completely. Since this change is wide-reaching and complex, it's nice to have an easy "escape hatch" if there are undesired consequences. ## TODO - [x] Allow configuration via CLI flags - [x] Test on Mac - [x] Test on RasPi. - [x] Determine if GNU malloc is present? - I'm not quite sure how to detect for glibc.. This issue suggests we can't really: https://github.com/rust-lang/rust/issues/33244 - [x] Make a clear argument regarding the affect of this on CPU utilization. - [x] Test with higher `M_ARENA_MAX` values. - [x] Test with longer trim intervals - [x] Add some stats about memory savings - [x] Remove `malloc_trim` calls & code
48 lines
1.6 KiB
Rust
48 lines
1.6 KiB
Rust
//! Provides utilities for configuring the system allocator.
|
|
//!
|
|
//! ## Conditional Compilation
|
|
//!
|
|
//! Presently, only configuration for "The GNU Allocator" from `glibc` is supported. All other
|
|
//! allocators are ignored.
|
|
//!
|
|
//! It is assumed that if the following two statements are correct then we should expect to
|
|
//! configure `glibc`:
|
|
//!
|
|
//! - `target_os = linux`
|
|
//! - `target_env != musl`
|
|
//!
|
|
//! In all other cases this library will not attempt to do anything (i.e., all functions are
|
|
//! no-ops).
|
|
//!
|
|
//! If the above conditions are fulfilled but `glibc` still isn't present at runtime then a panic
|
|
//! may be triggered. It is understood that there's no way to be certain that a compatible `glibc`
|
|
//! is present: https://github.com/rust-lang/rust/issues/33244.
|
|
//!
|
|
//! ## Notes
|
|
//!
|
|
//! It's not clear how to precisely determine what the underlying allocator is. The efforts at
|
|
//! detecting `glibc` are best-effort. If this crate throws errors about undefined external
|
|
//! functions, then try to compile with the `not_glibc_interface` module.
|
|
|
|
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
|
|
mod glibc;
|
|
|
|
pub use interface::*;
|
|
|
|
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
|
|
mod interface {
|
|
pub use crate::glibc::configure_glibc_malloc as configure_memory_allocator;
|
|
pub use crate::glibc::scrape_mallinfo_metrics as scrape_allocator_metrics;
|
|
}
|
|
|
|
#[cfg(any(not(target_os = "linux"), target_env = "musl"))]
|
|
mod interface {
|
|
#[allow(dead_code, clippy::unnecessary_wraps)]
|
|
pub fn configure_memory_allocator() -> Result<(), String> {
|
|
Ok(())
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub fn scrape_allocator_metrics() {}
|
|
}
|