use std::cell::RefCell;
use std::rc::Rc;
use std::time::{Duration, Instant};
use runite::channel::mpsc;
use runite::time::interval;
fn crunch(job: u32) -> u64 {
let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
for round in 0..25_000_000u64 {
hash ^= round.wrapping_add(u64::from(job));
hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
}
hash
}
#[derive(Default)]
struct Progress {
finished: u32,
ticks: u32,
worst_jitter: Duration,
}
#[runite::main]
async fn main() {
let inline = std::env::args().any(|arg| arg == "--blocking");
let jobs = 4u32;
let progress = Rc::new(RefCell::new(Progress::default()));
let heartbeat = {
let progress = Rc::clone(&progress);
runite::spawn(async move {
let period = Duration::from_millis(25);
let mut ticker = interval(period);
let mut last = Instant::now();
loop {
ticker.tick().await;
let now = Instant::now();
let jitter = now.duration_since(last).saturating_sub(period);
last = now;
let mut progress = progress.borrow_mut();
progress.ticks += 1;
progress.worst_jitter = progress.worst_jitter.max(jitter);
let done = progress.finished;
print!(
"\r[heartbeat {:>3}] jobs done: {done}/{jobs} ",
progress.ticks
);
use std::io::Write as _;
let _ = std::io::stdout().flush();
if done == jobs {
break;
}
}
})
};
runite::time::sleep(Duration::from_millis(30)).await;
let started = Instant::now();
let (results_tx, mut results_rx) = mpsc::channel::<(u32, u64)>(8);
if inline {
for job in 0..jobs {
let digest = crunch(job);
results_tx.send((job, digest)).await.expect("send result");
}
} else {
for job in 0..jobs {
let results_tx = results_tx.clone();
runite::spawn_blocking(move || {
let digest = crunch(job);
let _ = results_tx.try_send((job, digest));
})
.expect("blocking pool should accept the job")
;
}
}
drop(results_tx);
while let Some((job, digest)) = results_rx.recv().await {
progress.borrow_mut().finished += 1;
println!("\rjob {job} finished (digest {digest:#018x})");
}
let _ = heartbeat.await;
let progress = progress.borrow();
println!(
"\n{} jobs in {:?}; heartbeat ticked {} times, worst jitter {:?}",
jobs,
started.elapsed(),
progress.ticks,
progress.worst_jitter,
);
if inline {
println!("(--blocking mode: the jitter above IS the jank users would feel)");
} else {
println!("(offloaded: the loop never missed a beat while the pool did the work)");
}
}