use datafusion_app::local_benchmarks::BenchmarkProgressReporter;
use indicatif::{ProgressBar, ProgressStyle};
use std::time::{Duration, Instant};
pub struct IndicatifProgressReporter {
pb: ProgressBar,
start_time: Instant,
concurrent: bool,
}
impl IndicatifProgressReporter {
pub fn new(query: &str, total_iterations: usize, concurrent: bool, concurrency: usize) -> Self {
let pb = ProgressBar::new(total_iterations as u64);
let query_display = if query.len() > 50 {
format!("{}...", &query[..47])
} else {
query.to_string()
};
let template = if concurrent {
format!(
"{{spinner:.green}} Benchmarking (concurrent, {} workers): {} [{{elapsed_precise}}]\n\
{{bar:40.cyan/blue}} {{pos}}/{{len}} ({{percent}}%) | {{msg}}",
concurrency, query_display
)
} else {
format!(
"{{spinner:.green}} Benchmarking: {} [{{elapsed_precise}}]\n\
{{bar:40.cyan/blue}} {{pos}}/{{len}} ({{percent}}%) | {{msg}}",
query_display
)
};
pb.set_style(
ProgressStyle::default_bar()
.template(&template)
.expect("Invalid progress template")
.progress_chars("━━╾─")
.tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "),
);
pb.enable_steady_tick(std::time::Duration::from_millis(100));
Self {
pb,
start_time: Instant::now(),
concurrent,
}
}
}
impl BenchmarkProgressReporter for IndicatifProgressReporter {
fn on_iteration_complete(&self, completed: usize, total: usize, _last_duration: Duration) {
self.pb.set_position(completed as u64);
let elapsed = self.start_time.elapsed();
if self.concurrent {
let throughput = if elapsed.as_secs_f64() > 0.0 {
completed as f64 / elapsed.as_secs_f64()
} else {
0.0
};
let remaining = total - completed;
let eta_secs = if throughput > 0.0 {
remaining as f64 / throughput
} else {
0.0
};
self.pb
.set_message(format!("{:.1} iter/s | ETA: {:.1}s", throughput, eta_secs));
} else {
let avg_time = elapsed.as_secs_f64() / completed as f64;
let remaining = total - completed;
let eta_secs = avg_time * remaining as f64;
self.pb
.set_message(format!("{:.2}s per iter | ETA: {:.1}s", avg_time, eta_secs));
}
}
fn finish(&self) {
self.pb.finish_and_clear();
}
}