use perdix::buffer::Buffer;
use perdix::{Producer, AgentType};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::{Duration, Instant};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("╔══════════════════════════════════════════════╗");
println!("║ Perdix Async GPU Streaming Test ║");
println!("╚══════════════════════════════════════════════╝");
let n_slots = 4096;
let n_gpu_messages = 500;
println!("\nConfiguration:");
println!(" Buffer slots: {}", n_slots);
println!(" GPU messages: {}", n_gpu_messages);
println!("\nInitializing unified memory buffer...");
let buffer = Buffer::new(n_slots)?;
let (mut producer, consumer) = buffer.split();
let stop_flag = Arc::new(AtomicBool::new(false));
let stop_clone = stop_flag.clone();
let consumer_handle = thread::spawn(move || {
let mut consumer = consumer;
let mut total = 0u64;
let mut last_seq = None;
let start = Instant::now();
println!("[Consumer] Thread started - waiting for async GPU messages");
while !stop_clone.load(Ordering::Relaxed) {
if let Some(msg) = consumer.try_consume() {
if let Some(last) = last_seq {
if msg.seq != last + 1 {
println!("[Consumer] ERROR: Sequence gap! {} -> {}", last, msg.seq);
}
}
last_seq = Some(msg.seq);
if total < 5 || total % 100 == 0 || total == n_gpu_messages as u64 - 1 {
let text = String::from_utf8_lossy(&msg.payload);
println!("[Consumer] Message {}: {}", msg.seq, text.trim());
}
total += 1;
if total >= n_gpu_messages as u64 {
let elapsed = start.elapsed();
let throughput = total as f64 / elapsed.as_secs_f64();
println!("\n[Consumer] Received all {} messages in {:?}", total, elapsed);
println!("[Consumer] Throughput: {:.0} messages/second", throughput);
break;
}
} else {
thread::yield_now();
}
}
println!("[Consumer] Thread stopped. Total consumed: {}", total);
total
});
#[cfg(feature = "cuda")]
{
run_async_gpu_test(&mut producer, n_gpu_messages)?;
}
#[cfg(not(feature = "cuda"))]
{
println!("\n⚠️ CUDA not enabled - simulating with CPU producer");
for i in 0..n_gpu_messages {
let msg = format!("CPU Simulation Message #{:03}", i);
producer.try_produce(msg.as_bytes())?;
}
}
let timeout = Duration::from_secs(10);
let start = Instant::now();
while start.elapsed() < timeout {
if consumer_handle.is_finished() {
break;
}
thread::sleep(Duration::from_millis(100));
}
stop_flag.store(true, Ordering::Release);
let total = consumer_handle.join().unwrap();
println!("\n╔══════════════════════════════════════════════╗");
println!("║ Test Complete! ║");
println!("╠══════════════════════════════════════════════╣");
println!("║ Messages sent: {:24} ║", n_gpu_messages);
println!("║ Messages received: {:24} ║", total);
println!("║ Status: {} ║",
if total == n_gpu_messages as u64 { "SUCCESS ✅" } else { "PARTIAL ⚠️ " });
println!("╚══════════════════════════════════════════════╝");
Ok(())
}
#[cfg(feature = "cuda")]
fn run_async_gpu_test(producer: &mut Producer, n_messages: u32) -> Result<(), Box<dyn std::error::Error>> {
use perdix::buffer::gpu_arena::GpuTextArena;
println!("\n🚀 Launching ASYNC GPU kernel (no blocking)...");
let mut arena = GpuTextArena::new(1024 * 1024)?;
for i in 0..n_messages {
let text = format!("🚀 Async GPU Msg #{:04}", i);
let agent_type = match i % 7 {
0 => AgentType::System,
1 => AgentType::User,
2 => AgentType::Assistant,
3 => AgentType::Error,
4 => AgentType::Warning,
5 => AgentType::Info,
_ => AgentType::Debug,
};
arena.add_text(text.as_bytes(), agent_type)?;
}
println!(" Packing {} messages into arena...", n_messages);
let (num_contexts, num_bytes) = {
let (packed_contexts, text_data) = arena.pack();
(packed_contexts.len(), text_data.len())
};
println!(" Uploading to GPU ({} bytes text, {} contexts)...", num_bytes, num_contexts);
arena.upload_to_device_async()?;
let start = Instant::now();
producer.launch_async_gpu_kernel(&arena, n_messages)?;
let launch_time = start.elapsed();
println!(" ✅ Kernel launched in {:?} (returned immediately)", launch_time);
println!(" 📊 GPU is now streaming {} messages asynchronously...", n_messages);
println!(" ⏳ Consumer will receive messages as GPU produces them");
Ok(())
}