Skip to content

Commit e2f34cb

Browse files
committed
Make find_route's dist map elements fit in 128 bytes
We'd previously aggressively cached elements in the `PathBuildingHop` struct (and its sub-structs), which resulted in a rather bloated size. This implied cache misses as we read from and write to multiple cache lines during processing of a single channel. Here, we reduce caching in `DirectedChannelInfo`, fitting the `(NodeId, PathBuildingHop)` tuple in exactly 128 bytes. While this should fit in a single cache line, it sadly does not generally lie in only two lines, as glibc returns large buffers from `malloc` which are very well aligned, plus 16 bytes (for its own allocation tracking). Thus, we try to avoid reading from the last 16 bytes of a `PathBuildingHop`, but luckily that isn't super hard. Note that here we make accessing `DirectedChannelInfo::effective_capacity` somewhat slower, but that's okay as its only ever done once per `DirectedChannelInfo` anyway. While our routing benchmarks are quite noisy, this appears to result in between a 5% and 15% performance improvement in the probabilistic scoring benchmarks.
1 parent d0084c2 commit e2f34cb

File tree

2 files changed

+30
-23
lines changed

2 files changed

+30
-23
lines changed

lightning/src/routing/gossip.rs

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -990,8 +990,6 @@ impl Readable for ChannelInfo {
990990
pub struct DirectedChannelInfo<'a> {
991991
channel: &'a ChannelInfo,
992992
direction: &'a ChannelUpdateInfo,
993-
htlc_maximum_msat: u64,
994-
effective_capacity: EffectiveCapacity,
995993
/// The direction this channel is in - if set, it indicates that we're traversing the channel
996994
/// from [`ChannelInfo::node_one`] to [`ChannelInfo::node_two`].
997995
from_node_one: bool,
@@ -1000,39 +998,30 @@ pub struct DirectedChannelInfo<'a> {
1000998
impl<'a> DirectedChannelInfo<'a> {
1001999
#[inline]
10021000
fn new(channel: &'a ChannelInfo, direction: &'a ChannelUpdateInfo, from_node_one: bool) -> Self {
1003-
let mut htlc_maximum_msat = direction.htlc_maximum_msat;
1004-
let capacity_msat = channel.capacity_sats.map(|capacity_sats| capacity_sats * 1000);
1005-
1006-
let effective_capacity = match capacity_msat {
1007-
Some(capacity_msat) => {
1008-
htlc_maximum_msat = cmp::min(htlc_maximum_msat, capacity_msat);
1009-
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat }
1010-
},
1011-
None => EffectiveCapacity::AdvertisedMaxHTLC { amount_msat: htlc_maximum_msat },
1012-
};
1013-
1014-
Self {
1015-
channel, direction, htlc_maximum_msat, effective_capacity, from_node_one,
1016-
}
1001+
Self { channel, direction, from_node_one }
10171002
}
10181003

10191004
/// Returns information for the channel.
10201005
#[inline]
10211006
pub fn channel(&self) -> &'a ChannelInfo { self.channel }
10221007

1023-
/// Returns the maximum HTLC amount allowed over the channel in the direction.
1024-
#[inline]
1025-
pub fn htlc_maximum_msat(&self) -> u64 {
1026-
self.htlc_maximum_msat
1027-
}
1028-
10291008
/// Returns the [`EffectiveCapacity`] of the channel in the direction.
10301009
///
10311010
/// This is either the total capacity from the funding transaction, if known, or the
10321011
/// `htlc_maximum_msat` for the direction as advertised by the gossip network, if known,
10331012
/// otherwise.
1013+
#[inline]
10341014
pub fn effective_capacity(&self) -> EffectiveCapacity {
1035-
self.effective_capacity
1015+
let mut htlc_maximum_msat = self.direction().htlc_maximum_msat;
1016+
let capacity_msat = self.channel.capacity_sats.map(|capacity_sats| capacity_sats * 1000);
1017+
1018+
match capacity_msat {
1019+
Some(capacity_msat) => {
1020+
htlc_maximum_msat = cmp::min(htlc_maximum_msat, capacity_msat);
1021+
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat }
1022+
},
1023+
None => EffectiveCapacity::AdvertisedMaxHTLC { amount_msat: htlc_maximum_msat },
1024+
}
10361025
}
10371026

10381027
/// Returns information for the direction.
@@ -1042,11 +1031,13 @@ impl<'a> DirectedChannelInfo<'a> {
10421031
/// Returns the `node_id` of the source hop.
10431032
///
10441033
/// Refers to the `node_id` forwarding the payment to the next hop.
1034+
#[inline]
10451035
pub(super) fn source(&self) -> &'a NodeId { if self.from_node_one { &self.channel.node_one } else { &self.channel.node_two } }
10461036

10471037
/// Returns the `node_id` of the target hop.
10481038
///
10491039
/// Refers to the `node_id` receiving the payment from the previous hop.
1040+
#[inline]
10501041
pub(super) fn target(&self) -> &'a NodeId { if self.from_node_one { &self.channel.node_two } else { &self.channel.node_one } }
10511042
}
10521043

lightning/src/routing/router.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,10 @@ impl<'a> CandidateRouteHop<'a> {
11861186
}
11871187
}
11881188

1189+
/// Fetch the effective capacity of this hop.
1190+
///
1191+
/// Note that this may be somewhat expensive, so calls to this should be limited and results
1192+
/// cached!
11891193
fn effective_capacity(&self) -> EffectiveCapacity {
11901194
match self {
11911195
CandidateRouteHop::FirstHop { details, .. } => EffectiveCapacity::ExactLiquidity {
@@ -1341,6 +1345,18 @@ struct PathBuildingHop<'a> {
13411345
value_contribution_msat: u64,
13421346
}
13431347

1348+
// Checks that the entries in the `find_route` `dist` map fit in (exactly) two standard x86-64
1349+
// cache lines. Sadly, they're not guaranteed to actually lie on a cache line (and in fact,
1350+
// generally won't, because at least glibc's malloc will align to a nice, big, round
1351+
// boundary...plus 16), but at least it will reduce the amount of data we'll need to load.
1352+
//
1353+
// Note that these assertions only pass on somewhat recent rustc, and thus are gated on the
1354+
// ldk_bench flag.
1355+
#[cfg(ldk_bench)]
1356+
const _NODE_MAP_SIZE_TWO_CACHE_LINES: usize = 128 - core::mem::size_of::<(NodeId, PathBuildingHop)>();
1357+
#[cfg(ldk_bench)]
1358+
const _NODE_MAP_SIZE_EXACTLY_CACHE_LINES: usize = core::mem::size_of::<(NodeId, PathBuildingHop)>() - 128;
1359+
13441360
impl<'a> core::fmt::Debug for PathBuildingHop<'a> {
13451361
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
13461362
let mut debug_struct = f.debug_struct("PathBuildingHop");

0 commit comments

Comments
 (0)