Skip to content

Commit 1a24dcc

Browse files
Merge pull request #1275 from jkczyz/2022-01-benchmark-improvements
Router benchmark improvements
2 parents 3baaebe + d924c5d commit 1a24dcc

File tree

1 file changed

+102
-40
lines changed

1 file changed

+102
-40
lines changed

lightning/src/routing/router.rs

Lines changed: 102 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4963,6 +4963,11 @@ pub(crate) mod test_utils {
49634963
#[cfg(all(test, feature = "unstable", not(feature = "no-std")))]
49644964
mod benches {
49654965
use super::*;
4966+
use bitcoin::hashes::Hash;
4967+
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
4968+
use chain::transaction::OutPoint;
4969+
use ln::channelmanager::{ChannelCounterparty, ChannelDetails};
4970+
use ln::features::{InitFeatures, InvoiceFeatures};
49664971
use routing::scoring::Scorer;
49674972
use util::logger::{Logger, Record};
49684973

@@ -4973,72 +4978,129 @@ mod benches {
49734978
fn log(&self, _record: &Record) {}
49744979
}
49754980

4976-
#[bench]
4977-
fn generate_routes(bench: &mut Bencher) {
4981+
struct ZeroPenaltyScorer;
4982+
impl Score for ZeroPenaltyScorer {
4983+
fn channel_penalty_msat(
4984+
&self, _short_channel_id: u64, _send_amt: u64, _capacity_msat: Option<u64>, _source: &NodeId, _target: &NodeId
4985+
) -> u64 { 0 }
4986+
fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {}
4987+
fn payment_path_successful(&mut self, _path: &[&RouteHop]) {}
4988+
}
4989+
4990+
fn read_network_graph() -> NetworkGraph {
49784991
let mut d = test_utils::get_route_file().unwrap();
4979-
let graph = NetworkGraph::read(&mut d).unwrap();
4980-
let nodes = graph.read_only().nodes().clone();
4981-
let scorer = Scorer::with_fixed_penalty(0);
4992+
NetworkGraph::read(&mut d).unwrap()
4993+
}
49824994

4983-
// First, get 100 (source, destination) pairs for which route-getting actually succeeds...
4984-
let mut path_endpoints = Vec::new();
4985-
let mut seed: usize = 0xdeadbeef;
4986-
'load_endpoints: for _ in 0..100 {
4987-
loop {
4988-
seed *= 0xdeadbeef;
4989-
let src = PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
4990-
seed *= 0xdeadbeef;
4991-
let dst = PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
4992-
let payment_params = PaymentParameters::from_node_id(dst);
4993-
let amt = seed as u64 % 1_000_000;
4994-
if get_route(&src, &payment_params, &graph, None, amt, 42, &DummyLogger{}, &scorer).is_ok() {
4995-
path_endpoints.push((src, dst, amt));
4996-
continue 'load_endpoints;
4997-
}
4998-
}
4995+
fn payer_pubkey() -> PublicKey {
4996+
let secp_ctx = Secp256k1::new();
4997+
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap())
4998+
}
4999+
5000+
#[inline]
5001+
fn first_hop(node_id: PublicKey) -> ChannelDetails {
5002+
ChannelDetails {
5003+
channel_id: [0; 32],
5004+
counterparty: ChannelCounterparty {
5005+
features: InitFeatures::known(),
5006+
node_id,
5007+
unspendable_punishment_reserve: 0,
5008+
forwarding_info: None,
5009+
},
5010+
funding_txo: Some(OutPoint {
5011+
txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0
5012+
}),
5013+
short_channel_id: Some(1),
5014+
channel_value_satoshis: 10_000_000,
5015+
user_channel_id: 0,
5016+
balance_msat: 10_000_000,
5017+
outbound_capacity_msat: 10_000_000,
5018+
inbound_capacity_msat: 0,
5019+
unspendable_punishment_reserve: None,
5020+
confirmations_required: None,
5021+
force_close_spend_delay: None,
5022+
is_outbound: true,
5023+
is_funding_locked: true,
5024+
is_usable: true,
5025+
is_public: true,
49995026
}
5027+
}
50005028

5001-
// ...then benchmark finding paths between the nodes we learned.
5002-
let mut idx = 0;
5003-
bench.iter(|| {
5004-
let (src, dst, amt) = path_endpoints[idx % path_endpoints.len()];
5005-
let payment_params = PaymentParameters::from_node_id(dst);
5006-
assert!(get_route(&src, &payment_params, &graph, None, amt, 42, &DummyLogger{}, &scorer).is_ok());
5007-
idx += 1;
5008-
});
5029+
#[bench]
5030+
fn generate_routes_with_zero_penalty_scorer(bench: &mut Bencher) {
5031+
let network_graph = read_network_graph();
5032+
let scorer = ZeroPenaltyScorer;
5033+
generate_routes(bench, &network_graph, scorer, InvoiceFeatures::empty());
50095034
}
50105035

50115036
#[bench]
5012-
fn generate_mpp_routes(bench: &mut Bencher) {
5013-
let mut d = test_utils::get_route_file().unwrap();
5014-
let graph = NetworkGraph::read(&mut d).unwrap();
5037+
fn generate_mpp_routes_with_zero_penalty_scorer(bench: &mut Bencher) {
5038+
let network_graph = read_network_graph();
5039+
let scorer = ZeroPenaltyScorer;
5040+
generate_routes(bench, &network_graph, scorer, InvoiceFeatures::known());
5041+
}
5042+
5043+
#[bench]
5044+
fn generate_routes_with_default_scorer(bench: &mut Bencher) {
5045+
let network_graph = read_network_graph();
5046+
let scorer = Scorer::default();
5047+
generate_routes(bench, &network_graph, scorer, InvoiceFeatures::empty());
5048+
}
5049+
5050+
#[bench]
5051+
fn generate_mpp_routes_with_default_scorer(bench: &mut Bencher) {
5052+
let network_graph = read_network_graph();
5053+
let scorer = Scorer::default();
5054+
generate_routes(bench, &network_graph, scorer, InvoiceFeatures::known());
5055+
}
5056+
5057+
fn generate_routes<S: Score>(
5058+
bench: &mut Bencher, graph: &NetworkGraph, mut scorer: S, features: InvoiceFeatures
5059+
) {
50155060
let nodes = graph.read_only().nodes().clone();
5016-
let scorer = Scorer::with_fixed_penalty(0);
5061+
let payer = payer_pubkey();
50175062

50185063
// First, get 100 (source, destination) pairs for which route-getting actually succeeds...
5019-
let mut path_endpoints = Vec::new();
5064+
let mut routes = Vec::new();
5065+
let mut route_endpoints = Vec::new();
50205066
let mut seed: usize = 0xdeadbeef;
50215067
'load_endpoints: for _ in 0..100 {
50225068
loop {
50235069
seed *= 0xdeadbeef;
50245070
let src = PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
50255071
seed *= 0xdeadbeef;
50265072
let dst = PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
5027-
let payment_params = PaymentParameters::from_node_id(dst).with_features(InvoiceFeatures::known());
5073+
let params = PaymentParameters::from_node_id(dst).with_features(features.clone());
5074+
let first_hop = first_hop(src);
50285075
let amt = seed as u64 % 1_000_000;
5029-
if get_route(&src, &payment_params, &graph, None, amt, 42, &DummyLogger{}, &scorer).is_ok() {
5030-
path_endpoints.push((src, dst, amt));
5076+
if let Ok(route) = get_route(&payer, &params, &graph, Some(&[&first_hop]), amt, 42, &DummyLogger{}, &scorer) {
5077+
routes.push(route);
5078+
route_endpoints.push((first_hop, params, amt));
50315079
continue 'load_endpoints;
50325080
}
50335081
}
50345082
}
50355083

5084+
// ...and seed the scorer with success and failure data...
5085+
for route in routes {
5086+
let amount = route.get_total_amount();
5087+
if amount < 250_000 {
5088+
for path in route.paths {
5089+
scorer.payment_path_successful(&path.iter().collect::<Vec<_>>());
5090+
}
5091+
} else if amount > 750_000 {
5092+
for path in route.paths {
5093+
let short_channel_id = path[path.len() / 2].short_channel_id;
5094+
scorer.payment_path_failed(&path.iter().collect::<Vec<_>>(), short_channel_id);
5095+
}
5096+
}
5097+
}
5098+
50365099
// ...then benchmark finding paths between the nodes we learned.
50375100
let mut idx = 0;
50385101
bench.iter(|| {
5039-
let (src, dst, amt) = path_endpoints[idx % path_endpoints.len()];
5040-
let payment_params = PaymentParameters::from_node_id(dst).with_features(InvoiceFeatures::known());
5041-
assert!(get_route(&src, &payment_params, &graph, None, amt, 42, &DummyLogger{}, &scorer).is_ok());
5102+
let (first_hop, params, amt) = &route_endpoints[idx % route_endpoints.len()];
5103+
assert!(get_route(&payer, params, &graph, Some(&[first_hop]), *amt, 42, &DummyLogger{}, &scorer).is_ok());
50425104
idx += 1;
50435105
});
50445106
}

0 commit comments

Comments
 (0)