Skip to content

Commit 62ffd78

Browse files
committed
Layout channel info to ensure routing uses cache lines well
Because we scan per-channel information in the hot inner loop of our routefinding immediately after looking a channel up in a `HashMap`, we end up spending a nontrivial portion of our routefinding time waiting on memory to be read in. While there is only so much we can do about that, ensuring the channel information that we care about is sitting on one or adjacent cache lines avoids paying that penalty twice. Thus, here we manually lay out `ChannelInfo` and `ChannelUpdateInfo` and set them to 128b and 32b alignment, respectively. This wastes some space in memory in our network graph, but improves routing performance in return.
1 parent 3d9d38f commit 62ffd78

File tree

1 file changed

+45
-16
lines changed

1 file changed

+45
-16
lines changed

lightning/src/routing/gossip.rs

+45-16
Original file line numberDiff line numberDiff line change
@@ -760,22 +760,32 @@ where
760760
}
761761
}
762762

763+
// Fetching values from this struct is very performance sensitive during routefinding. Thus, we
764+
// want to ensure that all of the fields we care about (all of them except `last_update_message`)
765+
// sit on the same cache line.
766+
//
767+
// We do this by using `repr(C)`, which forces the struct to be laid out in memory the way we write
768+
// it (ensuring `last_update_message` hangs off the end and no fields are reordered after it), and
769+
// `align(32)`, ensuring the struct starts either at the start, or in the middle, of a 64b x86-64
770+
// cache line. This ensures the beginning fields (which are 31 bytes) all sit in the same cache
771+
// line.
772+
#[repr(C, align(32))]
763773
#[derive(Clone, Debug, PartialEq, Eq)]
764774
/// Details about one direction of a channel as received within a [`ChannelUpdate`].
765775
pub struct ChannelUpdateInfo {
766-
/// When the last update to the channel direction was issued.
767-
/// Value is opaque, as set in the announcement.
768-
pub last_update: u32,
769-
/// Whether the channel can be currently used for payments (in this one direction).
770-
pub enabled: bool,
771-
/// The difference in CLTV values that you must have when routing through this channel.
772-
pub cltv_expiry_delta: u16,
773776
/// The minimum value, which must be relayed to the next hop via the channel
774777
pub htlc_minimum_msat: u64,
775778
/// The maximum value which may be relayed to the next hop via the channel.
776779
pub htlc_maximum_msat: u64,
777780
/// Fees charged when the channel is used for routing
778781
pub fees: RoutingFees,
782+
/// When the last update to the channel direction was issued.
783+
/// Value is opaque, as set in the announcement.
784+
pub last_update: u32,
785+
/// The difference in CLTV values that you must have when routing through this channel.
786+
pub cltv_expiry_delta: u16,
787+
/// Whether the channel can be currently used for payments (in this one direction).
788+
pub enabled: bool,
779789
/// Most recent update for the channel received from the network
780790
/// Mostly redundant with the data we store in fields explicitly.
781791
/// Everything else is useful only for sending out for initial routing sync.
@@ -843,22 +853,46 @@ impl Readable for ChannelUpdateInfo {
843853
}
844854
}
845855

856+
// Fetching values from this struct is very performance sensitive during routefinding. Thus, we
857+
// want to ensure that all of the fields we care about (all of them except `last_update_message`
858+
// and `announcement_received_time`) sit on the same cache line.
859+
//
860+
// Sadly, this is not possible, however we can still do okay - all of the fields before
861+
// `one_to_two` and `two_to_one` are just under 128 bytes long, so we can ensure they sit on
862+
// adjacent cache lines (which are generally fetched together in x86_64 processors).
863+
//
864+
// This leaves only the two directional channel info structs on separate cache lines.
865+
//
866+
// We accomplish this using `repr(C)`, which forces the struct to be laid out in memory the way we
867+
// write it (ensuring the fields we care about are at the start of the struct) and `align(128)`,
868+
// ensuring the struct starts at the beginning of two adjacent 64b x86-64 cache lines.
869+
#[repr(align(128), C)]
846870
#[derive(Clone, Debug, Eq)]
847871
/// Details about a channel (both directions).
848872
/// Received within a channel announcement.
849873
pub struct ChannelInfo {
850874
/// Protocol features of a channel communicated during its announcement
851875
pub features: ChannelFeatures,
876+
852877
/// Source node of the first direction of a channel
853878
pub node_one: NodeId,
854-
/// Details about the first direction of a channel
855-
pub one_to_two: Option<ChannelUpdateInfo>,
879+
856880
/// Source node of the second direction of a channel
857881
pub node_two: NodeId,
858-
/// Details about the second direction of a channel
859-
pub two_to_one: Option<ChannelUpdateInfo>,
882+
883+
/// The [`NodeInfo::node_counter`] of the node pointed to by [`Self::node_one`].
884+
pub(crate) node_one_counter: u32,
885+
/// The [`NodeInfo::node_counter`] of the node pointed to by [`Self::node_two`].
886+
pub(crate) node_two_counter: u32,
887+
860888
/// The channel capacity as seen on-chain, if chain lookup is available.
861889
pub capacity_sats: Option<u64>,
890+
891+
/// Details about the first direction of a channel
892+
pub one_to_two: Option<ChannelUpdateInfo>,
893+
/// Details about the second direction of a channel
894+
pub two_to_one: Option<ChannelUpdateInfo>,
895+
862896
/// An initial announcement of the channel
863897
/// Mostly redundant with the data we store in fields explicitly.
864898
/// Everything else is useful only for sending out for initial routing sync.
@@ -868,11 +902,6 @@ pub struct ChannelInfo {
868902
/// (which we can probably assume we are - no-std environments probably won't have a full
869903
/// network graph in memory!).
870904
announcement_received_time: u64,
871-
872-
/// The [`NodeInfo::node_counter`] of the node pointed to by [`Self::node_one`].
873-
pub(crate) node_one_counter: u32,
874-
/// The [`NodeInfo::node_counter`] of the node pointed to by [`Self::node_two`].
875-
pub(crate) node_two_counter: u32,
876905
}
877906

878907
impl PartialEq for ChannelInfo {

0 commit comments

Comments
 (0)