@@ -771,6 +771,19 @@ impl ProbabilisticScoringDecayParameters {
771
771
}
772
772
}
773
773
774
+ /// A dummy copy of [`ChannelLiquidity`] to calculate its unpadded size
775
+ #[ repr( C ) ]
776
+ struct DummyLiquidity {
777
+ a : u64 ,
778
+ b : u64 ,
779
+ c : HistoricalLiquidityTracker ,
780
+ d : Duration ,
781
+ e : Duration ,
782
+ }
783
+
784
+ /// The amount of padding required to make [`ChannelLiquidity`] (plus a u64) a full 4 cache lines.
785
+ const LIQ_PADDING_LEN : usize = ( 256 - :: core:: mem:: size_of :: < ( u64 , DummyLiquidity ) > ( ) ) / 8 ;
786
+
774
787
/// Accounting for channel liquidity balance uncertainty.
775
788
///
776
789
/// Direction is defined in terms of [`NodeId`] partial ordering, where the source node is the
@@ -792,17 +805,25 @@ struct ChannelLiquidity {
792
805
/// Time when the historical liquidity bounds were last modified as an offset against the unix
793
806
/// epoch.
794
807
offset_history_last_updated : Duration ,
808
+
809
+ _padding : [ u64 ; LIQ_PADDING_LEN ] ,
795
810
}
796
811
797
- // Check that the liquidity HashMap's entries sit on round cache lines.
812
+ // Check that the liquidity HashMap's entries sit on round cache line pairs.
813
+ //
814
+ // Most modern CPUs have 64-byte cache lines, so we really want to be on round cache lines to avoid
815
+ // hitting memory too much during scoring. Further, many x86 CPUs (and possibly others) load
816
+ // adjacent cache lines opportunistically in case they will be useful.
798
817
//
799
- // Specifically, the first cache line will have the key, the liquidity offsets, and the total
800
- // points tracked in the historical tracker.
818
+ // Thus, we really want our HashMap entries to be aligned to 128 bytes. This will leave the first
819
+ // cache line will have the key, the liquidity offsets, and the total points tracked in the
820
+ // historical tracker.
801
821
//
802
822
// The next two cache lines will have the historical points, which we only access last during
803
- // scoring, followed by the last_updated `Duration`s (which we do not need during scoring).
804
- const _LIQUIDITY_MAP_SIZING_CHECK: usize = 192 - :: core:: mem:: size_of :: < ( u64 , ChannelLiquidity ) > ( ) ;
805
- const _LIQUIDITY_MAP_SIZING_CHECK_2: usize = :: core:: mem:: size_of :: < ( u64 , ChannelLiquidity ) > ( ) - 192 ;
823
+ // scoring, followed by the last_updated `Duration`s (which we do not need during scoring). The
824
+ // extra padding brings us up to a clean four cache lines.
825
+ const _LIQUIDITY_MAP_SIZING_CHECK: usize = 256 - :: core:: mem:: size_of :: < ( u64 , ChannelLiquidity ) > ( ) ;
826
+ const _LIQUIDITY_MAP_SIZING_CHECK_2: usize = :: core:: mem:: size_of :: < ( u64 , ChannelLiquidity ) > ( ) - 256 ;
806
827
807
828
/// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity.
808
829
struct DirectedChannelLiquidity < L : Deref < Target = u64 > , HT : Deref < Target = HistoricalLiquidityTracker > , T : Deref < Target = Duration > > {
@@ -988,6 +1009,7 @@ impl ChannelLiquidity {
988
1009
liquidity_history : HistoricalLiquidityTracker :: new ( ) ,
989
1010
last_updated,
990
1011
offset_history_last_updated : last_updated,
1012
+ _padding : [ 0 ; LIQ_PADDING_LEN ] ,
991
1013
}
992
1014
}
993
1015
@@ -1980,13 +2002,14 @@ impl Readable for ChannelLiquidity {
1980
2002
) ,
1981
2003
last_updated,
1982
2004
offset_history_last_updated : offset_history_last_updated. unwrap_or ( last_updated) ,
2005
+ _padding : [ 0 ; LIQ_PADDING_LEN ] ,
1983
2006
} )
1984
2007
}
1985
2008
}
1986
2009
1987
2010
#[ cfg( test) ]
1988
2011
mod tests {
1989
- use super :: { ChannelLiquidity , HistoricalLiquidityTracker , ProbabilisticScoringFeeParameters , ProbabilisticScoringDecayParameters , ProbabilisticScorer } ;
2012
+ use super :: * ;
1990
2013
use crate :: blinded_path:: BlindedHop ;
1991
2014
use crate :: util:: config:: UserConfig ;
1992
2015
@@ -2160,12 +2183,14 @@ mod tests {
2160
2183
min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 ,
2161
2184
last_updated, offset_history_last_updated,
2162
2185
liquidity_history : HistoricalLiquidityTracker :: new ( ) ,
2186
+ _padding : [ 0 ; LIQ_PADDING_LEN ] ,
2163
2187
} )
2164
2188
. with_channel ( 43 ,
2165
2189
ChannelLiquidity {
2166
2190
min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 ,
2167
2191
last_updated, offset_history_last_updated,
2168
2192
liquidity_history : HistoricalLiquidityTracker :: new ( ) ,
2193
+ _padding : [ 0 ; LIQ_PADDING_LEN ] ,
2169
2194
} ) ;
2170
2195
let source = source_node_id ( ) ;
2171
2196
let target = target_node_id ( ) ;
@@ -2239,6 +2264,7 @@ mod tests {
2239
2264
min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 ,
2240
2265
last_updated, offset_history_last_updated,
2241
2266
liquidity_history : HistoricalLiquidityTracker :: new ( ) ,
2267
+ _padding : [ 0 ; LIQ_PADDING_LEN ] ,
2242
2268
} ) ;
2243
2269
let source = source_node_id ( ) ;
2244
2270
let target = target_node_id ( ) ;
@@ -2299,6 +2325,7 @@ mod tests {
2299
2325
min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 ,
2300
2326
last_updated, offset_history_last_updated,
2301
2327
liquidity_history : HistoricalLiquidityTracker :: new ( ) ,
2328
+ _padding : [ 0 ; LIQ_PADDING_LEN ] ,
2302
2329
} ) ;
2303
2330
let source = source_node_id ( ) ;
2304
2331
let target = target_node_id ( ) ;
@@ -2418,6 +2445,7 @@ mod tests {
2418
2445
min_liquidity_offset_msat : 40 , max_liquidity_offset_msat : 40 ,
2419
2446
last_updated, offset_history_last_updated,
2420
2447
liquidity_history : HistoricalLiquidityTracker :: new ( ) ,
2448
+ _padding : [ 0 ; LIQ_PADDING_LEN ] ,
2421
2449
} ) ;
2422
2450
let source = source_node_id ( ) ;
2423
2451
0 commit comments