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

Use jemalloc by default #2288

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ perf.data*
*.tar.gz
/bin
genesis.ssz
jeprof*
63 changes: 63 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,6 @@ eth2_ssz = { path = "consensus/ssz" }
eth2_ssz_derive = { path = "consensus/ssz_derive" }
eth2_ssz_types = { path = "consensus/ssz_types" }
eth2_hashing = { path = "crypto/eth2_hashing" }

#[profile.release]
# debug = true
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@ BUILD_PATH_AARCH64 = "target/$(AARCH64_TAG)/release"

PINNED_NIGHTLY ?= nightly

ifeq ($(PROFILING), true)
PROFILING_FEATURE=jemalloc-profiling
else
PROFILING_FEATURE=
endif

# Builds the Lighthouse binary in release (optimized).
#
# Binaries will most likely be found in `./target/release`
install:
ifeq ($(PORTABLE), true)
cargo install --path lighthouse --force --locked --features portable
cargo install --path lighthouse --force --locked --features $(PROFILING_FEATURE),portable
else
cargo install --path lighthouse --force --locked
cargo install --path lighthouse --force --locked --features $(PROFILING_FEATURE)
endif

# Builds the lcli binary in release (optimized).
Expand Down
2 changes: 2 additions & 0 deletions beacon_node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ node_test_rig = { path = "../testing/node_test_rig" }

[features]
write_ssz_files = ["beacon_chain/write_ssz_files"] # Writes debugging .ssz files to /tmp during block processing.
# Use the system allocator instead of jemalloc. This replicates default Rust behaviour.
sysalloc = ["client/sysalloc"]

[dependencies]
eth2_config = { path = "../common/eth2_config" }
Expand Down
12 changes: 8 additions & 4 deletions beacon_node/beacon_chain/src/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,15 +690,14 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
/// Returns an error if the block is invalid, or if the block was unable to be verified.
pub fn new(
block: SignedBeaconBlock<T::EthSpec>,
block_root: Hash256,
chain: &BeaconChain<T>,
) -> Result<Self, BlockError<T::EthSpec>> {
let (mut parent, block) = load_parent(block, chain)?;

// Reject any block that exceeds our limit on skipped slots.
check_block_skip_slots(chain, parent.beacon_block.slot(), &block.message)?;

let block_root = get_block_root(&block);

let state = cheap_state_advance_to_obtain_committees(
&mut parent.pre_state,
parent.beacon_state_root,
Expand Down Expand Up @@ -726,10 +725,11 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
/// As for `new` above but producing `BlockSlashInfo`.
pub fn check_slashable(
block: SignedBeaconBlock<T::EthSpec>,
block_root: Hash256,
chain: &BeaconChain<T>,
) -> Result<Self, BlockSlashInfo<BlockError<T::EthSpec>>> {
let header = block.signed_block_header();
Self::new(block, chain).map_err(|e| BlockSlashInfo::from_early_error(header, e))
Self::new(block, block_root, chain).map_err(|e| BlockSlashInfo::from_early_error(header, e))
}

/// Finishes signature verification on the provided `GossipVerifedBlock`. Does not re-verify
Expand Down Expand Up @@ -814,7 +814,11 @@ impl<T: BeaconChainTypes> IntoFullyVerifiedBlock<T> for SignedBeaconBlock<T::Eth
self,
chain: &BeaconChain<T>,
) -> Result<FullyVerifiedBlock<T>, BlockSlashInfo<BlockError<T::EthSpec>>> {
SignatureVerifiedBlock::check_slashable(self, chain)?
// Perform an early check to prevent wasting time on irrelevant blocks.
let block_root = check_block_relevancy(&self, None, chain)
.map_err(|e| BlockSlashInfo::SignatureValid(self.signed_block_header(), e))?;

SignatureVerifiedBlock::check_slashable(self, block_root, chain)?
.into_fully_verified_block_slashable(chain)
}

Expand Down
4 changes: 4 additions & 0 deletions beacon_node/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ http_api = { path = "../http_api" }
http_metrics = { path = "../http_metrics" }
slasher = { path = "../../slasher" }
slasher_service = { path = "../../slasher/service" }

[features]
# Use the system allocator instead of jemalloc. This replicates default Rust behaviour.
sysalloc = ["http_metrics/sysalloc"]
6 changes: 6 additions & 0 deletions beacon_node/http_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ version = "0.1.0"
authors = ["Paul Hauner <[email protected]>"]
edition = "2018"

[features]
# Use the system allocator instead of jemalloc. This replicates default Rust behaviour.
sysalloc = []

[dependencies]
warp = { git = "https://github.com/paulhauner/warp ", branch = "cors-wildcard" }
serde = { version = "1.0.116", features = ["derive"] }
Expand All @@ -29,6 +33,8 @@ slot_clock = { path = "../../common/slot_clock" }
eth2_ssz = { path = "../../consensus/ssz" }
bs58 = "0.4.0"
futures = "0.3.8"
jemalloc-sys = { version = "0.3.2" }
libc = { version = "0.2.86" }

[dev-dependencies]
store = { path = "../store" }
Expand Down
44 changes: 44 additions & 0 deletions beacon_node/http_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2127,6 +2127,49 @@ pub fn serve<T: BeaconChainTypes>(
})
});

