Skip to content

Commit 5d04d03

Browse files
giaki3003Ash-L2L
authored andcommitted
[perf]: backport changes from thunder perf hackathon (#68)
* [perf]: backport changes from thunder perf hackathon * [misc] Fix std dep order, add comments * [cli] remove mimalloc from cli * [fix] smallvec usage * [misc] Add comments for LMDB flags * [fix] Switch to Borsh and add small test for OutpointKey * [fix] make in/out tracking explicit as per suggestion * [fix] Adjust import ordering * [fix] clarify counts() use, rm into_parts() and explicit deconstruct * [fix] explicit From
1 parent 2c70751 commit 5d04d03

File tree

12 files changed

+526
-361
lines changed

12 files changed

+526
-361
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/main.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,36 @@ use util::saturating_pred_level;
2020
#[global_allocator]
2121
static GLOBAL: MiMalloc = MiMalloc;
2222

23+
fn configure_mimalloc() {
24+
// Tune mimalloc via environment variables
25+
// SAFETY: called before any threads are started, so no other thread can
26+
// concurrently read or write the process environment.
27+
unsafe {
28+
// Limit how many abandoned pages stay cached before returning them to the OS.
29+
std::env::set_var("MIMALLOC_ABANDONED_PAGE_LIMIT", "4");
30+
// Reset abandoned pages so their physical memory is released quickly.
31+
std::env::set_var("MIMALLOC_ABANDONED_PAGE_RESET", "1");
32+
// Cap the number of huge arenas we keep around to bound reserved memory.
33+
std::env::set_var("MIMALLOC_ARENA_LIMIT", "4");
34+
// Allow mimalloc to allocate from any NUMA node for better balance.
35+
std::env::set_var("MIMALLOC_USE_NUMA_NODES", "all");
36+
// Commit new pages immediately to avoid first-use page fault latency.
37+
std::env::set_var("MIMALLOC_EAGER_COMMIT", "1");
38+
// Commit entire regions up front rather than piecemeal to reduce faults.
39+
std::env::set_var("MIMALLOC_EAGER_REGION_COMMIT", "1");
40+
// Keep up to 32 segments cached for quick reuse before releasing to the OS.
41+
std::env::set_var("MIMALLOC_SEGMENT_CACHE", "32");
42+
// Prefer allocating from large OS pages (2MB) when the system supports it.
43+
std::env::set_var("MIMALLOC_LARGE_OS_PAGES", "1");
44+
// Reserve a handful of huge OS pages at startup to back large heaps.
45+
std::env::set_var("MIMALLOC_RESERVE_HUGE_OS_PAGES", "4");
46+
// Keep freed pages committed instead of resetting to avoid extra madvise calls.
47+
std::env::set_var("MIMALLOC_PAGE_RESET", "0");
48+
// Likewise, keep whole segments committed to reduce release/reacquire churn.
49+
std::env::set_var("MIMALLOC_SEGMENT_RESET", "0");
50+
}
51+
}
52+
2353
/// The empty string target `""` can be used to set a default level.
2454
fn targets_directive_str<'a, Targets>(targets: Targets) -> String
2555
where
@@ -167,6 +197,8 @@ fn run_egui_app(
167197
}
168198

169199
fn main() -> anyhow::Result<()> {
200+
// Configure the allocator before Tokio spins up worker threads.
201+
configure_mimalloc();
170202
let cli = cli::Cli::parse();
171203
let config = cli.get_config()?;
172204
let (line_buffer, _rolling_log_guard) = set_tracing_subscriber(

lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ rayon = "1.7.0"
4141
rcgen = "0.13.2"
4242
rustls = { version = "0.23.21", default-features = false, features = ["ring"] }
4343
rustreexo = { workspace = true, features = ["with-serde"] }
44+
smallvec = { version = "1.13.2", features = ["write"] }
4445
semver = { version = "1.0.25", features = ["serde"] }
4546
serde = { workspace = true, features = ["derive"] }
4647
serde_json = { workspace = true }

lib/node/mod.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ where
137137
// let _ = std::fs::remove_dir_all(&env_path);
138138
std::fs::create_dir_all(&env_path)?;
139139
let env = {
140+
use heed::EnvFlags;
140141
let mut env_open_opts = heed::EnvOpenOptions::new();
141142
env_open_opts
142143
.map_size(128 * 1024 * 1024 * 1024) // 128 GB
@@ -146,6 +147,28 @@ where
146147
+ MemPool::NUM_DBS
147148
+ Net::NUM_DBS,
148149
);
150+
// Apply LMDB "fast" flags consistent with our benchmark setup:
151+
// - WRITE_MAP lets us write directly into the memory map instead of
152+
// copying into LMDB's page buffer, reducing syscall overhead for
153+
// write-heavy workloads.
154+
// - MAP_ASYNC hands dirty-page flushing to the kernel so commits do
155+
// not block waiting for msync, keeping latencies tight.
156+
// - NO_SYNC and NO_META_SYNC skip fsync calls for data and
157+
// metadata; this trades durability for throughput, which is
158+
// acceptable here because the state can be reconstructed from the
159+
// canonical chain if a crash occurs.
160+
// - NO_READ_AHEAD disables kernel readahead that would otherwise
161+
// touch cold pages we immediately overwrite, improving random
162+
// access behaviour on SSDs used in testing.
163+
// - NO_TLS stops LMDB from relying on thread-local storage for
164+
// reader slots so transactions can be moved across Tokio tasks.
165+
let fast_flags = EnvFlags::WRITE_MAP
166+
| EnvFlags::MAP_ASYNC
167+
| EnvFlags::NO_SYNC
168+
| EnvFlags::NO_META_SYNC
169+
| EnvFlags::NO_READ_AHEAD
170+
| EnvFlags::NO_TLS;
171+
unsafe { env_open_opts.flags(fast_flags) };
149172
unsafe { Env::open(&env_open_opts, &env_path) }
150173
.map_err(EnvError::from)?
151174
};

lib/node/net_task.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,23 @@ fn connect_tip_(
9393
two_way_peg_data: &mainchain::TwoWayPegData,
9494
) -> Result<(), Error> {
9595
let block_hash = header.hash();
96-
let (_fees, merkle_root): (bitcoin::Amount, MerkleRoot) =
97-
state.validate_block(rwtxn, header, body)?;
96+
let prevalidated = state.prevalidate_block(rwtxn, header, body)?;
9897
if tracing::enabled!(tracing::Level::DEBUG) {
9998
let height = state.try_get_height(rwtxn)?;
100-
let _: MerkleRoot = state.connect_block(rwtxn, header, body)?;
101-
tracing::debug!(?height, %merkle_root, %block_hash,
102-
"connected body")
99+
let merkle_root = state.connect_prevalidated_block(
100+
rwtxn,
101+
header,
102+
body,
103+
prevalidated,
104+
)?;
105+
tracing::debug!(?height, %merkle_root, %block_hash, "connected body")
103106
} else {
104-
let _: MerkleRoot = state.connect_block(rwtxn, header, body)?;
107+
let _: MerkleRoot = state.connect_prevalidated_block(
108+
rwtxn,
109+
header,
110+
body,
111+
prevalidated,
112+
)?;
105113
}
106114
let () = state.connect_two_way_peg_data(rwtxn, two_way_peg_data)?;
107115
let accumulator = state.get_accumulator(rwtxn)?;

0 commit comments

Comments
 (0)