use std::fmt::Write as _;
use std::fs::File;
use std::io::Write as _;
use std::sync::{Mutex, OnceLock};
static SINK: OnceLock<Option<Mutex<File>>> = OnceLock::new();
fn sink() -> Option<&'static Mutex<File>> {
SINK.get_or_init(|| {
let path = std::env::var_os("MEMRA_HYPER_TRACE")?;
let mut file = File::create(&path)
.unwrap_or_else(|error| panic!("MEMRA_HYPER_TRACE={path:?}: {error}"));
writeln!(file, "format\tmemra-hidden-trace-v1").ok();
Some(Mutex::new(file))
})
.as_ref()
}
pub fn enabled() -> bool {
sink().is_some()
}
pub fn emit_tokens(token_ids: &[u32]) {
let Some(sink) = sink() else { return };
let ids = token_ids
.iter()
.map(u32::to_string)
.collect::<Vec<_>>()
.join(",");
let mut file = sink.lock().expect("hidden-trace sink poisoned");
writeln!(file, "tokens\t{ids}").ok();
}
pub fn emit_last_row(stage: &str, layer: i64, rows: usize, width: usize, data: &[f32]) {
let Some(sink) = sink() else { return };
if rows == 0 || width == 0 || data.len() != rows * width {
panic!(
"hidden-trace {stage}[{layer}]: {} values is not rows {rows} x width {width}",
data.len()
);
}
let row = &data[(rows - 1) * width..];
let mut line = String::with_capacity(width * 9 + 64);
let _ = write!(line, "stage\t{stage}\t{layer}\t{width}\t");
for (index, value) in row.iter().enumerate() {
if index != 0 {
line.push(',');
}
let _ = write!(line, "{:08x}", value.to_bits());
}
line.push('\n');
let mut file = sink.lock().expect("hidden-trace sink poisoned");
file.write_all(line.as_bytes()).ok();
}