// GET lighthouse/jemalloc_prof_dump
let get_lighthouse_jemalloc_prof_dump = warp::path("lighthouse")
.and(warp::path("jemalloc_prof_dump"))
.and(warp::path::end())
.and_then(|| {
blocking_json_task(move || {
// This endpoint has no purpose without jemalloc.
#[cfg(feature = "sysalloc")]
{
return Err::<String, _>(warp_utils::reject::custom_not_found(
"jemalloc not enabled, see the sysalloc compile feature".to_string(),
));
}

// When using jemalloc, create profile dump as per:
//
// https://github.com/jemalloc/jemalloc/wiki/Use-Case%3A-Heap-Profiling
#[cfg(not(feature = "sysalloc"))]
{
let result = unsafe {
let opt_name = "prof.dump";
let opt_c_name = std::ffi::CString::new(opt_name).unwrap();
jemalloc_sys::mallctl(
opt_c_name.as_ptr(),
std::ptr::null_mut(),
std::ptr::null_mut(),
std::ptr::null_mut(),
std::mem::size_of::<*mut std::ffi::c_void>(),
)
};

if result == 0 {
Ok("profile dumped")
} else {
Err(warp_utils::reject::custom_server_error(format!(
"profiling dump failed with code {}, is the jemalloc-profiling feature enabled?",
result
)))
}
}
})
});

