Tune GNU malloc (#2299)

## 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
This commit is contained in:
Paul Hauner
2021-05-28 05:59:45 +00:00
parent fdaeec631b
commit 456b313665
16 changed files with 350 additions and 1 deletions

View File

@@ -2,10 +2,12 @@ mod metrics;
use beacon_node::{get_eth2_network_config, ProductionBeaconNode};
use clap::{App, Arg, ArgMatches};
use clap_utils::flags::DISABLE_MALLOC_TUNING_FLAG;
use env_logger::{Builder, Env};
use environment::EnvironmentBuilder;
use eth2_network_config::{Eth2NetworkConfig, DEFAULT_HARDCODED_NETWORK};
use lighthouse_version::VERSION;
use malloc_utils::configure_memory_allocator;
use slog::{crit, info, warn};
use std::fs::File;
use std::path::PathBuf;
@@ -144,6 +146,16 @@ fn main() {
Used for testing only, DO NOT USE IN PRODUCTION.")
.global(true)
)
.arg(
Arg::with_name(DISABLE_MALLOC_TUNING_FLAG)
.long(DISABLE_MALLOC_TUNING_FLAG)
.help(
"If present, do not configure the system allocator. Providing this flag will \
generally increase memory usage, it should only be provided when debugging \
specific memory allocation issues."
)
.global(true),
)
.subcommand(beacon_node::cli_app())
.subcommand(boot_node::cli_app())
.subcommand(validator_client::cli_app())
@@ -151,6 +163,19 @@ fn main() {
.subcommand(remote_signer::cli_app())
.get_matches();
// Configure the allocator early in the process, before it has the chance to use the default values for
// anything important.
if !matches.is_present(DISABLE_MALLOC_TUNING_FLAG) {
if let Err(e) = configure_memory_allocator() {
eprintln!(
"Unable to configure the memory allocator: {} \n\
Try providing the --{} flag",
e, DISABLE_MALLOC_TUNING_FLAG
);
exit(1)
}
}
// Debugging output for libp2p and external crates.
if matches.is_present("env_log") {
Builder::from_env(Env::default()).init();