use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::time::{Duration, Instant};
static TRACE_ENABLED: AtomicBool = AtomicBool::new(false);
static START_TIME_US: AtomicU64 = AtomicU64::new(0);
pub fn enable_tracing() {
START_TIME_US.store(
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_micros() as u64,
Ordering::Relaxed,
);
TRACE_ENABLED.store(true, Ordering::Release);
}
pub fn disable_tracing() {
TRACE_ENABLED.store(false, Ordering::Release);
}
#[inline]
pub fn is_tracing_enabled() -> bool {
TRACE_ENABLED.load(Ordering::Acquire)
}
pub struct TimingGuard {
name: &'static str,
start: Option<Instant>,
budget_us: u64,
}
impl TimingGuard {
#[inline]
pub fn new(name: &'static str, budget_us: u64) -> Self {
if is_tracing_enabled() {
Self {
name,
start: Some(Instant::now()),
budget_us,
}
} else {
Self {
name,
start: None,
budget_us,
}
}
}
#[inline]
pub fn with_default_budget(name: &'static str) -> Self {
Self::new(name, 1000)
}
#[inline]
pub fn render(name: &'static str) -> Self {
Self::new(name, 16_000)
}
#[inline]
pub fn collect(name: &'static str) -> Self {
Self::new(name, 100_000)
}
}
impl Drop for TimingGuard {
fn drop(&mut self) {
if let Some(start) = self.start {
let elapsed = start.elapsed();
let elapsed_us = elapsed.as_micros() as u64;
let exceeded = elapsed_us > self.budget_us;
let relative_ms = (std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_micros() as u64)
.saturating_sub(START_TIME_US.load(Ordering::Relaxed))
/ 1000;
let status = if exceeded { "⚠️" } else { "✓" };
eprintln!(
"[+{:04}ms] [TRACE] {status} {} <- {:.2}ms (budget: {}μs)",
relative_ms,
self.name,
elapsed_us as f64 / 1000.0,
self.budget_us
);
}
}
}
#[repr(C, align(64))] #[derive(Debug, Clone, Default)]
pub struct SimdStats {
pub count: u64,
pub sum: f64,
pub sum_sq: f64,
pub min: f64,
pub max: f64,
}
impl SimdStats {
pub fn new() -> Self {
Self {
count: 0,
sum: 0.0,
sum_sq: 0.0,
min: f64::MAX,
max: f64::MIN,
}
}
#[inline]
pub fn update(&mut self, value: f64) {
self.count += 1;
self.sum += value;
self.sum_sq += value * value;
self.min = self.min.min(value);
self.max = self.max.max(value);
}
#[inline]
pub fn mean(&self) -> f64 {
if self.count == 0 {
0.0
} else {
self.sum / self.count as f64
}
}
#[inline]
pub fn variance(&self) -> f64 {
if self.count < 2 {
return 0.0;
}
let n = self.count as f64;
(self.sum_sq - (self.sum * self.sum) / n) / (n - 1.0)
}
#[inline]
pub fn std_dev(&self) -> f64 {
self.variance().sqrt()
}
#[inline]
pub fn cv_percent(&self) -> f64 {
let mean = self.mean();
if mean.abs() < 1e-9 {
0.0
} else {
(self.std_dev() / mean) * 100.0
}
}
pub fn reset(&mut self) {
*self = Self::new();
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BrickType {
Collect,
Render,
Compute,
Network,
Storage,
}
impl BrickType {
#[must_use]
pub fn default_budget_us(&self) -> u64 {
match self {
Self::Collect => 100_000, Self::Render => 16_000, Self::Compute => 1_000, Self::Network => 500_000, Self::Storage => 50_000, }
}
#[must_use]
pub fn cv_threshold(&self) -> f64 {
match self {
Self::Render => 10.0, Self::Compute => 15.0, Self::Collect => 25.0, Self::Network => 50.0, Self::Storage => 30.0, }
}
}
#[derive(Debug)]
pub struct BrickProfiler {
stats: std::collections::HashMap<String, (BrickType, SimdStats)>,
enabled: bool,
}
impl Default for BrickProfiler {
fn default() -> Self {
Self::new()
}
}
impl BrickProfiler {
#[must_use]
pub fn new() -> Self {
Self {
stats: std::collections::HashMap::new(),
enabled: is_tracing_enabled(),
}
}
pub fn profile<F, R>(&mut self, name: &str, brick_type: BrickType, f: F) -> R
where
F: FnOnce() -> R,
{
if !self.enabled {
return f();
}
let start = std::time::Instant::now();
let result = f();
let elapsed_us = start.elapsed().as_micros() as f64;
let (_, stats) = self
.stats
.entry(name.to_string())
.or_insert_with(|| (brick_type, SimdStats::new()));
stats.update(elapsed_us);
result
}
#[must_use]
pub fn should_escalate(&self, name: &str) -> bool {
if let Some((brick_type, stats)) = self.stats.get(name) {
let cv = stats.cv_percent();
cv > brick_type.cv_threshold()
} else {
false
}
}
#[must_use]
pub fn get_stats(&self, name: &str) -> Option<&SimdStats> {
self.stats.get(name).map(|(_, s)| s)
}
#[must_use]
pub fn summary(&self) -> String {
let mut lines = vec!["=== Brick Profiler Summary ===".to_string()];
let mut sorted: Vec<_> = self.stats.iter().collect();
sorted.sort_by(|a, b| {
let a_total = a.1 .1.sum;
let b_total = b.1 .1.sum;
b_total
.partial_cmp(&a_total)
.unwrap_or(std::cmp::Ordering::Equal)
});
for (name, (brick_type, stats)) in sorted {
let budget = brick_type.default_budget_us();
let avg = stats.mean();
let cv = stats.cv_percent();
let status = if avg > budget as f64 { "⚠️" } else { "✓" };
let escalate = if self.should_escalate(name) {
" [ESCALATE]"
} else {
""
};
lines.push(format!(
"{status} {name} ({brick_type:?}): avg={avg:.0}μs cv={cv:.1}% n={}{escalate}",
stats.count
));
}
lines.join("\n")
}
}
#[derive(Debug, Clone)]
pub struct TraceEvent {
pub name: String,
pub duration: Duration,
pub timestamp_us: u64,
pub budget_exceeded: bool,
pub budget_us: Option<u64>,
}
#[derive(Debug, Clone, Default)]
pub struct TraceStats {
pub count: u64,
pub total_duration: Duration,
pub min_duration: Duration,
pub max_duration: Duration,
pub budget_violations: u64,
pub budget_us: u64,
}
impl TraceStats {
fn new(duration: Duration, budget_us: u64, exceeded: bool) -> Self {
Self {
count: 1,
total_duration: duration,
min_duration: duration,
max_duration: duration,
budget_violations: u64::from(exceeded),
budget_us,
}
}
fn update(&mut self, duration: Duration, exceeded: bool) {
self.count += 1;
self.total_duration += duration;
self.min_duration = self.min_duration.min(duration);
self.max_duration = self.max_duration.max(duration);
if exceeded {
self.budget_violations += 1;
}
}
pub fn avg_duration(&self) -> Duration {
if self.count == 0 {
Duration::ZERO
} else {
self.total_duration / self.count as u32
}
}
pub fn cv_percent(&self) -> f64 {
if self.count < 2 {
return 0.0;
}
let avg = self.avg_duration().as_secs_f64();
if avg < 1e-9 {
return 0.0;
}
let range = self
.max_duration
.checked_sub(self.min_duration)
.unwrap_or_default()
.as_secs_f64();
(range / avg) * 50.0 }
pub fn efficiency_percent(&self) -> f64 {
if self.budget_us == 0 {
return 100.0;
}
let avg_us = self.avg_duration().as_micros() as f64;
((self.budget_us as f64) / avg_us * 100.0).min(100.0)
}
}
#[derive(Debug, Clone, Copy)]
pub struct EscalationThresholds {
pub cv_percent: f64,
pub efficiency_percent: f64,
pub max_traces_per_sec: u32,
}
impl Default for EscalationThresholds {
fn default() -> Self {
Self {
cv_percent: 15.0,
efficiency_percent: 25.0,
max_traces_per_sec: 100,
}
}
}
#[derive(Debug)]
pub struct PerfTracer {
stats: HashMap<String, TraceStats>,
recent_events: Vec<TraceEvent>,
max_recent: usize,
start_time: Instant,
thresholds: EscalationThresholds,
traces_this_second: u32,
last_second: u64,
}
impl Default for PerfTracer {
fn default() -> Self {
Self::new()
}
}
impl PerfTracer {
#[must_use]
pub fn new() -> Self {
Self {
stats: HashMap::new(),
recent_events: Vec::with_capacity(100),
max_recent: 100,
start_time: Instant::now(),
thresholds: EscalationThresholds::default(),
traces_this_second: 0,
last_second: 0,
}
}
#[must_use]
pub fn with_thresholds(thresholds: EscalationThresholds) -> Self {
Self {
thresholds,
..Self::new()
}
}
pub fn trace_with_budget<F, R>(&mut self, name: &str, budget_us: u64, f: F) -> R
where
F: FnOnce() -> R,
{
let start = Instant::now();
let result = f();
let duration = start.elapsed();
self.record_trace(name, duration, budget_us);
result
}
pub fn trace<F, R>(&mut self, name: &str, f: F) -> R
where
F: FnOnce() -> R,
{
self.trace_with_budget(name, 1000, f) }
fn record_trace(&mut self, name: &str, duration: Duration, budget_us: u64) {
let timestamp_us = self.start_time.elapsed().as_micros() as u64;
let budget_exceeded = duration.as_micros() as u64 > budget_us;
let current_second = timestamp_us / 1_000_000;
if current_second != self.last_second {
self.traces_this_second = 0;
self.last_second = current_second;
}
self.traces_this_second += 1;
let event = TraceEvent {
name: name.to_string(),
duration,
timestamp_us,
budget_exceeded,
budget_us: Some(budget_us),
};
if let Some(stats) = self.stats.get_mut(name) {
stats.update(duration, budget_exceeded);
} else {
self.stats.insert(
name.to_string(),
TraceStats::new(duration, budget_us, budget_exceeded),
);
}
if self.recent_events.len() >= self.max_recent {
self.recent_events.remove(0);
}
self.recent_events.push(event);
}
#[must_use]
pub fn should_escalate(&self, name: &str) -> bool {
if let Some(stats) = self.stats.get(name) {
let cv = stats.cv_percent();
let efficiency = stats.efficiency_percent();
cv > self.thresholds.cv_percent || efficiency < self.thresholds.efficiency_percent
} else {
false
}
}
#[must_use]
pub fn get_stats(&self, name: &str) -> Option<&TraceStats> {
self.stats.get(name)
}
#[must_use]
pub fn all_stats(&self) -> &HashMap<String, TraceStats> {
&self.stats
}
#[must_use]
pub fn summary(&self) -> String {
let mut lines = vec![
"=== Performance Trace Summary ===".to_string(),
String::new(),
];
let mut sorted: Vec<_> = self.stats.iter().collect();
sorted.sort_by(|a, b| b.1.total_duration.cmp(&a.1.total_duration));
for (name, stats) in sorted {
let avg_us = stats.avg_duration().as_micros();
let max_us = stats.max_duration.as_micros();
let cv = stats.cv_percent();
let eff = stats.efficiency_percent();
let status = if stats.budget_violations > 0 {
"⚠️"
} else {
"✓"
};
lines.push(format!(
"{status} {name}: avg={avg_us}μs max={max_us}μs count={} cv={cv:.1}% eff={eff:.0}%",
stats.count
));
if self.should_escalate(name) {
lines.push(format!(
" └── ESCALATE: CV={cv:.1}% > {}% OR eff={eff:.0}% < {}%",
self.thresholds.cv_percent, self.thresholds.efficiency_percent
));
}
}
lines.join("\n")
}
#[must_use]
pub fn export_renacer_format(&self) -> String {
let mut lines = vec!["# renacer-compatible trace export".to_string()];
lines.push(format!("# timestamp: {:?}", self.start_time.elapsed()));
for (name, stats) in &self.stats {
lines.push(format!(
"TRACE {} count={} total_us={} avg_us={} max_us={} cv={:.2} eff={:.2} violations={}",
name,
stats.count,
stats.total_duration.as_micros(),
stats.avg_duration().as_micros(),
stats.max_duration.as_micros(),
stats.cv_percent(),
stats.efficiency_percent(),
stats.budget_violations
));
}
lines.join("\n")
}
pub fn clear(&mut self) {
self.stats.clear();
self.recent_events.clear();
}
}