let get_events = eth1_v1
.and(warp::path("events"))
.and(warp::path::end())
Expand Down Expand Up @@ -2233,6 +2276,7 @@ pub fn serve<T: BeaconChainTypes>(
.or(get_lighthouse_eth1_deposit_cache.boxed())
.or(get_lighthouse_beacon_states_ssz.boxed())
.or(get_lighthouse_staking.boxed())
.or(get_lighthouse_jemalloc_prof_dump.boxed())
.or(get_events.boxed()),
)
.or(warp::post().and(
Expand Down
4 changes: 4 additions & 0 deletions beacon_node/http_metrics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ tokio = { version = "1.1.0", features = ["sync"] }
reqwest = { version = "0.11.0", features = ["json"] }
environment = { path = "../../lighthouse/environment" }
types = { path = "../../consensus/types" }

[features]
# Use the system allocator instead of jemalloc. This replicates default Rust behaviour.
sysalloc = ["warp_utils/sysalloc"]
5 changes: 5 additions & 0 deletions common/warp_utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ tokio = { version = "1.1.0", features = ["sync"] }
headers = "0.3.2"
lighthouse_metrics = { path = "../lighthouse_metrics" }
lazy_static = "1.4.0"
jemalloc-ctl = { version = "0.3.3" }

[features]
# Use the system allocator instead of jemalloc. This replicates default Rust behaviour.
sysalloc = []
55 changes: 55 additions & 0 deletions common/warp_utils/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use eth2::lighthouse::Health;
use lighthouse_metrics::*;

#[cfg(not(feature = "sysalloc"))]
use jemalloc_ctl::{arenas, epoch, stats};

lazy_static::lazy_static! {
pub static ref PROCESS_NUM_THREADS: Result<IntGauge> = try_create_int_gauge(
"process_num_threads",
Expand Down Expand Up @@ -34,6 +37,24 @@ lazy_static::lazy_static! {
try_create_float_gauge("system_loadavg_5", "Loadavg over 5 minutes");
pub static ref SYSTEM_LOADAVG_15: Result<Gauge> =
try_create_float_gauge("system_loadavg_15", "Loadavg over 15 minutes");

/*
* jemalloc
*/
pub static ref JEMALLOC_RESIDENT: Result<IntGauge> =
try_create_int_gauge("jemalloc_resident", "Total number of bytes in physically resident data pages mapped by the allocator.");
pub static ref JEMALLOC_ALLOCATED: Result<IntGauge> =
try_create_int_gauge("jemalloc_allocated", "Total number of bytes allocated by the application.");
pub static ref JEMALLOC_MAPPED: Result<IntGauge> =
try_create_int_gauge("jemalloc_mapped", "Total number of bytes in active extents mapped by the allocator.");
pub static ref JEMALLOC_METADATA: Result<IntGauge> =
try_create_int_gauge("jemalloc_metadata", "Total number of bytes dedicated to jemalloc metadata.");
pub static ref JEMALLOC_RETAINED: Result<IntGauge> =
try_create_int_gauge("jemalloc_retained", "Total number of bytes in virtual memory mappings that were retained rather than being returned to the operating system.");
pub static ref JEMALLOC_ACTIVE: Result<IntGauge> =
try_create_int_gauge("jemalloc_active", "Total number of bytes in active pages allocated by the application.");
pub static ref JEMALLOC_ARENAS: Result<IntGauge> =
try_create_int_gauge("jemalloc_arenas", "Current limit on the number of arenas.");
}

pub fn scrape_health_metrics() {
Expand All @@ -58,4 +79,38 @@ pub fn scrape_health_metrics() {
set_float_gauge(&SYSTEM_LOADAVG_5, health.sys_loadavg_5);
set_float_gauge(&SYSTEM_LOADAVG_15, health.sys_loadavg_15);
}

scrape_jemalloc_metrics();
}

#[cfg(not(feature = "sysalloc"))]
pub fn scrape_jemalloc_metrics() {
if epoch::advance().is_ok() {
if let Ok(allocated) = stats::allocated::read() {
set_gauge(&JEMALLOC_ALLOCATED, allocated as i64);
}
if let Ok(resident) = stats::resident::read() {
set_gauge(&JEMALLOC_RESIDENT, resident as i64);
}
if let Ok(mapped) = stats::mapped::read() {
set_gauge(&JEMALLOC_MAPPED, mapped as i64);
}
if let Ok(metadata) = stats::metadata::read() {
set_gauge(&JEMALLOC_METADATA, metadata as i64);
}
if let Ok(retained) = stats::retained::read() {
set_gauge(&JEMALLOC_RETAINED, retained as i64);
}
if let Ok(active) = stats::active::read() {
set_gauge(&JEMALLOC_ACTIVE, active as i64);
}
if let Ok(narenas) = arenas::narenas::read() {
set_gauge(&JEMALLOC_ARENAS, narenas as i64);
}
}
}

#[cfg(feature = "sysalloc")]
pub fn scrape_jemalloc_metrics() {
// NO OP
}
7 changes: 7 additions & 0 deletions lighthouse/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ milagro = ["bls/milagro"]
spec-minimal = []
# Support spec v0.12 (used by Medalla testnet).
spec-v12 = []
# Use the system allocator instead of jemalloc. This replicates default Rust behaviour.
sysalloc = ["beacon_node/sysalloc"]
# Jemalloc profiling
jemalloc-profiling = ["jemallocator/profiling"]

[dependencies]
beacon_node = { "path" = "../beacon_node" }
Expand All @@ -43,6 +47,9 @@ account_utils = { path = "../common/account_utils" }
remote_signer = { "path" = "../remote_signer" }
lighthouse_metrics = { path = "../common/lighthouse_metrics" }
lazy_static = "1.4.0"
jemallocator = { version = "0.3.2" }
jemalloc-sys = { version = "0.3.2" }
libc = { version = "0.2.86" }

[dev-dependencies]
tempfile = "3.1.0"
Expand Down
Loading