logwise::declare_logging_domain!();
#[cfg(not(target_arch = "wasm32"))]
use std::thread;
#[cfg(target_arch = "wasm32")]
use wasm_safe_thread as thread;
use some_executor::task::{Configuration, Task};
#[cfg(not(target_arch = "wasm32"))]
use std::time::{Duration, Instant};
#[cfg(target_arch = "wasm32")]
use web_time::{Duration, Instant};
#[cfg(target_arch = "wasm32")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
const NUM_ITERATIONS: usize = 25;
struct TimingStats {
samples: Vec<Duration>,
}
impl TimingStats {
fn new() -> Self {
Self {
samples: Vec::new(),
}
}
fn add_sample(&mut self, duration: Duration) {
self.samples.push(duration);
}
fn report(&self) {
if self.samples.is_empty() {
logwise::error_sync!("No samples collected!");
return;
}
let total: Duration = self.samples.iter().sum();
let avg = total / self.samples.len() as u32;
let min = self.samples.iter().min().unwrap();
let max = self.samples.iter().max().unwrap();
let avg_micros = avg.as_micros() as f64;
let variance = self
.samples
.iter()
.map(|d| {
let diff = d.as_micros() as f64 - avg_micros;
diff * diff
})
.sum::<f64>()
/ self.samples.len() as f64;
let std_dev = variance.sqrt();
logwise::warn_sync!("=== Timing Statistics ===");
logwise::warn_sync!("Samples: {samples}", samples = self.samples.len());
logwise::warn_sync!("Average: {avg}µs", avg = format!("{:.3}", avg_micros));
logwise::warn_sync!(
"Min: {min}µs",
min = format!("{:.3}", min.as_micros() as f64)
);
logwise::warn_sync!(
"Max: {max}µs",
max = format!("{:.3}", max.as_micros() as f64)
);
logwise::warn_sync!("Std Dev: {std_dev}µs", std_dev = format!("{:.3}", std_dev));
logwise::warn_sync!("Distribution:");
let buckets = [
(0.0, 10.0, " <10µs"),
(10.0, 50.0, " 10-50µs"),
(50.0, 100.0, "50-100µs"),
(100.0, 500.0, "100-500µs"),
(500.0, 1000.0, "500µs-1ms"),
(1000.0, f64::INFINITY, " >1ms"),
];
for (min_us, max_us, label) in &buckets {
let count = self
.samples
.iter()
.filter(|d| {
let us = d.as_micros() as f64;
us >= *min_us && us < *max_us
})
.count();
if count > 0 {
let percentage = (count as f64 / self.samples.len() as f64) * 100.0;
logwise::warn_sync!(
"{label}: {count} ({percentage}%)",
label = *label,
count = format!("{:3}", count),
percentage = format!("{:5.1}", percentage)
);
}
}
}
}
#[cfg(not(target_arch = "wasm32"))]
fn main() {
logwise::warn_sync!("=== submit_to_main_thread Latency Benchmark ===");
app_window::application::main(|| {
thread::spawn(|| {
let t = Task::without_notifications(
"submit_to_main_thread_benchmark".to_string(),
Configuration::default(),
async {
run_benchmark().await;
},
);
t.spawn_static_current();
});
});
}
#[cfg(target_arch = "wasm32")]
fn main() {}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen_test::wasm_bindgen_test]
async fn wasm_main() {
assert!(app_window::application::is_main_thread());
let (c, r) = r#continue::continuation();
logwise::info_sync!("WILL call main thread");
app_window::application::main(move || {
logwise::warn_sync!("=== submit_to_main_thread_benchmark ===");
let t = Task::without_notifications(
"submit_to_main_thread_benchmark".to_string(),
Configuration::default(),
async move {
logwise::info_sync!("WASM main thread started");
run_benchmark().await;
c.send(());
},
);
t.spawn_static_current();
});
logwise::info_sync!("Awaiting benchmark completion...");
r.await;
logwise::info_sync!("Benchmark completed, exiting...");
}
async fn run_benchmark() {
logwise::warn_sync!(
"\nRunning {iterations} iterations...",
iterations = NUM_ITERATIONS
);
let mut stats = TimingStats::new();
let mut senders = Vec::new();
let mut futures = Vec::new();
for _ in 0..NUM_ITERATIONS {
let (tx, rx) = r#continue::continuation();
senders.push(tx);
futures.push(rx);
}
thread::spawn(move || {
logwise::info_sync!(
"Background thread started, will submit {count} tasks",
count = senders.len()
);
for (s, sender) in senders.drain(..).enumerate() {
eprintln!("Submitting task {}/{}", s + 1, NUM_ITERATIONS);
let start_time = Instant::now();
let task_label = format!("submit_to_main_thread_benchmark_task_{s}");
app_window::application::submit_to_main_thread(task_label, move || {
let elapsed = start_time.elapsed();
sender.send((s, elapsed));
});
thread::sleep(Duration::from_millis(20));
}
logwise::info_sync!(
"Background thread finished submitting all {count} tasks",
count = NUM_ITERATIONS
);
});
logwise::warn_sync!(
"Starting to collect {count} results...",
count = futures.len()
);
for (_i, recv) in futures.into_iter().enumerate() {
let r = recv.await;
stats.add_sample(r.1);
}
logwise::warn_sync!("Finished collecting all results!");
stats.report();
#[cfg(not(target_arch = "wasm32"))]
std::process::exit(0);
}