atproto blogging
1//! Performance timing utilities for instrumentation.
2//!
3//! Provides a cross-platform wrapper around Performance.now() for WASM
4//! and a fallback for native builds.
5
6/// Get the current high-resolution timestamp in milliseconds.
7///
8/// On WASM, this uses `Performance.now()` from the Web Performance API.
9/// On native builds, uses std::time::Instant for actual timing.
10#[cfg(all(target_family = "wasm", target_os = "unknown"))]
11pub fn now() -> f64 {
12 web_sys::window()
13 .and_then(|w| w.performance())
14 .map(|p| p.now())
15 .unwrap_or(0.0)
16}
17
18#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
19pub fn now() -> f64 {
20 use std::time::Instant;
21 static START: std::sync::OnceLock<Instant> = std::sync::OnceLock::new();
22 let start = START.get_or_init(Instant::now);
23 start.elapsed().as_secs_f64() * 1000.0
24}
25
26/// Measure the execution time of a closure and log it.
27///
28/// Returns the closure's result and logs the elapsed time via tracing.
29#[allow(dead_code)]
30pub fn measure<T, F: FnOnce() -> T>(label: &str, f: F) -> T {
31 let start = now();
32 let result = f();
33 let elapsed = now() - start;
34 tracing::debug!(elapsed_ms = elapsed, "{}", label);
35 result
36}
37
38/// A guard that logs elapsed time when dropped.
39///
40/// Useful for timing blocks of code without closures.
41#[allow(dead_code)]
42pub struct TimingGuard {
43 label: &'static str,
44 start: f64,
45}
46
47impl TimingGuard {
48 pub fn new(label: &'static str) -> Self {
49 Self {
50 label,
51 start: now(),
52 }
53 }
54}
55
56impl Drop for TimingGuard {
57 fn drop(&mut self) {
58 let elapsed = now() - self.start;
59 tracing::debug!(elapsed_ms = elapsed, "{}", self.label);
60 }
61}