llam 0.1.1

Safe, Go-style Rust bindings for the LLAM runtime
use std::time::{Duration, Instant};

fn main() {
    let seconds = std::env::args()
        .nth(1)
        .and_then(|value| value.parse::<u64>().ok())
        .unwrap_or(5);
    let workers = std::env::args()
        .nth(2)
        .and_then(|value| value.parse::<usize>().ok())
        .unwrap_or(64);

    llam::Runtime::builder()
        .profile(llam::Profile::ReleaseFast)
        .dynamic_workers(true)
        .run(move || stress(Duration::from_secs(seconds), workers))
        .expect("LLAM-rs stress failed");
}

fn stress(duration: Duration, workers: usize) -> llam::Result<()> {
    let deadline = Instant::now() + duration;
    let (tx, rx) = llam::channel::bounded::<u64>(1024)?;
    let mut group = llam::TaskGroup::new()?;

    for id in 0..workers {
        let tx = tx.clone();
        group.spawn(move || {
            let mut n = id as u64;
            while Instant::now() < deadline {
                if tx.send_timeout(n, Duration::from_millis(10)).is_ok() {
                    n = n.wrapping_add(workers as u64);
                }
                llam::task::yield_now();
            }
        })?;
    }
    drop(tx);

    let mut received = 0u64;
    loop {
        match rx.recv_timeout(Duration::from_millis(1)) {
            Ok(_) => received += 1,
            Err(error) if error.is_timed_out() || error.is_closed() => {
                if Instant::now() >= deadline {
                    break;
                }
            }
            Err(error) => return Err(error),
        }
    }
    group.join()?;
    println!("llam-rs stress ok: workers={workers} duration={duration:?} received={received}");
    Ok(())
}