From 5994b49412c058079639585501a78e6458fdbb6f Mon Sep 17 00:00:00 2001 From: tv Date: Fri, 6 Nov 2026 19:54:09 +0100 Subject: HyParView (slim) --- src/simtest/bench.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 8 deletions(-) (limited to 'src/simtest/bench.rs') diff --git a/src/simtest/bench.rs b/src/simtest/bench.rs index 2530015..dac7a48 100644 --- a/src/simtest/bench.rs +++ b/src/simtest/bench.rs @@ -491,7 +491,7 @@ impl Totals { } /// The kinds, in the order of the report. -const KINDS: [&str; 11] = [ +const KINDS: [&str; 12] = [ "SYNC", "STATUS", "STATUS_REPLY", @@ -503,9 +503,10 @@ const KINDS: [&str; 11] = [ "LINKS", "PROBE", "PRUNE/GRAFT", + "NEIGHBOUR", ]; -fn counters(by: &ByKind) -> [Counter; 11] { +fn counters(by: &ByKind) -> [Counter; 12] { [ by.sync, by.status, @@ -518,10 +519,11 @@ fn counters(by: &ByKind) -> [Counter; 11] { by.links, by.probe, by.plumtree, + by.hyparview, ] } -fn counters_mut(by: &mut ByKind) -> [&mut Counter; 11] { +fn counters_mut(by: &mut ByKind) -> [&mut Counter; 12] { [ &mut by.sync, &mut by.status, @@ -534,6 +536,7 @@ fn counters_mut(by: &mut ByKind) -> [&mut Counter; 11] { &mut by.links, &mut by.probe, &mut by.plumtree, + &mut by.hyparview, ] } @@ -547,8 +550,11 @@ async fn run(seed: u64, scenario: &'static Scenario) -> (String, Vec<(&'static s 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; + // As in production (`--neighbours`): 12, or HyParView's 5 (`config::derive_defaults`). + config.neighbours_k = match config.topology { + crate::swarm::topology::Kind::Hyparview => 5, + crate::swarm::topology::Kind::RingAndPairs => 12, + }; }; let mut nodes = vec![sim.start_on_with(&ids[0], (scenario.on)(0), &[], Start::Genesis, timing)]; // Those there from the start; the others join during the workloads. @@ -620,7 +626,7 @@ async fn run(seed: u64, scenario: &'static Scenario) -> (String, Vec<(&'static s scenario.name, writes(), 1000 / WRITE_EVERY.as_millis(), - all[0].dissemination.name() + all[0].dissemination().name() ); let mut joined = initial; for (w, (workload, writer)) in [ @@ -685,6 +691,7 @@ async fn run(seed: u64, scenario: &'static Scenario) -> (String, Vec<(&'static s trees(&mut out, &nodes, &sim.net).await; sent_kept(&mut out, &nodes).await; eager_links(&mut out, &nodes, &sim.net); + active_views(&mut out, &nodes); if let Some(writer) = writer { slowest(&mut out, &nodes, &nodes[writer], &sim.net).await; } @@ -801,6 +808,37 @@ pub(super) async fn sent_kept(out: &mut String, nodes: &[AppState]) { ); } +/// HyParView's active views after the workload (`swarm::hyparview`): how many neighbours +/// each agreed to, the fewest and the most, and the links only one end has in its view +/// (a DISCONNECT lost, or one end gave up on the other). Nothing for a topology that +/// keeps no such views. +pub(super) fn active_views(out: &mut String, nodes: &[AppState]) { + let mut views = HashMap::new(); + for node in nodes { + let Some(active) = node.topology().active() else { + return; + }; + views.insert(node.local_id().to_owned(), active); + } + let sizes: Vec = views.values().map(|active| active.len()).collect(); + let one_ended = views + .iter() + .flat_map(|(node, active)| active.iter().map(move |other| (node, other))) + .filter(|(node, other)| { + !views + .get(*other) + .is_some_and(|theirs| theirs.contains(*node)) + }) + .count(); + let _ = writeln!( + out, + " HyParView's active views at the end: {:.1} neighbours on average, {} to {}; {one_ended} links in one end's view only", + sizes.iter().sum::() as f64 / sizes.len().max(1) as f64, + sizes.iter().min().copied().unwrap_or(0), + sizes.iter().max().copied().unwrap_or(0), + ); +} + /// A link with a longer round trip is slow (`eager_links`): over Tor, a slow circuit /// (`tor_like`). const SLOW_LINK_MS: u64 = 1000; @@ -822,12 +860,16 @@ fn mean(values: &[u64]) -> u64 { /// along eager links alone, by the links' latencies (the fastest such path, as the /// first copy of a push takes it), against writers' trees' (`trees`): how deep the /// tree is. Nothing for a way that keeps no such links. -fn eager_links(out: &mut String, nodes: &[AppState], net: &crate::transport::sim::SimNet) { +pub(super) fn eager_links( + out: &mut String, + nodes: &[AppState], + net: &crate::transport::sim::SimNet, +) { let mut pushes: HashMap> = HashMap::new(); // The round trips of eager and of lazy links, as each node measured them. let (mut eager_rtts, mut lazy_rtts) = (Vec::new(), Vec::new()); for node in nodes { - let Some(lazy) = node.dissemination.lazy() else { + let Some(lazy) = node.dissemination().lazy() else { return; }; let (eager, others): (Vec, Vec) = -- cgit v1.3.1