mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-08 09:16:00 +00:00
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:
@@ -46,6 +46,7 @@ lighthouse_metrics = { path = "../common/lighthouse_metrics" }
|
||||
lazy_static = "1.4.0"
|
||||
serde_json = "1.0.59"
|
||||
task_executor = { path = "../common/task_executor" }
|
||||
malloc_utils = { path = "../common/malloc_utils" }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -800,6 +800,15 @@ fn slasher_broadcast_flag() {
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
pub fn malloc_tuning_flag() {
|
||||
CommandLineTest::new()
|
||||
.flag("disable-malloc-tuning", None)
|
||||
.run()
|
||||
.with_config(|config| {
|
||||
assert!(!config.http_metrics.allocator_metrics_enabled);
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn ensure_panic_on_failed_launch() {
|
||||
CommandLineTest::new()
|
||||
|
||||
@@ -344,3 +344,11 @@ fn metrics_allow_origin_all_flag() {
|
||||
.run()
|
||||
.with_config(|config| assert_eq!(config.http_metrics.allow_origin, Some("*".to_string())));
|
||||
}
|
||||
#[test]
|
||||
pub fn malloc_tuning_flag() {
|
||||
CommandLineTest::new()
|
||||
.flag("disable-malloc-tuning", None)
|
||||
// Simply ensure that the node can start with this flag, it's very difficult to observe the
|
||||
// effects of it.
|
||||
.run();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user