aboutsummaryrefslogtreecommitdiffstats
path: root/src/simtest/bench.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-06 19:54:09 +0100
committertv <tv@krebsco.de>2026-11-06 19:54:09 +0100
commit5994b49412c058079639585501a78e6458fdbb6f (patch)
treeca78aa3cd7d0d6d2a48bfa42d61afcddb8efd6df /src/simtest/bench.rs
parent7c0c318dca3054be6c7bacf5a4b3f5a4e47cc949 (diff)
HyParView (slim)
Diffstat (limited to 'src/simtest/bench.rs')
-rw-r--r--src/simtest/bench.rs58
1 files changed, 50 insertions, 8 deletions
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<usize> = 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::<usize>() 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<String, Vec<String>> = 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<String>, Vec<String>) =