spark_model/layers/glm5next_layer/
profile.rs1use spark_runtime::gpu::GpuBackend;
14use std::sync::atomic::{AtomicU64, Ordering::Relaxed};
15use std::time::Instant;
16
17pub const MHC: usize = 0;
18pub const NORM: usize = 1;
19pub const KDA: usize = 2;
20pub const DSA_PROJ: usize = 3;
21pub const DSA_INDEXER: usize = 4;
22pub const DSA_SELECT: usize = 5;
23pub const DSA_ATTEND: usize = 6;
24pub const REDUCE_ATTN: usize = 7;
25pub const MLP_DENSE: usize = 8;
26pub const MOE_ROUTER: usize = 9;
27pub const MOE_HOSTSYNC: usize = 10;
28pub const MOE_EXPERTS: usize = 11;
29pub const MOE_SHARED: usize = 12;
30pub const MOE_COMBINE: usize = 13;
31pub const REDUCE_MLP: usize = 14;
32pub const REDUCE_ATTN_ENQ: usize = 15;
37pub const REDUCE_MLP_ENQ: usize = 16;
38pub const REDUCE_ATTN_BAR: usize = 17;
49pub const REDUCE_MLP_BAR: usize = 18;
50pub const MHC_POST: usize = 19;
52pub const KDA_FRONT: usize = 20;
58pub const KDA_RECUR: usize = 21;
59pub const KDA_BACK: usize = 22;
60const N: usize = 23;
61
62const NAMES: [&str; N] = [
63 "mhc",
64 "norm",
65 "kda_mixer",
66 "dsa_proj",
67 "dsa_indexer",
68 "dsa_select",
69 "dsa_attend",
70 "reduce_attn",
71 "mlp_dense",
72 "moe_router",
73 "moe_hostsync",
74 "moe_experts",
75 "moe_shared",
76 "moe_combine",
77 "reduce_mlp",
78 "reduce_attn_enq",
79 "reduce_mlp_enq",
80 "reduce_attn_bar",
81 "reduce_mlp_bar",
82 "mhc_post",
83 "kda_front",
84 "kda_recur",
85 "kda_back",
86];
87
88static NANOS: [AtomicU64; N] = [const { AtomicU64::new(0) }; N];
89static CALLS: [AtomicU64; N] = [const { AtomicU64::new(0) }; N];
90static STEPS: AtomicU64 = AtomicU64::new(0);
91
92fn level() -> u8 {
100 static L: std::sync::OnceLock<u8> = std::sync::OnceLock::new();
101 *L.get_or_init(|| match std::env::var("AVAROK_GLM_PROFILE").as_deref() {
102 Ok("1") => 1,
103 Ok("2") => 2,
104 _ => 0,
105 })
106}
107
108pub fn on() -> bool {
109 level() != 0
110}
111
112pub fn full() -> bool {
114 level() == 1
115}
116
117pub fn start() -> Option<Instant> {
119 full().then(Instant::now)
120}
121
122pub fn start_hot() -> Option<Instant> {
124 on().then(Instant::now)
125}
126
127pub fn end(bucket: usize, t0: Option<Instant>, gpu: &dyn GpuBackend, stream: u64) {
128 let _ = end_us(bucket, t0, gpu, stream);
129}
130
131pub fn end_us(bucket: usize, t0: Option<Instant>, gpu: &dyn GpuBackend, stream: u64) -> f64 {
133 let Some(t0) = t0 else { return 0.0 };
134 let _ = gpu.synchronize(stream);
135 let ns = t0.elapsed().as_nanos() as u64;
136 NANOS[bucket].fetch_add(ns, Relaxed);
137 CALLS[bucket].fetch_add(1, Relaxed);
138 ns as f64 / 1e3
139}
140
141pub fn trace_on() -> bool {
148 static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
149 *ON.get_or_init(|| std::env::var("AVAROK_GLM_ROUTE_TRACE").as_deref() == Ok("1"))
150}
151
152thread_local! {
153 static ROUTE: std::cell::RefCell<Vec<i32>> = const { std::cell::RefCell::new(Vec::new()) };
155}
156
157pub fn stash_route(ids: &[i32]) {
159 if !trace_on() {
160 return;
161 }
162 ROUTE.with(|r| {
163 let mut v = r.borrow_mut();
164 v.clear();
165 v.extend_from_slice(ids);
166 });
167}
168
169pub fn trace_bar(site: &str, layer: usize, moe: bool, us: f64) {
172 if !trace_on() {
173 return;
174 }
175 let step = STEPS.load(Relaxed);
176 ROUTE.with(|r| {
177 let v = r.borrow();
178 let ids = v
179 .iter()
180 .map(|x| x.to_string())
181 .collect::<Vec<_>>()
182 .join(",");
183 tracing::warn!(
184 "GLMTRACE step={step} site={site} L={layer} moe={} bar_us={us:.1} ids={ids}",
185 u8::from(moe)
186 );
187 });
188}
189
190pub fn probe_buf(gpu: &dyn GpuBackend) -> u64 {
192 static P: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
193 *P.get_or_init(|| gpu.alloc(4).map(|p| p.0).unwrap_or(0))
194}
195
196pub fn end_nosync(bucket: usize, t0: Option<Instant>) {
198 let Some(t0) = t0 else { return };
199 NANOS[bucket].fetch_add(t0.elapsed().as_nanos() as u64, Relaxed);
200 CALLS[bucket].fetch_add(1, Relaxed);
201}
202
203pub fn step() {
206 if !on() {
207 return;
208 }
209 let s = STEPS.fetch_add(1, Relaxed) + 1;
210 if !s.is_multiple_of(8) {
211 return;
212 }
213 let total: u64 = NANOS.iter().map(|n| n.load(Relaxed)).sum();
214 let mut rows: Vec<(usize, u64, u64)> = (0..N)
215 .map(|i| (i, NANOS[i].load(Relaxed), CALLS[i].load(Relaxed)))
216 .collect();
217 rows.sort_by_key(|r| std::cmp::Reverse(r.1));
218 let mut out = format!(
219 "GLM decode profile after {s} steps โ {:.2} ms/token measured under profiling\n",
220 total as f64 / 1e6 / s as f64
221 );
222 for (i, ns, calls) in rows {
223 if calls == 0 {
224 continue;
225 }
226 out += &format!(
227 " {:<13} {:>8.2} ms/tok {:>6.1}% {:>5} calls/tok {:>7.1} us/call\n",
228 NAMES[i],
229 ns as f64 / 1e6 / s as f64,
230 100.0 * ns as f64 / total.max(1) as f64,
231 calls / s,
232 ns as f64 / 1e3 / calls.max(1) as f64,
233 );
234 }
235 tracing::warn!("{out}");
236}