Skip to content

Commit 4df7223

Browse files
committed
Properly pre-allocate NetworkGraph channel/node maps
When we build a new `NetworkGraph` from empty, we're generally doing an initial startup and will be syncing the graph very soon. Using an initially-empty `IndexedMap` for the `channels` and `nodes` results in quite some memory churn, with the initial RGS application benchmark showing 15% of its time in pagefault handling alone (i.e. allocating new memory from the OS, let alone the 23% of time in `memmove`). Further, when deserializing a `NetworkGraph`, we'd swapped the expected node and channel count constants, leaving the node map too small and causing map doubling as we read entries from disk. Finally, when deserializing, allocating only exactly the amount of map entries we need is likely to lead to at least one doubling, so we're better off just over-estimating the number of nodes and channels and allocating what we want. Here we just always allocate `channels` and `nodes` based on constants, leading to a 20%-ish speedup in the initial RGS application benchmark.
1 parent c06b284 commit 4df7223

File tree

1 file changed

+13
-6
lines changed

1 file changed

+13
-6
lines changed

lightning/src/routing/gossip.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,8 +1660,7 @@ where
16601660

16611661
let chain_hash: ChainHash = Readable::read(reader)?;
16621662
let channels_count: u64 = Readable::read(reader)?;
1663-
// In Nov, 2023 there were about 15,000 nodes; we cap allocations to 1.5x that.
1664-
let mut channels = IndexedMap::with_capacity(cmp::min(channels_count as usize, 22500));
1663+
let mut channels = IndexedMap::with_capacity(CHAN_COUNT_ESTIMATE);
16651664
for _ in 0..channels_count {
16661665
let chan_id: u64 = Readable::read(reader)?;
16671666
let chan_info: ChannelInfo = Readable::read(reader)?;
@@ -1673,8 +1672,7 @@ where
16731672
if nodes_count > u32::max_value() as u64 / 2 {
16741673
return Err(DecodeError::InvalidValue);
16751674
}
1676-
// In Nov, 2023 there were about 69K channels; we cap allocations to 1.5x that.
1677-
let mut nodes = IndexedMap::with_capacity(cmp::min(nodes_count as usize, 103500));
1675+
let mut nodes = IndexedMap::with_capacity(NODE_COUNT_ESTIMATE);
16781676
for i in 0..nodes_count {
16791677
let node_id = Readable::read(reader)?;
16801678
let mut node_info: NodeInfo = Readable::read(reader)?;
@@ -1750,6 +1748,15 @@ where
17501748
}
17511749
}
17521750

1751+
// In Jan, 2025 there were about 49K channels.
1752+
// We over-allocate by a bit because 20% more is better than the double we get if we're slightly
1753+
// too low
1754+
const CHAN_COUNT_ESTIMATE: usize = 60_000;
1755+
// In Jan, 2025 there were about 15K nodes
1756+
// We over-allocate by a bit because 33% more is better than the double we get if we're slightly
1757+
// too low
1758+
const NODE_COUNT_ESTIMATE: usize = 20_000;
1759+
17531760
impl<L: Deref> NetworkGraph<L>
17541761
where
17551762
L::Target: Logger,
@@ -1760,8 +1767,8 @@ where
17601767
secp_ctx: Secp256k1::verification_only(),
17611768
chain_hash: ChainHash::using_genesis_block(network),
17621769
logger,
1763-
channels: RwLock::new(IndexedMap::new()),
1764-
nodes: RwLock::new(IndexedMap::new()),
1770+
channels: RwLock::new(IndexedMap::with_capacity(CHAN_COUNT_ESTIMATE)),
1771+
nodes: RwLock::new(IndexedMap::with_capacity(NODE_COUNT_ESTIMATE)),
17651772
next_node_counter: AtomicUsize::new(0),
17661773
removed_node_counters: Mutex::new(Vec::new()),
17671774
last_rapid_gossip_sync_timestamp: Mutex::new(None),

0 commit comments

Comments
 (0)