use std::cell::RefCell;
use std::time::{Duration, Instant};
#[derive(Copy, Clone, Debug)]
pub enum SectionKind {
UploadWeights,
LayerOps1to3,
LayerQkvDeinterleave,
LayerChunkPrep,
LayerChunkCall,
ChunkGqaExpand,
ChunkAllocs,
ChunkEncBuild,
ChunkCommitWait,
LayerChunkOps8to9,
LayerAutoregOps5to9,
LayerLinearTotal,
LayerFullTotal,
FaOps1to4,
FaSdpaTotal,
FaSdpaKvDownloadCopy,
FaSdpaQDownloadPermuteUpload,
FaSdpaKernel,
FaSdpaOutDownloadPermuteUpload,
FaOps6to7,
LayerPostAttnFusedNorm,
LayerFfnDispatch,
LayerFfnPostResidual,
DnStatePingpongMemcpy,
DnQkvGpuSplit,
DnOuterPostAttnNorm,
DnOuterFfnDispatch,
DnOuterPostFfnResidual,
DnOuterChoreographyTotal,
FfnAllocScratch,
FfnPhaseAProj,
FfnBarrierAB,
FfnPhaseBRouteSilu,
FfnBarrierBC,
FfnPhaseCGateUpSharedDown,
FfnBarrierCD,
FfnPhaseDSilu,
FfnBarrierDE,
FfnPhaseEDown,
FfnBarrierEF,
FfnPhaseFReduce,
}
impl SectionKind {
fn idx(self) -> usize {
self as usize
}
fn label(self) -> &'static str {
match self {
SectionKind::UploadWeights => "upload_weights",
SectionKind::LayerOps1to3 => "layer.ops1_3",
SectionKind::LayerQkvDeinterleave => "layer.qkv_deinterleave",
SectionKind::LayerChunkPrep => "layer.chunk_prep",
SectionKind::LayerChunkCall => "layer.chunk_call",
SectionKind::ChunkGqaExpand => "chunk.gqa_expand",
SectionKind::ChunkAllocs => "chunk.allocs",
SectionKind::ChunkEncBuild => "chunk.enc_build",
SectionKind::ChunkCommitWait => "chunk.commit_wait",
SectionKind::LayerChunkOps8to9 => "layer.chunk_ops8_9",
SectionKind::LayerAutoregOps5to9 => "layer.autoreg_ops5_9",
SectionKind::LayerLinearTotal => "layer.linear_total",
SectionKind::LayerFullTotal => "layer.full_total",
SectionKind::FaOps1to4 => "fa.ops1_4",
SectionKind::FaSdpaTotal => "fa.sdpa_total",
SectionKind::FaSdpaKvDownloadCopy => "fa.sdpa.kv_dl_copy",
SectionKind::FaSdpaQDownloadPermuteUpload => "fa.sdpa.q_dl_perm_ul",
SectionKind::FaSdpaKernel => "fa.sdpa.kernel",
SectionKind::FaSdpaOutDownloadPermuteUpload => "fa.sdpa.out_dl_perm_ul",
SectionKind::FaOps6to7 => "fa.ops6_7",
SectionKind::LayerPostAttnFusedNorm => "layer.post_attn_fused_norm",
SectionKind::LayerFfnDispatch => "layer.ffn_dispatch",
SectionKind::LayerFfnPostResidual => "layer.ffn_post_residual",
SectionKind::DnStatePingpongMemcpy => "dn.state_pingpong_memcpy",
SectionKind::DnQkvGpuSplit => "dn.qkv_gpu_split",
SectionKind::DnOuterPostAttnNorm => "dn.outer_post_attn_norm",
SectionKind::DnOuterFfnDispatch => "dn.outer_ffn_dispatch",
SectionKind::DnOuterPostFfnResidual => "dn.outer_post_ffn_residual",
SectionKind::DnOuterChoreographyTotal => "dn.outer_choreography_total",
SectionKind::FfnAllocScratch => "ffn.alloc_scratch",
SectionKind::FfnPhaseAProj => "ffn.phase_a_proj",
SectionKind::FfnBarrierAB => "ffn.barrier_ab",
SectionKind::FfnPhaseBRouteSilu => "ffn.phase_b_route_silu",
SectionKind::FfnBarrierBC => "ffn.barrier_bc",
SectionKind::FfnPhaseCGateUpSharedDown => "ffn.phase_c_gate_up_shared_down",
SectionKind::FfnBarrierCD => "ffn.barrier_cd",
SectionKind::FfnPhaseDSilu => "ffn.phase_d_silu",
SectionKind::FfnBarrierDE => "ffn.barrier_de",
SectionKind::FfnPhaseEDown => "ffn.phase_e_down",
SectionKind::FfnBarrierEF => "ffn.barrier_ef",
SectionKind::FfnPhaseFReduce => "ffn.phase_f_reduce",
}
}
const COUNT: usize = 41;
}
#[derive(Default, Clone)]
struct Acc {
samples: Vec<u128>, }
impl Acc {
fn record(&mut self, dur: Duration) {
self.samples.push(dur.as_micros());
}
fn count(&self) -> usize {
self.samples.len()
}
fn sum_us(&self) -> u128 {
self.samples.iter().sum()
}
fn min_us(&self) -> u128 {
self.samples.iter().copied().min().unwrap_or(0)
}
fn max_us(&self) -> u128 {
self.samples.iter().copied().max().unwrap_or(0)
}
fn mean_us(&self) -> u128 {
if self.samples.is_empty() {
0
} else {
self.sum_us() / self.samples.len() as u128
}
}
fn percentile_us(&self, p: f64) -> u128 {
if self.samples.is_empty() {
return 0;
}
let mut s = self.samples.clone();
s.sort_unstable();
let idx = ((s.len() - 1) as f64 * p).round() as usize;
s[idx]
}
}
#[derive(Default, Clone)]
struct W5b8State {
accs: Vec<Acc>,
}
impl W5b8State {
fn new() -> Self {
Self {
accs: vec![Acc::default(); SectionKind::COUNT],
}
}
fn record(&mut self, kind: SectionKind, dur: Duration) {
if self.accs.is_empty() {
self.accs = vec![Acc::default(); SectionKind::COUNT];
}
self.accs[kind.idx()].record(dur);
}
}
thread_local! {
static W5B8: RefCell<W5b8State> = RefCell::new(W5b8State::new());
}
#[inline]
pub fn w5b8_enabled() -> bool {
std::env::var("HF2Q_PROFILE_W5B8").is_ok()
}
#[inline]
pub fn w5b17_enabled() -> bool {
std::env::var("HF2Q_PROFILE_W5B17").is_ok()
}
#[inline]
pub fn w5b22_enabled() -> bool {
std::env::var("HF2Q_PROFILE_W5B22").is_ok()
}
pub struct Section {
kind: SectionKind,
t0: Option<Instant>,
}
impl Section {
pub fn start(kind: SectionKind) -> Self {
let t0 = if w5b8_enabled() {
Some(Instant::now())
} else {
None
};
Self { kind, t0 }
}
pub fn start_w5b17(kind: SectionKind) -> Self {
let t0 = if w5b17_enabled() {
Some(Instant::now())
} else {
None
};
Self { kind, t0 }
}
pub fn start_w5b22(kind: SectionKind) -> Self {
let t0 = if w5b22_enabled() {
Some(Instant::now())
} else {
None
};
Self { kind, t0 }
}
}
impl Drop for Section {
fn drop(&mut self) {
if let Some(t0) = self.t0 {
let dur = t0.elapsed();
W5B8.with(|cell| cell.borrow_mut().record(self.kind, dur));
}
}
}
pub fn w5b8_print_and_reset(label: &str) {
if !w5b8_enabled() && !w5b17_enabled() && !w5b22_enabled() {
return;
}
W5B8.with(|cell| {
let mut state = cell.borrow_mut();
eprintln!("[W5B8_PROFILE] === section summary: {label} ===");
eprintln!(
"[W5B8_PROFILE] {:<26} {:>6} {:>10} {:>10} {:>10} {:>10} {:>10} {:>10}",
"section", "n", "sum_ms", "mean_ms", "min_ms", "max_ms", "p50_ms", "p95_ms"
);
let kinds = [
SectionKind::UploadWeights,
SectionKind::LayerOps1to3,
SectionKind::LayerQkvDeinterleave,
SectionKind::LayerChunkPrep,
SectionKind::LayerChunkCall,
SectionKind::ChunkGqaExpand,
SectionKind::ChunkAllocs,
SectionKind::ChunkEncBuild,
SectionKind::ChunkCommitWait,
SectionKind::LayerChunkOps8to9,
SectionKind::LayerAutoregOps5to9,
SectionKind::LayerLinearTotal,
SectionKind::LayerFullTotal,
SectionKind::FaOps1to4,
SectionKind::FaSdpaTotal,
SectionKind::FaSdpaKvDownloadCopy,
SectionKind::FaSdpaQDownloadPermuteUpload,
SectionKind::FaSdpaKernel,
SectionKind::FaSdpaOutDownloadPermuteUpload,
SectionKind::FaOps6to7,
SectionKind::LayerPostAttnFusedNorm,
SectionKind::LayerFfnDispatch,
SectionKind::LayerFfnPostResidual,
SectionKind::DnStatePingpongMemcpy,
SectionKind::DnQkvGpuSplit,
SectionKind::DnOuterPostAttnNorm,
SectionKind::DnOuterFfnDispatch,
SectionKind::DnOuterPostFfnResidual,
SectionKind::DnOuterChoreographyTotal,
SectionKind::FfnAllocScratch,
SectionKind::FfnPhaseAProj,
SectionKind::FfnBarrierAB,
SectionKind::FfnPhaseBRouteSilu,
SectionKind::FfnBarrierBC,
SectionKind::FfnPhaseCGateUpSharedDown,
SectionKind::FfnBarrierCD,
SectionKind::FfnPhaseDSilu,
SectionKind::FfnBarrierDE,
SectionKind::FfnPhaseEDown,
SectionKind::FfnBarrierEF,
SectionKind::FfnPhaseFReduce,
];
for k in kinds {
let acc = &state.accs[k.idx()];
if acc.count() == 0 {
continue;
}
eprintln!(
"[W5B8_PROFILE] {:<26} {:>6} {:>10.3} {:>10.3} {:>10.3} {:>10.3} {:>10.3} {:>10.3}",
k.label(),
acc.count(),
acc.sum_us() as f64 / 1000.0,
acc.mean_us() as f64 / 1000.0,
acc.min_us() as f64 / 1000.0,
acc.max_us() as f64 / 1000.0,
acc.percentile_us(0.50) as f64 / 1000.0,
acc.percentile_us(0.95) as f64 / 1000.0,
);
}
eprintln!("[W5B8_PROFILE] === end summary ===");
*state = W5b8State::new();
});
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn section_records_only_when_enabled() {
std::env::remove_var("HF2Q_PROFILE_W5B8");
{
let _t = Section::start(SectionKind::UploadWeights);
std::thread::sleep(Duration::from_millis(1));
}
W5B8.with(|cell| {
let s = cell.borrow();
assert_eq!(
s.accs[SectionKind::UploadWeights.idx()].count(),
0,
"section should not record when env unset"
);
});
std::env::set_var("HF2Q_PROFILE_W5B8", "1");
{
let _t = Section::start(SectionKind::UploadWeights);
std::thread::sleep(Duration::from_millis(2));
}
W5B8.with(|cell| {
let s = cell.borrow();
assert_eq!(s.accs[SectionKind::UploadWeights.idx()].count(), 1);
assert!(s.accs[SectionKind::UploadWeights.idx()].sum_us() >= 1_000);
});
std::env::remove_var("HF2Q_PROFILE_W5B8");
W5B8.with(|cell| *cell.borrow_mut() = W5b8State::new());
}
}