From bef410759df8ebe2fd57aa4f987103e28bb4ea97 Mon Sep 17 00:00:00 2001 From: tv Date: Thu, 5 Nov 2026 01:48:26 +0100 Subject: bench tor round trips --- docs/development.md | 2 +- src/simtest/bench.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/docs/development.md b/docs/development.md index 2ed15f6..519d64c 100644 --- a/docs/development.md +++ b/docs/development.md @@ -22,7 +22,7 @@ messages, `document/bench.rs`), the remakes' replay (`remake/bench.rs`), and wha passing changes on costs over the simulated network (`simtest/bench.rs`: messages and bytes per write by kind, propagation delays, for a full mesh, a writer behind NAT, two transports, partial meshes of 50 and 100 nodes, lossy links (with delays at random, -and with Mycelium's round trips, each link its own), a member away for a while, and +and with Mycelium's round trips, each link its own; and Tor's, with some slow circuits), a member away for a while, and members joining during the writes; several minutes, or one scenario alone with `BENCH_SCENARIO`, part of its name: `BENCH_SCENARIO=NAT`; all at once with `BENCH_PARALLEL=1`, faster on many cores, though sharing them makes delays come out diff --git a/src/simtest/bench.rs b/src/simtest/bench.rs index 82c8985..1d6d411 100644 --- a/src/simtest/bench.rs +++ b/src/simtest/bench.rs @@ -63,6 +63,9 @@ struct Scenario { /// registration reached them, and their trees with them. Their catching up counts /// in the messages, but not in the delays (`swarm::stats`: not until caught up). joining: usize, + /// The first wait for a sync answer, if not `SYNC_REPLY_TIMEOUT`: longer where round + /// trips take seconds, as Tor's transport asks for (`Transport::sync_reply_timeout`). + reply_timeout: Option, } fn sim_only(_: usize) -> &'static [&'static str] { @@ -127,6 +130,31 @@ fn mycelium_like(sim: &Sim, ids: &[String]) { } } +/// Each link a round trip of its own, as over Tor: 250 to 400 ms, each message within a +/// fifth of its link's; one link in ten through a slow circuit, 1 to 3 s. Nothing lost +/// (Tor carries streams reliably). The simulated net can't make one link slow for a +/// while only, so the circuits that are slow at times are slow throughout here. With a +/// first wait for answers of 5 s, as Tor's transport waits longer (30 s in production). +fn tor_like(sim: &Sim, ids: &[String]) { + let mut rng = crate::testrand::Rng::new(9); + for (i, from) in ids.iter().enumerate() { + for to in &ids[i + 1..] { + let rtt_ms = if rng.chance(0.1) { + 1000.0 + rng.next_f64() * 2000.0 + } else { + 250.0 + rng.next_f64() * 150.0 + }; + let half = Duration::from_secs_f64(rtt_ms / 2.0 / 1000.0); + let link = LinkParams { + delay: (half * 4 / 5, half * 6 / 5), + ..LinkParams::default() + }; + sim.net.set_link(from, to, link.clone()); + sim.net.set_link(to, from, link); + } + } +} + const SCENARIOS: &[Scenario] = &[ Scenario { name: "full mesh, 13 nodes", @@ -136,6 +164,7 @@ const SCENARIOS: &[Scenario] = &[ writer: 1, away: None, joining: 0, + reply_timeout: None, }, Scenario { name: "writer behind NAT (one link), 13 nodes", @@ -145,6 +174,7 @@ const SCENARIOS: &[Scenario] = &[ writer: 1, away: None, joining: 0, + reply_timeout: None, }, Scenario { name: "two transports, 3 bridges, 30 nodes", @@ -154,6 +184,7 @@ const SCENARIOS: &[Scenario] = &[ writer: 5, away: None, joining: 0, + reply_timeout: None, }, Scenario { name: "partial mesh, 50 nodes", @@ -163,6 +194,7 @@ const SCENARIOS: &[Scenario] = &[ writer: 1, away: None, joining: 0, + reply_timeout: None, }, Scenario { name: "partial mesh, lossy and slow links, 50 nodes", @@ -172,6 +204,7 @@ const SCENARIOS: &[Scenario] = &[ writer: 1, away: None, joining: 0, + reply_timeout: None, }, Scenario { name: "partial mesh, 100 nodes", @@ -181,6 +214,7 @@ const SCENARIOS: &[Scenario] = &[ writer: 1, away: None, joining: 0, + reply_timeout: None, }, Scenario { name: "partial mesh, a member away for 10 s, 50 nodes", @@ -190,6 +224,7 @@ const SCENARIOS: &[Scenario] = &[ writer: 1, away: Some(3), joining: 0, + reply_timeout: None, }, Scenario { name: "partial mesh, 5 members joining during each workload, 50 nodes", @@ -199,6 +234,7 @@ const SCENARIOS: &[Scenario] = &[ writer: 1, away: None, joining: 5, + reply_timeout: None, }, // Last, so the others keep their seeds. Scenario { @@ -209,6 +245,17 @@ const SCENARIOS: &[Scenario] = &[ writer: 1, away: None, joining: 0, + reply_timeout: None, + }, + Scenario { + name: "partial mesh, Tor's round trips, 50 nodes", + nodes: 50, + on: sim_only, + net: tor_like, + writer: 1, + away: None, + joining: 0, + reply_timeout: Some(Duration::from_secs(5)), }, ]; @@ -378,8 +425,9 @@ async fn run(seed: u64, scenario: &'static Scenario) -> String { let sim = Sim::with_identity(seed); let ids: Vec = (0..scenario.nodes).map(|i| format!("n{i:03}")).collect(); (scenario.net)(&sim, &ids); - let timing = |config: &mut crate::node::NodeConfig| { - config.timing = Timing::new(KEEPALIVE, SYNC_REPLY_TIMEOUT, DELIVERY_LIMIT); + let reply_timeout = scenario.reply_timeout.unwrap_or(SYNC_REPLY_TIMEOUT); + let timing = move |config: &mut crate::node::NodeConfig| { + config.timing = Timing::new(KEEPALIVE, reply_timeout, DELIVERY_LIMIT); // As in production (`--neighbours`). config.neighbours_k = 12; }; -- cgit v1.3.1