use peat_btle::observer::DisconnectReason;
use peat_btle::{NodeId, PeatMesh, PeatMeshConfig};
use std::time::Instant;
const NUM_NODES: usize = 10;
const ITERATIONS: usize = 1000;
#[cfg(feature = "legacy-chat")]
const CHAT_MESSAGES: usize = 500;
fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
println!("=== PEAT-BTLE Profiling Stress Test ===\n");
let total_start = Instant::now();
println!("[Phase 1] Creating {} mesh nodes...", NUM_NODES);
let phase_start = Instant::now();
let meshes = create_meshes(NUM_NODES);
println!(
" Created {} nodes in {:?}\n",
meshes.len(),
phase_start.elapsed()
);
println!(
"[Phase 2] Document sync ({} sync cycles)...",
ITERATIONS / 10
);
let phase_start = Instant::now();
test_document_sync(&meshes, ITERATIONS / 10);
println!(" Completed in {:?}\n", phase_start.elapsed());
#[cfg(feature = "legacy-chat")]
{
println!("[Phase 3] Chat CRDT ({} messages)...", CHAT_MESSAGES);
let phase_start = Instant::now();
test_chat_operations(&meshes, CHAT_MESSAGES);
println!(" Completed in {:?}\n", phase_start.elapsed());
}
println!(
"[Phase 4] Emergency/ACK cycles ({} cycles)...",
ITERATIONS / 10
);
let phase_start = Instant::now();
test_emergency_cycles(&meshes, ITERATIONS / 10);
println!(" Completed in {:?}\n", phase_start.elapsed());
println!(
"[Phase 5] Peer churn simulation ({} connect/disconnect cycles)...",
ITERATIONS
);
let phase_start = Instant::now();
test_peer_churn(&meshes, ITERATIONS);
println!(" Completed in {:?}\n", phase_start.elapsed());
println!("[Phase 6] Document size verification...");
let phase_start = Instant::now();
test_document_sizes(&meshes);
println!(" Completed in {:?}\n", phase_start.elapsed());
println!("=== Profiling Complete ===");
println!("Total time: {:?}", total_start.elapsed());
println!("\nMemory stats (if available):");
print_memory_stats();
}
fn create_meshes(count: usize) -> Vec<PeatMesh> {
(0..count)
.map(|i| {
let node_id = NodeId::new(0x10000000 + i as u32);
let config = PeatMeshConfig::new(node_id, &format!("NODE-{:02}", i), "PROFILE_TEST")
.with_encryption(*b"profile-test-key-32-bytes-pad!!!");
PeatMesh::new(config)
})
.collect()
}
fn test_document_sync(meshes: &[PeatMesh], iterations: usize) {
let now_ms = now();
for i in 0..iterations {
let documents: Vec<_> = meshes.iter().map(|m| m.build_document()).collect();
for (recv_idx, receiver) in meshes.iter().enumerate() {
for (send_idx, doc) in documents.iter().enumerate() {
if recv_idx != send_idx {
let peer_id = format!("peer-{}", send_idx);
receiver.on_ble_discovered(
&peer_id,
Some(&format!("PEAT_TEST-{:08X}", 0x10000000 + send_idx as u32)),
-60,
Some("PROFILE_TEST"),
now_ms + i as u64 * 100,
);
receiver.on_ble_connected(&peer_id, now_ms + i as u64 * 100);
let _ = receiver.on_ble_data_received(&peer_id, doc, now_ms + i as u64 * 100);
}
}
}
}
}
#[cfg(feature = "legacy-chat")]
fn test_chat_operations(meshes: &[PeatMesh], message_count: usize) {
let now_ms = now();
for (i, mesh) in meshes.iter().enumerate() {
for (j, _) in meshes.iter().enumerate() {
if i != j {
let peer_id = format!("chat-peer-{}", j);
mesh.on_ble_discovered(
&peer_id,
Some(&format!("PEAT_TEST-{:08X}", 0x10000000 + j as u32)),
-60,
Some("PROFILE_TEST"),
now_ms,
);
mesh.on_ble_connected(&peer_id, now_ms);
}
}
}
for i in 0..message_count {
let sender_idx = i % meshes.len();
let sender = &meshes[sender_idx];
let timestamp = now_ms + i as u64;
if let Some(doc) = sender.send_chat(
&format!("NODE-{:02}", sender_idx),
&format!("Test message #{} from node {}", i, sender_idx),
timestamp,
) {
for (recv_idx, receiver) in meshes.iter().enumerate() {
if recv_idx != sender_idx {
let peer_id = format!("chat-peer-{}", sender_idx);
let _ = receiver.on_ble_data_received(&peer_id, &doc, timestamp);
}
}
}
if i > 0 && i % 10 == 0 {
let replier_idx = (sender_idx + 1) % meshes.len();
let replier = &meshes[replier_idx];
let reply_timestamp = timestamp + 1;
if let Some(doc) = replier.send_chat_reply(
&format!("NODE-{:02}", replier_idx),
"ACK",
0x10000000 + sender_idx as u32,
timestamp,
reply_timestamp,
) {
for (recv_idx, receiver) in meshes.iter().enumerate() {
if recv_idx != replier_idx {
let peer_id = format!("chat-peer-{}", replier_idx);
let _ = receiver.on_ble_data_received(&peer_id, &doc, reply_timestamp);
}
}
}
}
}
for mesh in meshes {
let _ = mesh.all_chat_messages();
let _ = mesh.chat_messages_since(now_ms + (message_count / 2) as u64);
}
}
fn test_emergency_cycles(meshes: &[PeatMesh], cycles: usize) {
let now_ms = now();
for (i, mesh) in meshes.iter().enumerate() {
for (j, _) in meshes.iter().enumerate() {
if i != j {
let peer_id = format!("emerg-peer-{}", j);
mesh.on_ble_discovered(
&peer_id,
Some(&format!("PEAT_TEST-{:08X}", 0x10000000 + j as u32)),
-60,
Some("PROFILE_TEST"),
now_ms,
);
mesh.on_ble_connected(&peer_id, now_ms);
}
}
}
for i in 0..cycles {
let sender_idx = i % meshes.len();
let sender = &meshes[sender_idx];
let timestamp = now_ms + i as u64 * 1000;
let emergency_doc = sender.send_emergency(timestamp);
for (recv_idx, receiver) in meshes.iter().enumerate() {
if recv_idx != sender_idx {
let peer_id = format!("emerg-peer-{}", sender_idx);
let _ = receiver.on_ble_data_received(&peer_id, &emergency_doc, timestamp);
}
}
for (acker_idx, acker) in meshes.iter().enumerate() {
if acker_idx != sender_idx {
let ack_doc = acker.send_ack(timestamp + acker_idx as u64);
for (recv_idx, receiver) in meshes.iter().enumerate() {
if recv_idx != acker_idx {
let peer_id = format!("emerg-peer-{}", acker_idx);
let _ = receiver.on_ble_data_received(&peer_id, &ack_doc, timestamp + 100);
}
}
}
}
sender.clear_emergency();
}
}
fn test_peer_churn(meshes: &[PeatMesh], cycles: usize) {
let now_ms = now();
for i in 0..cycles {
let mesh = &meshes[i % meshes.len()];
let peer_id = format!("churn-peer-{}", i % 50); let peer_node = NodeId::new(0x20000000 + (i % 50) as u32);
mesh.on_ble_discovered(
&peer_id,
Some(&format!("PEAT_TEST-{:08X}", peer_node.as_u32())),
-60 - (i % 40) as i8,
Some("PROFILE_TEST"),
now_ms + i as u64,
);
mesh.on_ble_connected(&peer_id, now_ms + i as u64 + 1);
let doc = mesh.build_document();
let _ = mesh.on_ble_data_received(&peer_id, &doc, now_ms + i as u64 + 2);
mesh.on_ble_disconnected(&peer_id, DisconnectReason::RemoteRequest);
if i % 10 == 0 {
let _ = mesh.tick(now_ms + i as u64 + 100);
}
}
}
fn test_document_sizes(_meshes: &[PeatMesh]) {
let now_ms = now();
println!(" Creating fresh nodes for size verification...");
let fresh_meshes = create_meshes(2);
let peer_id = "size-peer-1";
fresh_meshes[0].on_ble_discovered(
peer_id,
Some(&format!("PEAT_TEST-{:08X}", 0x10000001)),
-60,
Some("PROFILE_TEST"),
now_ms,
);
fresh_meshes[0].on_ble_connected(peer_id, now_ms);
fresh_meshes[1].on_ble_discovered(
"size-peer-0",
Some(&format!("PEAT_TEST-{:08X}", 0x10000000)),
-60,
Some("PROFILE_TEST"),
now_ms,
);
fresh_meshes[1].on_ble_connected("size-peer-0", now_ms);
let baseline_doc = fresh_meshes[0].build_document();
println!(
" Baseline document size (no chat): {} bytes",
baseline_doc.len()
);
#[cfg(feature = "legacy-chat")]
{
for i in 0..50 {
if let Some(doc) = fresh_meshes[0].send_chat("TEST", &format!("Msg {}", i), now_ms + i)
{
let _ = fresh_meshes[1].on_ble_data_received("size-peer-0", &doc, now_ms + i);
}
}
println!(" Document sizes after 50 chat messages:");
for (i, mesh) in fresh_meshes.iter().enumerate() {
let doc = mesh.build_document();
let status = if doc.len() <= 512 { "OK" } else { "OVER MTU!" };
println!(" Fresh Node {}: {} bytes [{}]", i, doc.len(), status);
}
println!("\n Chat message counts:");
println!(" Node 0 local: {}", fresh_meshes[0].chat_count());
println!(" Expected sync limit: 8 (CHAT_SYNC_LIMIT), local max: 32 (CHAT_MAX_MESSAGES)");
let chat_doc = fresh_meshes[0].build_document();
let chat_overhead = chat_doc.len() - baseline_doc.len();
println!("\n Size breakdown:");
println!(
" Baseline (counter + peripheral + encryption): {} bytes",
baseline_doc.len()
);
println!(
" Chat overhead (8 sync messages): {} bytes",
chat_overhead
);
println!(" Total: {} bytes (MTU limit: 512)", chat_doc.len());
}
}
fn now() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis() as u64
}
fn print_memory_stats() {
if let Ok(status) = std::fs::read_to_string("/proc/self/status") {
for line in status.lines() {
if line.starts_with("VmRSS:")
|| line.starts_with("VmHWM:")
|| line.starts_with("VmSize:")
{
println!(" {}", line);
}
}
}
}