use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use peat_protocol::discovery::capability_query::{CapabilityQuery, CapabilityQueryEngine};
use peat_protocol::discovery::geographic::{GeographicBeacon, GeographicDiscovery};
use peat_protocol::discovery::GeoCoordinate;
use peat_protocol::models::capability::{Capability, CapabilityExt, CapabilityType};
use peat_protocol::models::cell::{CellConfig, CellConfigExt, CellState, CellStateExt};
use peat_protocol::models::node::{NodeConfig, NodeConfigExt};
use std::collections::HashSet;
fn bench_cell_formation_throughput(c: &mut Criterion) {
let mut group = c.benchmark_group("cell_formation_throughput");
for node_count in [10, 50, 100].iter() {
group.throughput(Throughput::Elements(*node_count as u64));
group.bench_with_input(
BenchmarkId::from_parameter(node_count),
node_count,
|b, &count| {
b.iter(|| {
let nodes: Vec<NodeConfig> = (0..count)
.map(|i| {
let mut node = NodeConfig::new("UAV".to_string());
node.id = format!("node_{}", i);
node.add_capability(Capability::new(
format!("cap_{}", i),
"Test Cap".to_string(),
CapabilityType::Sensor,
0.9,
));
node
})
.collect();
let mut cells = Vec::new();
for chunk in nodes.chunks(5) {
let config = CellConfig::new(5);
let mut cell = CellState::new(config);
for node in chunk {
cell.members.push(node.id.clone());
for cap in &node.capabilities {
cell.capabilities.push(cap.clone());
}
}
cells.push(cell);
}
black_box(cells)
});
},
);
}
group.finish();
}
fn bench_leader_election(c: &mut Criterion) {
let mut group = c.benchmark_group("leader_election");
for cell_size in [5, 10, 20].iter() {
group.bench_with_input(
BenchmarkId::from_parameter(cell_size),
cell_size,
|b, &size| {
let config = CellConfig::new(size);
let mut cell = CellState::new(config);
let members: Vec<String> = (0..size).map(|i| format!("node_{}", i)).collect();
for member in &members {
cell.members.push(member.clone());
}
b.iter(|| {
let mut sorted_members: Vec<_> = cell.members.iter().collect();
sorted_members.sort();
let leader = sorted_members.first().map(|s| (*s).clone());
let mut test_cell = cell.clone();
test_cell.leader_id = leader;
if let Some(ref mut ts) = test_cell.timestamp {
ts.seconds += 1;
}
black_box(test_cell)
});
},
);
}
group.finish();
}
fn bench_capability_aggregation(c: &mut Criterion) {
let mut group = c.benchmark_group("capability_aggregation");
for cap_count in [10, 50, 100].iter() {
group.throughput(Throughput::Elements(*cap_count as u64));
group.bench_with_input(
BenchmarkId::from_parameter(cap_count),
cap_count,
|b, &count| {
let nodes: Vec<NodeConfig> = (0..count)
.map(|i| {
let mut node = NodeConfig::new("UAV".to_string());
node.id = format!("node_{}", i);
for j in 0..((i % 3) + 3) {
node.add_capability(Capability::new(
format!("cap_{}_{}", i, j),
format!("Capability {}", j),
match j % 4 {
0 => CapabilityType::Sensor,
1 => CapabilityType::Communication,
2 => CapabilityType::Compute,
_ => CapabilityType::Mobility,
},
0.8 + (j as f32 * 0.02),
));
}
node
})
.collect();
b.iter(|| {
let mut aggregated = Vec::new();
for node in &nodes {
aggregated.extend(node.capabilities.clone());
}
let mut seen = HashSet::new();
aggregated.retain(|cap| seen.insert(cap.id.clone()));
black_box(aggregated)
});
},
);
}
group.finish();
}
fn bench_rebalancing_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("rebalancing_operations");
group.bench_function("cell_merge", |b| {
let config1 = CellConfig::new(10);
let mut cell1 = CellState::new(config1);
let config2 = CellConfig::new(10);
let mut cell2 = CellState::new(config2);
for i in 0..3 {
cell1.members.push(format!("node_1_{}", i));
cell1.capabilities.push(Capability::new(
format!("cap_1_{}", i),
"Cap".to_string(),
CapabilityType::Sensor,
0.9,
));
}
for i in 0..3 {
cell2.members.push(format!("node_2_{}", i));
cell2.capabilities.push(Capability::new(
format!("cap_2_{}", i),
"Cap".to_string(),
CapabilityType::Communication,
0.85,
));
}
b.iter(|| {
let mut merged = cell1.clone();
for member in &cell2.members {
merged.members.push(member.clone());
}
merged.capabilities.extend(cell2.capabilities.clone());
if let Some(ref mut ts) = merged.timestamp {
ts.seconds += 1;
}
black_box(merged)
});
});
group.bench_function("cell_split", |b| {
let config = CellConfig::new(20);
let mut cell = CellState::new(config);
for i in 0..10 {
cell.members.push(format!("node_{}", i));
cell.capabilities.push(Capability::new(
format!("cap_{}", i),
"Cap".to_string(),
CapabilityType::Sensor,
0.9,
));
}
b.iter(|| {
let members: Vec<String> = cell.members.to_vec();
let mid = members.len() / 2;
let config1 = CellConfig::new(10);
let mut cell1 = CellState::new(config1);
let config2 = CellConfig::new(10);
let mut cell2 = CellState::new(config2);
for (i, member) in members.iter().enumerate() {
if i < mid {
cell1.members.push(member.clone());
} else {
cell2.members.push(member.clone());
}
}
for (i, cap) in cell.capabilities.iter().enumerate() {
if i < cell.capabilities.len() / 2 {
cell1.capabilities.push(cap.clone());
} else {
cell2.capabilities.push(cap.clone());
}
}
black_box((cell1, cell2))
});
});
group.finish();
}
fn bench_crdt_sync(c: &mut Criterion) {
let mut group = c.benchmark_group("crdt_sync_latency");
for peer_count in [2, 5, 10].iter() {
group.bench_with_input(
BenchmarkId::from_parameter(peer_count),
peer_count,
|b, &count| {
let cells: Vec<CellState> = (0..count)
.map(|i| {
let config = CellConfig::new(10);
let mut cell = CellState::new(config);
cell.members.push(format!("node_{}", i));
if let Some(ref mut ts) = cell.timestamp {
ts.seconds = i as u64;
}
cell
})
.collect();
b.iter(|| {
let mut merged = cells[0].clone();
for cell in &cells[1..] {
let cell_ts = cell.timestamp.as_ref().map(|t| t.seconds).unwrap_or(0);
let merged_ts = merged.timestamp.as_ref().map(|t| t.seconds).unwrap_or(0);
if cell_ts > merged_ts {
merged = cell.clone();
}
}
for cell in &cells {
for member in &cell.members {
if !merged.members.contains(member) {
merged.members.push(member.clone());
}
}
}
black_box(merged)
});
},
);
}
group.finish();
}
fn bench_geographic_discovery(c: &mut Criterion) {
let mut group = c.benchmark_group("geographic_discovery");
for beacon_count in [10, 50, 100].iter() {
group.throughput(Throughput::Elements(*beacon_count as u64));
group.bench_with_input(
BenchmarkId::from_parameter(beacon_count),
beacon_count,
|b, &count| {
let beacons: Vec<GeographicBeacon> = (0..count)
.map(|i| {
let lat = 37.7749 + (i as f64 * 0.001); let lon = -122.4194 + (i as f64 * 0.001);
let pos = GeoCoordinate::new(lat, lon, 100.0).unwrap();
GeographicBeacon::new(format!("node_{}", i), pos, vec![])
})
.collect();
b.iter(|| {
let mut discovery = GeographicDiscovery::new("observer".to_string());
for beacon in &beacons {
discovery.process_beacon(beacon.clone());
}
black_box(discovery)
});
},
);
}
group.finish();
}
fn bench_capability_query(c: &mut Criterion) {
let mut group = c.benchmark_group("capability_query");
for node_count in [10, 50, 100].iter() {
group.throughput(Throughput::Elements(*node_count as u64));
group.bench_with_input(
BenchmarkId::from_parameter(node_count),
node_count,
|b, &count| {
let nodes: Vec<NodeConfig> = (0..count)
.map(|i| {
let mut node = NodeConfig::new("UAV".to_string());
node.id = format!("node_{}", i);
node.add_capability(Capability::new(
format!("sensor_{}", i),
"Sensor".to_string(),
CapabilityType::Sensor,
0.7 + ((i % 3) as f32 * 0.1),
));
if i % 2 == 0 {
node.add_capability(Capability::new(
format!("comms_{}", i),
"Comms".to_string(),
CapabilityType::Communication,
0.8,
));
}
node
})
.collect();
let query = CapabilityQuery::builder()
.require_type(CapabilityType::Sensor)
.prefer_type(CapabilityType::Communication)
.min_confidence(0.7)
.limit(10)
.build();
let engine = CapabilityQueryEngine::new();
b.iter(|| {
let matches = engine.query_platforms(&query, &nodes);
black_box(matches)
});
},
);
}
group.finish();
}
criterion_group!(
benches,
bench_cell_formation_throughput,
bench_leader_election,
bench_capability_aggregation,
bench_rebalancing_operations,
bench_crdt_sync,
bench_geographic_discovery,
bench_capability_query
);
criterion_main!(benches);