wowlab_engine/cli/sim/
progress.rs1use std::sync::{
2 Mutex,
3 atomic::{AtomicU32, Ordering},
4};
5
6use wowlab_common::output;
7use wowlab_engine_ports::{ProgressDone, ProgressSink, ProgressStart, ProgressTick};
8use wowlab_types::sim::FastMap;
9
10pub(super) struct ConsoleProgress {
11 bar: Option<output::ProgressBar>,
12 completed: AtomicU32,
13 per_chunk: Mutex<FastMap<String, u32>>,
14}
15
16impl ConsoleProgress {
17 pub(super) fn new(total: u32, show_progress: bool) -> Self {
18 Self {
19 bar: show_progress.then(|| output::ProgressBar::new(u64::from(total), "Simulating...")),
20 completed: AtomicU32::new(0),
21 per_chunk: Mutex::new(FastMap::default()),
22 }
23 }
24
25 pub(super) fn finish(&self) {
26 if let Some(ref bar) = self.bar {
27 bar.finish("");
28 }
29 }
30
31 fn advance(&self, chunk_id: &str, chunk_completed: u32) -> u32 {
32 let delta = {
33 let mut guard = self
34 .per_chunk
35 .lock()
36 .unwrap_or_else(std::sync::PoisonError::into_inner);
37 let prev = guard.entry(chunk_id.to_string()).or_insert(0);
38 let delta = chunk_completed.saturating_sub(*prev);
39
40 *prev = chunk_completed;
41
42 delta
43 };
44
45 self.completed.fetch_add(delta, Ordering::Relaxed) + delta
46 }
47}
48
49impl ProgressSink for ConsoleProgress {
50 fn on_start(&self, _meta: ProgressStart) {}
51
52 fn on_tick(&self, tick: ProgressTick) {
53 let global = self.advance(&tick.chunk_id, tick.iterations_completed);
54
55 if let Some(ref bar) = self.bar {
56 match (tick.running_mean_dps, tick.throughput_sps) {
57 (Some(mean), Some(tp)) => bar.tick_with_stats(u64::from(global), mean, tp),
58 _ => bar.tick(u64::from(global)),
59 }
60 }
61 }
62
63 fn on_complete(&self, done: ProgressDone) {
64 let global = self.advance(&done.chunk_id, done.iterations_completed);
65
66 if let Some(ref bar) = self.bar {
67 bar.tick(u64::from(global));
68 }
69 }
70}