1use crate::pool::Pool;
17use crate::qtensor::QTensor;
18use cortiq_core::{CmfModel, TensorDtype};
19use std::sync::Arc;
20
21const DEAD: i64 = -1;
22const FP8_NAN: u8 = 0x7f;
23const E8M0_NAN: u8 = 0xff;
24
25pub(crate) mod prof {
29 use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
30 use std::time::Instant;
31
32 pub static TOKENS: AtomicU64 = AtomicU64::new(0);
33 pub static LAYER_VISITS: AtomicU64 = AtomicU64::new(0);
34 pub static ATTN_NS: AtomicU64 = AtomicU64::new(0);
35 pub static SPARSE_NS: AtomicU64 = AtomicU64::new(0);
36 pub static ATTN_OTHER_NS: AtomicU64 = AtomicU64::new(0);
37 pub static MOE_NS: AtomicU64 = AtomicU64::new(0);
38 pub static ENGRAM_NS: AtomicU64 = AtomicU64::new(0);
39 pub static HEAD_NS: AtomicU64 = AtomicU64::new(0);
40 pub static TOTAL_NS: AtomicU64 = AtomicU64::new(0);
41 pub static MOE_CALLS: AtomicU64 = AtomicU64::new(0);
42 pub static GPU_MOE_CALLS: AtomicU64 = AtomicU64::new(0);
43 pub static CPU_MOE_CALLS: AtomicU64 = AtomicU64::new(0);
44 pub static COLD_EXPERTS: AtomicU64 = AtomicU64::new(0);
45 pub static GPU_ATTN_CALLS: AtomicU64 = AtomicU64::new(0);
46 pub static GPU_ATTN_FALLBACKS: AtomicU64 = AtomicU64::new(0);
47 static REPORTED: AtomicBool = AtomicBool::new(false);
48
49 #[inline]
50 pub fn on() -> bool {
51 static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
52 *ON.get_or_init(|| std::env::var("CMF_DSV41_PROF").is_ok_and(|v| v != "0"))
53 }
54
55 #[inline]
56 pub fn start() -> Option<Instant> {
57 on().then(Instant::now)
58 }
59
60 #[inline]
61 pub fn add(dst: &AtomicU64, started: Option<Instant>) {
62 if let Some(started) = started {
63 dst.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed);
64 }
65 }
66
67 #[inline]
68 pub fn note_token(layers: usize) {
69 if on() {
70 TOKENS.fetch_add(1, Ordering::Relaxed);
71 LAYER_VISITS.fetch_add(layers as u64, Ordering::Relaxed);
72 }
73 }
74
75 #[inline]
76 pub fn note_moe() {
77 if on() {
78 MOE_CALLS.fetch_add(1, Ordering::Relaxed);
79 }
80 }
81
82 #[inline]
83 pub fn note_gpu_moe() {
84 if on() {
85 GPU_MOE_CALLS.fetch_add(1, Ordering::Relaxed);
86 }
87 }
88
89 #[inline]
90 pub fn note_cpu_moe() {
91 if on() {
92 CPU_MOE_CALLS.fetch_add(1, Ordering::Relaxed);
93 }
94 }
95
96 #[inline]
97 pub fn note_cold(count: usize) {
98 if on() {
99 COLD_EXPERTS.fetch_add(count as u64, Ordering::Relaxed);
100 }
101 }
102
103 pub fn note_gpu_attn() {
104 if on() {
105 GPU_ATTN_CALLS.fetch_add(1, Ordering::Relaxed);
106 }
107 }
108
109 pub fn note_gpu_attn_fallback() {
110 if on() {
111 GPU_ATTN_FALLBACKS.fetch_add(1, Ordering::Relaxed);
112 }
113 }
114
115 pub fn report() {
121 if !on() || REPORTED.swap(true, Ordering::Relaxed) {
122 return;
123 }
124 let tokens = TOKENS.load(Ordering::Relaxed).max(1) as f64;
125 let layers = LAYER_VISITS.load(Ordering::Relaxed);
126 let ns = |counter: &AtomicU64| counter.load(Ordering::Relaxed) as f64;
127 let attn = ns(&ATTN_NS);
128 let sparse = ns(&SPARSE_NS);
129 let attn_other = ns(&ATTN_OTHER_NS);
130 let moe = ns(&MOE_NS);
131 let engram = ns(&ENGRAM_NS);
132 let head = ns(&HEAD_NS);
133 let total = ns(&TOTAL_NS);
134 let dense = (total - attn - moe - engram - head).max(0.0);
135 eprintln!(
136 "[dsv41-profile] tokens={} layer_visits={} per_token_ms: attention={:.2} sparse_attend={:.2} attention_other={:.2} moe={:.2} engram={:.2} head={:.2} dense_other={:.2} total={:.2}",
137 tokens as u64,
138 layers,
139 attn / 1e6 / tokens,
140 sparse / 1e6 / tokens,
141 attn_other / 1e6 / tokens,
142 moe / 1e6 / tokens,
143 engram / 1e6 / tokens,
144 head / 1e6 / tokens,
145 dense / 1e6 / tokens,
146 total / 1e6 / tokens,
147 );
148 eprintln!(
149 "[dsv41-profile] moe_calls={} gpu_moe_calls={} cpu_moe_calls={} cold_experts={} gpu_attn_calls={} gpu_attn_fallbacks={}",
150 MOE_CALLS.load(Ordering::Relaxed),
151 GPU_MOE_CALLS.load(Ordering::Relaxed),
152 CPU_MOE_CALLS.load(Ordering::Relaxed),
153 COLD_EXPERTS.load(Ordering::Relaxed),
154 GPU_ATTN_CALLS.load(Ordering::Relaxed),
155 GPU_ATTN_FALLBACKS.load(Ordering::Relaxed),
156 );
157 #[cfg(feature = "gpu")]
158 {
159 let fills = crate::gpu_wgpu::DSV4_FILLS.load(Ordering::Relaxed);
160 let fill_bytes = crate::gpu_wgpu::DSV4_FILL_BYTES.load(Ordering::Relaxed);
161 let fill_ns = crate::gpu_wgpu::DSV4_FILL_NS.load(Ordering::Relaxed);
162 let submits = crate::gpu_wgpu::SUBMITS.load(Ordering::Relaxed);
163 let passes = crate::gpu_wgpu::PASSES.load(Ordering::Relaxed);
164 let upload_bytes = crate::gpu_wgpu::UPLOAD_BYTES.load(Ordering::Relaxed);
165 let upload_ns = crate::gpu_wgpu::UPLOAD_NS.load(Ordering::Relaxed);
166 eprintln!(
167 "[dsv41-profile] gpu_counters fills={} fill_bytes={} submits={} passes={} upload_bytes={} upload_ms={:.2} refill_ms={:.2} resident_bytes={} vram_budget={}",
168 fills,
169 fill_bytes,
170 submits,
171 passes,
172 upload_bytes,
173 upload_ns as f64 / 1e6,
174 fill_ns as f64 / 1e6,
175 crate::gpu_wgpu::resident_bytes(),
176 crate::gpu_wgpu::device_vram_budget(),
177 );
178 eprintln!(
179 "[dsv41-profile] gpu_moe_host_encode_ms={:.2} gpu_moe_wait_ms={:.2} chain_encode_ms={:.2} chain_wait_ms={:.2} chain_layers={} chain_runs={}",
180 crate::gpu_wgpu::MOE_ENC_NS.load(Ordering::Relaxed) as f64 / 1e6,
181 crate::gpu_wgpu::MOE_WAIT_NS.load(Ordering::Relaxed) as f64 / 1e6,
182 crate::gpu_wgpu::CHAIN_ENC_NS.load(Ordering::Relaxed) as f64 / 1e6,
183 crate::gpu_wgpu::CHAIN_WAIT_NS.load(Ordering::Relaxed) as f64 / 1e6,
184 crate::gpu_wgpu::CHAIN_LAYERS.load(Ordering::Relaxed),
185 crate::gpu_wgpu::CHAIN_RUNS.load(Ordering::Relaxed),
186 );
187 eprintln!(
188 "[dsv41-profile] gpu_attn_frame_encode_ms={:.2} gpu_attn_frame_wait_ms={:.2}",
189 crate::gpu_wgpu::ATT_ENC_NS.load(Ordering::Relaxed) as f64 / 1e6,
190 crate::gpu_wgpu::ATT_WAIT_NS.load(Ordering::Relaxed) as f64 / 1e6,
191 );
192 }
193 }
194}
195
196#[inline]
202fn bf16_roundtrip(value: f32) -> f32 {
203 let bits = value.to_bits();
204 let round = 0x7fff + ((bits >> 16) & 1);
205 f32::from_bits(bits.wrapping_add(round) & 0xffff_0000)
206}
207
208#[inline]
209fn bf16_inplace(values: &mut [f32]) {
210 for value in values {
211 *value = bf16_roundtrip(*value);
212 }
213}
214
215#[inline]
216fn trace_stats(stage: &str, position: usize, layer: Option<usize>, v: &[f32]) {
217 if std::env::var_os("CMF_DSV41_TRACE").is_none() {
218 return;
219 }
220 let mean = v.iter().copied().sum::<f32>() / v.len().max(1) as f32;
221 let sum = v.iter().copied().sum::<f32>();
222 let min = v.iter().copied().fold(f32::INFINITY, f32::min);
223 let max = v.iter().copied().fold(f32::NEG_INFINITY, f32::max);
224 let l2 = v.iter().map(|x| x * x).sum::<f32>().sqrt();
225 let full = std::env::var_os("CMF_DSV41_TRACE_FULL").is_some()
226 && std::env::var("CMF_DSV41_TRACE_POS")
227 .ok()
228 .and_then(|p| p.parse::<usize>().ok())
229 .is_some_and(|p| p == position);
230 let head: Vec<f32> = if full {
231 v.to_vec()
232 } else {
233 v.iter().take(8).copied().collect()
234 };
235 match layer {
236 Some(layer) => eprintln!(
237 "dsv41_trace stage={stage} position={position} layer={layer} mean={mean:.9e} sum={sum:.9e} min={min:.9e} max={max:.9e} l2={l2:.9e} head={head:?}"
238 ),
239 None => eprintln!(
240 "dsv41_trace stage={stage} position={position} mean={mean:.9e} sum={sum:.9e} min={min:.9e} max={max:.9e} l2={l2:.9e} head={head:?}"
241 ),
242 }
243}
244
245#[inline]
246fn trace_indices(position: usize, layer: usize, values: &[usize]) {
247 if std::env::var_os("CMF_DSV41_TRACE").is_none() {
248 return;
249 }
250 eprintln!("dsv41_trace stage=idxs position={position} layer={layer} values={values:?}");
251}
252
253#[inline]
254fn trace_index_scores(
255 position: usize,
256 layer: usize,
257 scores: &[f32],
258 picked: &[usize],
259 candidate: Option<&[bool]>,
260 window_len: usize,
261 compressed_len: usize,
262 pending_len: usize,
263) {
264 if std::env::var_os("CMF_DSV41_TRACE_INDEX").is_none() {
265 return;
266 }
267 if let Some(filter) = std::env::var("CMF_DSV41_TRACE_POS")
268 .ok()
269 .and_then(|p| p.parse::<usize>().ok())
270 {
271 if filter != position {
272 return;
273 }
274 }
275 let mut order: Vec<usize> = (0..scores.len()).collect();
276 order.sort_by(|&a, &b| scores[b].total_cmp(&scores[a]).then_with(|| a.cmp(&b)));
277 let finite_ties: Vec<(usize, usize)> = (0..scores.len())
278 .flat_map(|a| ((a + 1)..scores.len()).map(move |b| (a, b)))
279 .filter(|&(a, b)| scores[a].is_finite() && scores[a].to_bits() == scores[b].to_bits())
280 .collect();
281 let top: Vec<(usize, f32)> = order.iter().take(12).map(|&i| (i, scores[i])).collect();
282 let candidate_ids: Vec<usize> = candidate
283 .map(|mask| {
284 mask.iter()
285 .enumerate()
286 .filter_map(|(i, &keep)| keep.then_some(i))
287 .collect()
288 })
289 .unwrap_or_default();
290 eprintln!(
291 "dsv41_trace stage=index_scores position={position} layer={layer} window_len={window_len} compressed_len={compressed_len} pending_len={pending_len} picked={picked:?} top={top:?} ties={finite_ties:?} candidate_ids={candidate_ids:?}"
292 );
293}
294
295#[inline]
302fn trace_moe(
303 position: usize,
304 layer: usize,
305 image: bool,
306 logits: &[f32],
307 scores: &[f32],
308 bias: &[f32],
309 picks: &[usize],
310) {
311 if std::env::var_os("CMF_DSV41_TRACE_MOE").is_none() {
312 return;
313 }
314 if let Some(filter) = std::env::var("CMF_DSV41_TRACE_POS")
315 .ok()
316 .and_then(|p| p.parse::<usize>().ok())
317 {
318 if filter != position {
319 return;
320 }
321 }
322 let shifted: Vec<f32> = scores
323 .iter()
324 .enumerate()
325 .map(|(i, &s)| s + bias.get(i).copied().unwrap_or(0.0))
326 .collect();
327 let mut order: Vec<usize> = (0..shifted.len()).collect();
328 order.sort_by(|&a, &b| {
329 shifted[b]
330 .partial_cmp(&shifted[a])
331 .unwrap_or(std::cmp::Ordering::Equal)
332 .then_with(|| a.cmp(&b))
333 });
334 let ties: Vec<(usize, usize)> = (0..shifted.len())
335 .flat_map(|a| ((a + 1)..shifted.len()).map(move |b| (a, b)))
336 .filter(|&(a, b)| shifted[a].to_bits() == shifted[b].to_bits())
337 .collect();
338 eprintln!(
339 "dsv41_trace stage=moe position={position} layer={layer} image={image} logits={logits:?} scores={scores:?} bias={bias:?} shifted={shifted:?} order={order:?} picks={picks:?} ties={ties:?}"
340 );
341}
342
343#[inline]
344fn sigmoid(x: f32) -> f32 {
345 1.0 / (1.0 + (-x).exp())
346}
347
348#[inline]
351pub fn fp8_e4m3(byte: u8) -> f32 {
352 if (byte & 0x7f) == FP8_NAN {
353 return f32::NAN;
354 }
355 let sign = if byte & 0x80 != 0 { -1.0 } else { 1.0 };
356 let exp = (byte >> 3) & 0x0f;
357 let mant = byte & 0x07;
358 if exp == 0 {
359 sign * (mant as f32) * 2.0f32.powi(-9)
360 } else {
361 sign * (1.0 + mant as f32 / 8.0) * 2.0f32.powi(exp as i32 - 7)
362 }
363}
364
365#[inline]
369pub fn e8m0_scale(byte: u8) -> f32 {
370 if byte == E8M0_NAN {
371 f32::NAN
372 } else {
373 2.0f32.powi(byte as i32 - 127)
374 }
375}
376
377#[inline]
382fn round_ties_even(x: f32) -> i32 {
383 let lo = x.floor() as i32;
384 let frac = x - lo as f32;
385 if frac > 0.5 || (frac == 0.5 && (lo & 1) != 0) {
386 lo + 1
387 } else {
388 lo
389 }
390}
391
392fn e4m3_round(x: f32) -> f32 {
393 if !x.is_finite() {
394 return if x.is_sign_negative() { -448.0 } else { 448.0 };
395 }
396 let sign = if x.is_sign_negative() { 0x80 } else { 0 };
397 let ax = x.abs().min(448.0);
398 if ax == 0.0 {
399 return 0.0;
400 }
401 let byte = if ax < 2.0f32.powi(-6) {
402 let mant = round_ties_even(ax * 2.0f32.powi(9));
406 if mant >= 8 {
407 sign | 0x08
408 } else {
409 sign | mant.clamp(0, 7) as u8
410 }
411 } else {
412 let exp = ((ax.to_bits() >> 23) & 0xff) as i32 - 127;
416 let mut mant = round_ties_even((ax / 2.0f32.powi(exp) - 1.0) * 8.0);
417 let mut exp = exp;
418 if mant >= 8 {
419 exp += 1;
420 mant = 0;
421 }
422 let exp_field = exp + 7;
423 if exp_field > 15 {
424 sign | (15 << 3) | 6
429 } else {
430 let mant = if exp_field == 15 { mant.min(6) } else { mant };
434 sign | ((exp_field.clamp(1, 15) as u8) << 3) | (mant.clamp(0, 7) as u8)
435 }
436 };
437 fp8_e4m3(byte)
438}
439
440fn round_e8m0_scale(raw: f32) -> f32 {
441 if !raw.is_finite() || raw <= 0.0 {
442 return 2.0f32.powi(-127);
443 }
444 let exponent = raw.log2().ceil().clamp(-127.0, 127.0);
448 2.0f32.powf(exponent)
449}
450
451#[derive(Clone)]
455pub struct RawFp8Rows {
456 model: Arc<CmfModel>,
457 weight_idx: usize,
458 scale_idx: usize,
459 pub rows: usize,
460 pub cols: usize,
461}
462
463impl RawFp8Rows {
464 pub fn from_model(model: &Arc<CmfModel>, weight: &str, scale: &str) -> Result<Self, String> {
465 let wi = model
466 .tensor_index(weight)
467 .ok_or_else(|| format!("Engram tensor '{weight}' not found"))?;
468 let si = model
469 .tensor_index(scale)
470 .ok_or_else(|| format!("Engram tensor '{scale}' not found"))?;
471 let we = &model.tensors[wi];
472 let se = &model.tensors[si];
473 if we.dtype != TensorDtype::U8 || se.dtype != TensorDtype::U8 {
474 return Err(format!(
475 "Engram rows must be U8, got {} and {}",
476 we.dtype.name(),
477 se.dtype.name()
478 ));
479 }
480 if we.shape.len() != 2 || se.shape.len() != 2 {
481 return Err("Engram rows must be two-dimensional".into());
482 }
483 let (rows, cols) = (we.shape[0], we.shape[1]);
484 if cols == 0 || cols % 32 != 0 {
485 return Err(format!(
486 "Engram row width {cols} is not a positive multiple of 32"
487 ));
488 }
489 if se.shape != vec![rows, cols / 32] {
490 return Err(format!(
491 "Engram scale shape {:?}, expected [{rows}, {}]",
492 se.shape,
493 cols / 32
494 ));
495 }
496 if we.nbytes as usize != rows * cols || se.nbytes as usize != rows * cols / 32 {
497 return Err(format!(
498 "Engram U8 payload size mismatch for {weight}/{scale}"
499 ));
500 }
501 Ok(Self {
502 model: model.clone(),
503 weight_idx: wi,
504 scale_idx: si,
505 rows,
506 cols,
507 })
508 }
509
510 pub fn row_into(&self, row: usize, dst: &mut [f32]) {
515 assert!(row < self.rows);
516 assert_eq!(dst.len(), self.cols);
517 let wb = self.model.entry_bytes(&self.model.tensors[self.weight_idx]);
518 let sb = self.model.entry_bytes(&self.model.tensors[self.scale_idx]);
519 for g in 0..self.cols / 32 {
520 let scale = e8m0_scale(sb[row * (self.cols / 32) + g]);
521 let scale = if scale.is_finite() { scale } else { 0.0 };
522 let src = &wb[row * self.cols + g * 32..row * self.cols + (g + 1) * 32];
523 for (out, &byte) in dst[g * 32..(g + 1) * 32].iter_mut().zip(src) {
524 let v = fp8_e4m3(byte);
525 *out = if v.is_finite() { v * scale } else { 0.0 };
526 }
527 }
528 }
529}
530
531#[derive(Clone)]
535pub struct EngramHash {
536 pub layer_ids: Vec<usize>,
537 pub max_ngram: usize,
538 pub n_heads: usize,
539 pub compressed_vocab: usize,
540 pub pad_id: i64,
541 pub primes: Vec<Vec<Vec<u64>>>,
542 pub offsets: Vec<Vec<u64>>,
543 pub token_map: Vec<u32>,
544 pub multipliers: Vec<[u64; 4]>,
545 history: Vec<i64>,
546}
547
548impl EngramHash {
549 pub fn new(
550 layer_ids: Vec<usize>,
551 max_ngram: usize,
552 n_heads: usize,
553 table_vocab: usize,
554 compressed_vocab: usize,
555 pad_token: usize,
556 token_map: Vec<u32>,
557 ) -> Result<Self, String> {
558 if max_ngram < 2 || n_heads == 0 || layer_ids.is_empty() {
559 return Err("invalid Engram hash geometry".into());
560 }
561 let mapped_vocab = token_map
562 .iter()
563 .copied()
564 .max()
565 .map(|m| m as usize + 1)
566 .unwrap_or(0);
567 if mapped_vocab != compressed_vocab {
568 return Err(format!(
569 "Engram compressed vocabulary mismatch: tokenizer={mapped_vocab}, config={compressed_vocab}"
570 ));
571 }
572 let mut seen = Vec::<u64>::new();
573 let mut primes = Vec::with_capacity(layer_ids.len());
574 let mut offsets = Vec::with_capacity(layer_ids.len());
575 for _ in &layer_ids {
576 let mut per_layer = Vec::with_capacity(max_ngram - 1);
577 let mut per_offsets = Vec::with_capacity(max_ngram - 1);
578 let mut offset = 0u64;
579 for _ in 0..max_ngram - 1 {
580 let mut per_n = Vec::with_capacity(n_heads);
581 per_offsets.push(offset);
582 let mut current = table_vocab.saturating_sub(1) as u64;
583 for _ in 0..n_heads {
584 loop {
585 current = current.saturating_add(1);
586 if is_prime(current) && !seen.contains(¤t) {
587 break;
588 }
589 }
590 seen.push(current);
591 per_n.push(current);
592 offset = offset.saturating_add(current);
593 }
594 per_layer.push(per_n);
595 }
596 primes.push(per_layer);
597 offsets.push(per_offsets);
598 }
599 let pad_id = token_map.get(pad_token).copied().unwrap_or(2) as i64;
600 let multipliers = layer_ids
601 .iter()
602 .map(|&id| hash_multipliers(id, max_ngram, compressed_vocab))
603 .collect();
604 Ok(Self {
605 layer_ids,
606 max_ngram,
607 n_heads,
608 compressed_vocab,
609 pad_id,
610 primes,
611 offsets,
612 token_map,
613 multipliers,
614 history: Vec::new(),
615 })
616 }
617
618 pub fn reset(&mut self) {
619 self.history.clear();
620 }
621
622 pub fn push(&mut self, token: u32, participates: bool) -> Vec<Vec<usize>> {
626 let mapped = self.token_map.get(token as usize).copied().unwrap_or(0) as i64;
627 self.history.push(if participates { mapped } else { DEAD });
628 let mut all = Vec::with_capacity(self.layer_ids.len());
629 for (li, _) in self.layer_ids.iter().enumerate() {
630 let mut cols = Vec::with_capacity((self.max_ngram - 1) * self.n_heads);
631 for n in 1..self.max_ngram {
632 let mut rolling = 0u64;
633 let mut blocked = false;
634 for shift in 0..=n {
638 let (source, dead) = self.history_value(shift);
639 blocked |= dead;
645 let source = if blocked { self.pad_id } else { source };
646 rolling ^= (source as u64).wrapping_mul(self.multipliers[li][shift.min(3)]);
647 }
648 for h in 0..self.n_heads {
649 let p = self.primes[li][n - 1][h];
650 let off =
651 self.offsets[li][n - 1] + self.primes[li][n - 1][..h].iter().sum::<u64>();
652 cols.push((rolling % p + off) as usize);
653 }
654 }
655 all.push(cols);
656 }
657 all
658 }
659
660 fn history_value(&self, shift: usize) -> (i64, bool) {
661 if shift >= self.history.len() {
662 (self.pad_id, true)
663 } else {
664 let v = self.history[self.history.len() - 1 - shift];
665 if v == DEAD {
666 (self.pad_id, true)
667 } else {
668 (v, false)
669 }
670 }
671 }
672}
673
674fn is_prime(v: u64) -> bool {
675 if v < 2 {
676 return false;
677 }
678 if v % 2 == 0 {
679 return v == 2;
680 }
681 let mut d = 3u64;
682 while d <= v / d {
683 if v % d == 0 {
684 return false;
685 }
686 d += 2;
687 }
688 true
689}
690
691fn hash_multipliers(layer: usize, n: usize, vocab: usize) -> [u64; 4] {
696 let known = match layer {
697 1 => [
698 76632096046245,
699 4839876093313,
700 35959672319349,
701 73987337458391,
702 ],
703 14 => [
704 67716810739261,
705 51510806800915,
706 30921347202721,
707 82619226485591,
708 ],
709 _ => [0; 4],
710 };
711 if n <= 4 && known[0] != 0 && vocab == 99092 {
712 return known;
713 }
714 let bound = ((i64::MAX as u128 / vocab.max(1) as u128) / 2) as u64;
715 let mut x = 10007u64
716 .wrapping_mul(layer as u64)
717 .wrapping_add(0x9e3779b97f4a7c15);
718 let mut out = [0u64; 4];
719 for i in 0..n.min(4) {
720 x = splitmix64(x);
721 out[i] = (x % bound.max(1)) * 2 + 1;
722 }
723 out
724}
725
726#[inline]
727fn splitmix64(mut x: u64) -> u64 {
728 x = x.wrapping_add(0x9e3779b97f4a7c15);
729 let mut z = x;
730 z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
731 z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
732 z ^ (z >> 31)
733}
734
735#[derive(Debug, Clone)]
739pub struct Dsv41Cfg {
740 pub dim: usize,
741 pub n_heads: usize,
742 pub head_dim: usize,
743 pub rope_head_dim: usize,
744 pub q_lora_rank: usize,
745 pub o_lora_rank: usize,
746 pub o_groups: usize,
747 pub hc_mult: usize,
748 pub hc_sinkhorn_iters: usize,
749 pub hc_eps: f32,
750 pub norm_eps: f32,
751 pub n_routed_experts: usize,
752 pub top_k: usize,
753 pub moe_inter: usize,
754 pub gate_temp: f32,
760 pub norm_topk_prob: bool,
761 pub route_scale: f32,
762 pub swiglu_limit: f32,
763 pub window: usize,
764 pub rope_theta: f32,
765 pub compress_rope_theta: f32,
766 pub rope_factor: f32,
767 pub original_seq_len: usize,
768 pub beta_fast: f32,
769 pub beta_slow: f32,
770 pub index_heads: usize,
771 pub index_head_dim: usize,
772 pub index_topk: usize,
773 pub candidate_source: usize,
774 pub candidate_topk_blocks: usize,
775 pub candidate_block_size: usize,
776 pub kv_sources: Vec<usize>,
777 pub index_sources: Vec<usize>,
778 pub compress_ratios: Vec<usize>,
779 pub engram_layers: Vec<usize>,
780 pub engram_vocab: usize,
781 pub engram_embeddings: Vec<usize>,
782 pub engram_max_ngram: usize,
783 pub engram_heads: usize,
784 pub engram_head_dim: usize,
785 pub engram_compressed_vocab: usize,
786 pub engram_pad_id: usize,
787 pub vocab: usize,
788}
789
790impl Dsv41Cfg {
791 pub fn ratio(&self, li: usize) -> usize {
792 self.compress_ratios.get(li).copied().unwrap_or(0)
793 }
794
795 pub fn kv_source(&self, li: usize) -> Option<usize> {
796 self.kv_sources.iter().copied().filter(|&s| s <= li).max()
797 }
798
799 pub fn index_source(&self, li: usize) -> Option<usize> {
800 self.index_sources
801 .iter()
802 .copied()
803 .filter(|&s| s <= li)
804 .max()
805 }
806}
807
808pub struct Dsv41Compressor {
809 pub wkv: QTensor,
810 pub wgate: Option<QTensor>,
811 pub norm: Vec<f32>,
812 pub ratio: usize,
813}
814
815pub struct Dsv41Indexer {
816 pub wq_b: QTensor,
817 pub weights_proj: QTensor,
818 pub wk: Option<QTensor>,
819 pub k_norm: Option<Vec<f32>>,
820}
821
822pub struct Dsv41Expert {
823 pub w1: QTensor,
824 pub w2: QTensor,
825 pub w3: QTensor,
826}
827
828pub struct Dsv41Engram {
829 pub embed: RawFp8Rows,
830 pub wkv: QTensor,
831 pub q_weight: Vec<f32>,
832 pub k_weight: Vec<f32>,
833}
834
835pub struct Dsv41Layer {
836 pub attn_norm: Vec<f32>,
837 pub ffn_norm: Vec<f32>,
838 pub wq_a: QTensor,
839 pub q_norm: Vec<f32>,
840 pub wq_b: QTensor,
841 pub wkv: QTensor,
842 pub kv_norm: Vec<f32>,
843 pub wo_a: QTensor,
844 pub wo_b: QTensor,
845 pub attn_sink: Vec<f32>,
846 pub compressor: Option<Dsv41Compressor>,
847 pub indexer: Option<Dsv41Indexer>,
848 pub hc_attn_fn: Vec<f32>,
849 pub hc_attn_base: Vec<f32>,
850 pub hc_attn_scale: [f32; 3],
851 pub hc_ffn_fn: Vec<f32>,
852 pub hc_ffn_base: Vec<f32>,
853 pub hc_ffn_scale: [f32; 3],
854 pub gate: QTensor,
855 pub gate_bias: Vec<f32>,
856 pub gate_bias_vl: Option<Vec<f32>>,
857 pub experts: Vec<Dsv41Expert>,
858 pub shared: Dsv41Expert,
859 pub engram: Option<Dsv41Engram>,
860 gpu_expert_ids: Vec<(usize, usize, usize)>,
864 gpu_shared_ids: Option<(usize, usize, usize)>,
865}
866
867pub struct Dsv41Globals {
868 pub embed: QTensor,
869 pub norm: Vec<f32>,
870 pub head: QTensor,
871 pub inv_freq_compress: Vec<f32>,
872 pub inv_freq_window: Vec<f32>,
873}
874
875pub struct Dsv41State {
878 pub pos: usize,
879 pub window: Vec<Vec<f32>>,
880 pub packed: packed_kv::Dsv41PackedKvCache,
883 pub pending_kv: Vec<Vec<f32>>,
884 pub pending_score: Vec<Vec<f32>>,
885 pub topk: Vec<usize>,
886 pub topk_ready: bool,
892 pub candidates: Vec<bool>,
893 pub hash: Option<EngramHash>,
894 #[cfg(feature = "gpu")]
898 gpu_kv_id: u64,
899 #[cfg(feature = "gpu")]
903 gpu_pool: Option<crate::qwen4_exp::QwenGpuPool>,
904}
905
906impl Dsv41State {
907 pub fn new(cfg: &Dsv41Cfg, hash: Option<EngramHash>) -> Self {
908 #[cfg(feature = "gpu")]
909 let gpu_kv_id = {
910 use std::sync::atomic::{AtomicU64, Ordering};
911 static NEXT: AtomicU64 = AtomicU64::new(1);
912 (0xD541u64 << 48) | NEXT.fetch_add(1, Ordering::Relaxed)
913 };
914 Self {
915 pos: 0,
916 window: vec![Vec::new(); cfg.compress_ratios.len()],
917 packed: packed_kv::Dsv41PackedKvCache::new(
918 cfg.kv_sources.len(),
919 cfg.head_dim,
920 cfg.index_head_dim,
921 )
922 .expect("valid V4.1 packed KV geometry"),
923 pending_kv: vec![Vec::new(); cfg.kv_sources.len()],
924 pending_score: vec![Vec::new(); cfg.kv_sources.len()],
925 topk: Vec::new(),
926 topk_ready: false,
927 candidates: Vec::new(),
928 hash,
929 #[cfg(feature = "gpu")]
930 gpu_kv_id,
931 #[cfg(feature = "gpu")]
932 gpu_pool: None,
933 }
934 }
935
936 pub fn clear(&mut self) {
937 #[cfg(feature = "gpu")]
938 crate::gpu_wgpu::dsv4_cache_clear(self.gpu_kv_id);
939 self.pos = 0;
940 for v in &mut self.window {
941 v.clear();
942 }
943 self.packed.clear();
944 for v in &mut self.pending_kv {
945 v.clear();
946 }
947 for v in &mut self.pending_score {
948 v.clear();
949 }
950 self.topk.clear();
951 self.topk_ready = false;
952 self.candidates.clear();
953 if let Some(h) = &mut self.hash {
954 h.reset();
955 }
956 }
957}
958
959fn source_slot(sources: &[usize], li: usize) -> Option<usize> {
960 sources
961 .iter()
962 .enumerate()
963 .filter(|&(_, &s)| s <= li)
964 .map(|(i, _)| i)
965 .max()
966}
967
968fn rms(v: &mut [f32], w: &[f32], eps: f32) {
969 bf16_inplace(v);
973 crate::dsv4::rms_weighted(v, w, eps);
974 bf16_inplace(v);
975}
976
977fn matvec(t: &QTensor, x: &[f32], out: &mut [f32], pool: Option<&Pool>) {
978 t.matvec(x, out, pool);
979}
980
981#[inline]
982fn matvec_bf16(t: &QTensor, x: &[f32], out: &mut [f32], pool: Option<&Pool>) {
983 t.matvec(x, out, pool);
984 bf16_inplace(out);
985}
986
987#[inline]
992fn v41_fused_q_enabled() -> bool {
993 static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
994 *ON.get_or_init(|| std::env::var("CMF_DSV41_FUSED_Q").is_ok_and(|value| value == "1"))
995}
996
997#[cfg(feature = "gpu")]
1001fn gpu_attention_tail_enabled() -> bool {
1002 static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1003 *ON.get_or_init(|| {
1004 let requested = std::env::var("CMF_DSV41_GPU_ATTN")
1005 .map(|v| v != "0")
1006 .unwrap_or(true);
1007 let live = requested && crate::gpu::enabled_here() && crate::gpu_wgpu::adapter_up();
1008 if requested && !live && std::env::var("CMF_DSV41_GPU_ATTN").is_ok() {
1009 tracing::debug!("V4.1 GPU attention tail unavailable; retaining the CPU path");
1010 }
1011 live
1012 })
1013}
1014
1015fn gpu_tail_tap() -> Option<&'static str> {
1019 static TAP: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
1020 TAP.get_or_init(|| {
1021 let tap = std::env::var("CMF_DSV41_TAIL_TAP").ok()?;
1022 matches!(tap.as_str(), "q" | "attn" | "mid" | "final").then_some(tap)
1023 })
1024 .as_deref()
1025}
1026
1027fn f_any(model: &CmfModel, names: &[String]) -> Result<Vec<f32>, String> {
1028 for n in names {
1029 if model.tensor(n).is_some() {
1030 return crate::loader::load_f32(model, n, &crate::loader::Overlay::None);
1031 }
1032 }
1033 Err(format!("missing tensor (tried {})", names.join(", ")))
1034}
1035
1036fn q_any(model: &Arc<CmfModel>, names: &[String]) -> Result<QTensor, String> {
1037 for n in names {
1038 if model.tensor(n).is_some() {
1039 return QTensor::from_model(model, n);
1040 }
1041 }
1042 Err(format!("missing tensor (tried {})", names.join(", ")))
1043}
1044
1045fn scale3(model: &CmfModel, names: &[String]) -> Result<[f32; 3], String> {
1046 let v = f_any(model, names)?;
1047 if v.len() < 3 {
1048 return Err(format!(
1049 "scale tensor (tried {}) expected three values",
1050 names.join(", ")
1051 ));
1052 }
1053 Ok([v[0], v[1], v[2]])
1054}
1055
1056fn load_expert(model: &Arc<CmfModel>, p: &str, e: usize) -> Result<Dsv41Expert, String> {
1057 let a = format!("{p}.experts.{e}");
1058 let w1 = q_any(
1059 model,
1060 &[format!("{a}.gate_proj.weight"), format!("{a}.w1.weight")],
1061 )?;
1062 let w2 = q_any(
1063 model,
1064 &[format!("{a}.down_proj.weight"), format!("{a}.w2.weight")],
1065 )?;
1066 let w3 = q_any(
1067 model,
1068 &[format!("{a}.up_proj.weight"), format!("{a}.w3.weight")],
1069 )?;
1070 Ok(Dsv41Expert { w1, w2, w3 })
1071}
1072
1073fn load_shared(model: &Arc<CmfModel>, p: &str) -> Result<Dsv41Expert, String> {
1074 let mut names = Vec::new();
1075 for sh in ["shared_expert", "shared_experts"] {
1076 names.push(format!("{p}.{sh}.gate_proj.weight"));
1077 names.push(format!("{p}.{sh}.w1.weight"));
1078 }
1079 let w1 = q_any(model, &names)?;
1080 let mut names2 = Vec::new();
1081 for sh in ["shared_expert", "shared_experts"] {
1082 names2.push(format!("{p}.{sh}.down_proj.weight"));
1083 names2.push(format!("{p}.{sh}.w2.weight"));
1084 }
1085 let w2 = q_any(model, &names2)?;
1086 let mut names3 = Vec::new();
1087 for sh in ["shared_expert", "shared_experts"] {
1088 names3.push(format!("{p}.{sh}.up_proj.weight"));
1089 names3.push(format!("{p}.{sh}.w3.weight"));
1090 }
1091 let w3 = q_any(model, &names3)?;
1092 Ok(Dsv41Expert { w1, w2, w3 })
1093}
1094
1095pub fn load_layer(model: &Arc<CmfModel>, cfg: &Dsv41Cfg, li: usize) -> Result<Dsv41Layer, String> {
1099 let p = format!("model.layers.{li}");
1100 let a = format!("{p}.self_attn");
1101 let q = |tail: &str| q_any(model, &[format!("{a}.{tail}"), format!("{p}.attn.{tail}")]);
1102 let attn_norm = f_any(
1103 model,
1104 &[
1105 format!("{p}.input_layernorm.weight"),
1106 format!("{p}.attn_norm.weight"),
1107 ],
1108 )?;
1109 let ffn_norm = f_any(
1110 model,
1111 &[
1112 format!("{p}.post_attention_layernorm.weight"),
1113 format!("{p}.ffn_norm.weight"),
1114 ],
1115 )?;
1116 let wq_a = q("wq_a.weight")?;
1117 let q_norm = f_any(
1118 model,
1119 &[
1120 format!("{a}.q_norm.weight"),
1121 format!("{p}.attn.q_norm.weight"),
1122 ],
1123 )?;
1124 let wq_b = q("wq_b.weight")?;
1125 let wkv = q("wkv.weight")?;
1126 let kv_norm = f_any(model, &[format!("{a}.kv_norm.weight")])?;
1127 let wo_a = q("wo_a.weight")?;
1128 let wo_b = q("wo_b.weight")?;
1129 let attn_sink = f_any(
1130 model,
1131 &[format!("{a}.attn_sink"), format!("{a}.attn_sink.weight")],
1132 )?;
1133
1134 let ratio = cfg.ratio(li);
1135 let compressor = if cfg.kv_sources.contains(&li) {
1136 let cwkv = q_any(
1137 model,
1138 &[
1139 format!("{a}.compressor.wkv.weight"),
1140 format!("{p}.attn.compressor.wkv.weight"),
1141 ],
1142 )?;
1143 let wgate = if ratio > 1 {
1144 Some(q_any(
1145 model,
1146 &[
1147 format!("{a}.compressor.wgate.weight"),
1148 format!("{p}.attn.compressor.wgate.weight"),
1149 ],
1150 )?)
1151 } else {
1152 None
1153 };
1154 let norm = f_any(model, &[format!("{a}.compressor.norm.weight")])?;
1155 Some(Dsv41Compressor {
1156 wkv: cwkv,
1157 wgate,
1158 norm,
1159 ratio,
1160 })
1161 } else {
1162 None
1163 };
1164
1165 let indexer = if cfg.index_sources.contains(&li) {
1166 let wq_bi = q_any(
1167 model,
1168 &[
1169 format!("{a}.indexer.wq_b.weight"),
1170 format!("{p}.attn.indexer.wq_b.weight"),
1171 ],
1172 )?;
1173 let weights_proj = q_any(
1174 model,
1175 &[
1176 format!("{a}.indexer.weights_proj.weight"),
1177 format!("{p}.attn.indexer.weights_proj.weight"),
1178 ],
1179 )?;
1180 let owns_k = cfg.kv_sources.contains(&li);
1181 let wk = if owns_k {
1182 Some(q_any(
1183 model,
1184 &[
1185 format!("{a}.indexer.wk.weight"),
1186 format!("{p}.attn.indexer.wk.weight"),
1187 ],
1188 )?)
1189 } else {
1190 None
1191 };
1192 let k_norm = if owns_k {
1193 Some(f_any(
1194 model,
1195 &[
1196 format!("{a}.indexer.k_norm.weight"),
1197 format!("{p}.attn.indexer.k_norm.weight"),
1198 ],
1199 )?)
1200 } else {
1201 None
1202 };
1203 Some(Dsv41Indexer {
1204 wq_b: wq_bi,
1205 weights_proj,
1206 wk,
1207 k_norm,
1208 })
1209 } else {
1210 None
1211 };
1212
1213 let hc_attn_fn = f_any(model, &[format!("{p}.hc_attn_fn")])?;
1214 let hc_attn_base = f_any(model, &[format!("{p}.hc_attn_base")])?;
1215 let hc_attn_scale = scale3(
1216 model,
1217 &[format!("{p}.hc_attn_scale"), format!("{p}.hc_attn.scale")],
1218 )?;
1219 let hc_ffn_fn = f_any(model, &[format!("{p}.hc_ffn_fn")])?;
1220 let hc_ffn_base = f_any(model, &[format!("{p}.hc_ffn_base")])?;
1221 let hc_ffn_scale = scale3(
1222 model,
1223 &[format!("{p}.hc_ffn_scale"), format!("{p}.hc_ffn.scale")],
1224 )?;
1225
1226 let gate = q_any(
1227 model,
1228 &[
1229 format!("{p}.mlp.gate.weight"),
1230 format!("{p}.ffn.gate.weight"),
1231 ],
1232 )?;
1233 let gate_bias = f_any(
1234 model,
1235 &[
1236 format!("{p}.mlp.expert_bias"),
1237 format!("{p}.ffn.gate.bias"),
1238 format!("{p}.mlp.gate.bias"),
1239 ],
1240 )?;
1241 let gate_bias_vl = f_any(
1242 model,
1243 &[
1244 format!("{p}.mlp.expert_bias_vl"),
1245 format!("{p}.ffn.gate.bias_vl"),
1246 ],
1247 )
1248 .ok();
1249 let mut experts = Vec::with_capacity(cfg.n_routed_experts);
1250 for e in 0..cfg.n_routed_experts {
1251 experts.push(
1252 load_expert(model, &format!("{p}.mlp"), e)
1253 .or_else(|_| load_expert(model, &format!("{p}.ffn"), e))?,
1254 );
1255 }
1256 let shared = load_shared(model, &format!("{p}.mlp"))
1257 .or_else(|_| load_shared(model, &format!("{p}.ffn")))?;
1258 let gpu_expert_ids = experts
1259 .iter()
1260 .map(|e| Some((e.w1.model_idx()?, e.w3.model_idx()?, e.w2.model_idx()?)))
1261 .collect::<Option<Vec<_>>>()
1262 .unwrap_or_default();
1263 let gpu_shared_ids = match (
1264 shared.w1.model_idx(),
1265 shared.w3.model_idx(),
1266 shared.w2.model_idx(),
1267 ) {
1268 (Some(w1), Some(w3), Some(w2)) => Some((w1, w3, w2)),
1269 _ => None,
1270 };
1271
1272 let engram = if cfg.engram_layers.contains(&li) {
1273 let ew = format!("{p}.engram.embed.weight");
1274 let es = format!("{p}.engram.embed.scale");
1275 let embed = RawFp8Rows::from_model(model, &ew, &es)?;
1276 if let Some(index) = cfg.engram_layers.iter().position(|&id| id == li) {
1277 if let Some(&expected_rows) = cfg.engram_embeddings.get(index) {
1278 if embed.rows != expected_rows {
1279 return Err(format!(
1280 "Engram layer {li} has {} rows, expected {expected_rows}",
1281 embed.rows
1282 ));
1283 }
1284 }
1285 }
1286 let wkv_e = q_any(model, &[format!("{p}.engram.wkv.weight")])?;
1287 let q_weight = f_any(model, &[format!("{p}.engram.q_weight")])?;
1288 let k_weight = f_any(model, &[format!("{p}.engram.k_weight")])?;
1289 Some(Dsv41Engram {
1290 embed,
1291 wkv: wkv_e,
1292 q_weight,
1293 k_weight,
1294 })
1295 } else {
1296 None
1297 };
1298
1299 Ok(Dsv41Layer {
1300 attn_norm,
1301 ffn_norm,
1302 wq_a,
1303 q_norm,
1304 wq_b,
1305 wkv,
1306 kv_norm,
1307 wo_a,
1308 wo_b,
1309 attn_sink,
1310 compressor,
1311 indexer,
1312 hc_attn_fn,
1313 hc_attn_base,
1314 hc_attn_scale,
1315 hc_ffn_fn,
1316 hc_ffn_base,
1317 hc_ffn_scale,
1318 gate,
1319 gate_bias,
1320 gate_bias_vl,
1321 experts,
1322 shared,
1323 engram,
1324 gpu_expert_ids,
1325 gpu_shared_ids,
1326 })
1327}
1328
1329pub fn load(
1333 model: &Arc<CmfModel>,
1334 cfg: &Dsv41Cfg,
1335 n_layers: usize,
1336 token_map: Vec<u32>,
1337) -> Result<(Dsv41Globals, Vec<Dsv41Layer>, Option<EngramHash>), String> {
1338 let q = |name: &str| QTensor::from_model(model, name);
1339 let globals = Dsv41Globals {
1340 embed: q("model.embed_tokens.weight")?,
1341 norm: crate::loader::load_f32(model, "model.norm.weight", &crate::loader::Overlay::None)?,
1342 head: q("lm_head.weight")?,
1343 inv_freq_compress: crate::attention::yarn_inv_freq(
1344 cfg.rope_head_dim,
1345 cfg.compress_rope_theta,
1346 cfg.rope_factor,
1347 cfg.original_seq_len,
1348 cfg.beta_fast,
1349 cfg.beta_slow,
1350 ),
1351 inv_freq_window: crate::attention::rope_inv_freq(cfg.rope_head_dim, cfg.rope_theta),
1352 };
1353 let mut layers = Vec::with_capacity(n_layers);
1354 for li in 0..n_layers {
1355 layers.push(load_layer(model, cfg, li)?);
1356 }
1357 let hash = if !cfg.engram_layers.is_empty() {
1358 Some(EngramHash::new(
1359 cfg.engram_layers.clone(),
1360 cfg.engram_max_ngram,
1361 cfg.engram_heads,
1362 cfg.engram_vocab,
1363 cfg.engram_compressed_vocab,
1364 cfg.engram_pad_id,
1365 token_map,
1366 )?)
1367 } else {
1368 None
1369 };
1370 Ok((globals, layers, hash))
1371}
1372
1373pub fn token_map_from_model(model: &CmfModel, vocab: usize) -> Vec<u32> {
1376 let tokenizer = model
1377 .vocab
1378 .as_ref()
1379 .and_then(|bytes| crate::tokenizer::Tokenizer::from_bytes(bytes).ok());
1380 let mut out = Vec::with_capacity(vocab);
1381 let mut keys = std::collections::HashMap::<String, u32>::new();
1382 for id in 0..vocab {
1383 let text = tokenizer
1384 .as_ref()
1385 .map(|t| t.decode_token_for_hash(id as u32))
1386 .unwrap_or_default();
1387 let key = if text.contains('\u{fffd}') {
1391 tokenizer
1392 .as_ref()
1393 .map(|t| t.raw_token_for_hash(id as u32))
1394 .unwrap_or(text)
1395 } else {
1396 normalize_hash_token(&text)
1397 };
1398 let next = keys.len() as u32;
1399 out.push(*keys.entry(key).or_insert(next));
1400 }
1401 out
1402}
1403
1404fn normalize_hash_token(text: &str) -> String {
1405 use unicode_normalization::UnicodeNormalization;
1406 let nfd: String = text.nfkc().nfd().collect();
1410 let mut out = String::with_capacity(nfd.len());
1411 let mut last_space = false;
1412 for c in nfd.chars() {
1413 if unicode_normalization::char::is_combining_mark(c) {
1414 continue;
1415 }
1416 if c == ' ' || c == '\t' || c == '\r' || c == '\n' {
1417 if !last_space {
1418 out.push(' ');
1419 }
1420 last_space = true;
1421 } else {
1422 for lower in c.to_lowercase() {
1423 out.push(lower);
1424 }
1425 last_space = false;
1426 }
1427 }
1428 let trimmed = out.trim_matches(' ');
1429 if trimmed.is_empty() && out == " " {
1430 " ".to_string()
1431 } else if trimmed.is_empty() {
1432 text.to_string()
1433 } else {
1434 trimmed.to_string()
1435 }
1436}
1437
1438fn apply_engram(
1439 e: &Dsv41Engram,
1440 h: &mut [f32],
1441 hashes: &[usize],
1442 cfg: &Dsv41Cfg,
1443 token_mask: bool,
1444 pool: Option<&Pool>,
1445) {
1446 if !token_mask {
1447 return;
1448 }
1449 let cols = hashes.len() * e.embed.cols;
1450 let mut emb = vec![0.0f32; cols];
1451 for (i, &row) in hashes.iter().enumerate() {
1452 e.embed.row_into(
1453 row.min(e.embed.rows.saturating_sub(1)),
1454 &mut emb[i * e.embed.cols..(i + 1) * e.embed.cols],
1455 );
1456 }
1457 bf16_inplace(&mut emb);
1461 let mut kv = vec![0.0f32; cfg.dim * (cfg.hc_mult + 1)];
1462 matvec_bf16(&e.wkv, &emb, &mut kv, pool);
1464 let key = &kv[..cfg.dim * cfg.hc_mult];
1465 let value = &kv[cfg.dim * cfg.hc_mult..];
1466 for copy in 0..cfg.hc_mult {
1467 let hs = &h[copy * cfg.dim..(copy + 1) * cfg.dim];
1468 let ks = &key[copy * cfg.dim..(copy + 1) * cfg.dim];
1469 let qw = e
1470 .q_weight
1471 .get(copy * cfg.dim..(copy + 1) * cfg.dim)
1472 .unwrap_or(&[]);
1473 let kw = e
1474 .k_weight
1475 .get(copy * cfg.dim..(copy + 1) * cfg.dim)
1476 .unwrap_or(&[]);
1477 let hm = hs.iter().map(|v| v * v).sum::<f32>() / cfg.dim as f32;
1478 let km = ks.iter().map(|v| v * v).sum::<f32>() / cfg.dim as f32;
1479 let rstd = 1.0 / (hm + cfg.norm_eps).sqrt() / (km + cfg.norm_eps).sqrt();
1480 let mut dot = 0.0;
1481 for i in 0..cfg.dim {
1482 dot += hs[i]
1483 * ks[i]
1484 * qw.get(i).copied().unwrap_or(1.0)
1485 * kw.get(i).copied().unwrap_or(1.0);
1486 }
1487 dot *= rstd * (cfg.dim as f32).powf(-0.5);
1488 let root = dot.abs().max(1e-6).sqrt();
1492 let gate = sigmoid(if dot.is_sign_negative() { -root } else { root });
1493 let dst = &mut h[copy * cfg.dim..(copy + 1) * cfg.dim];
1494 for i in 0..cfg.dim {
1495 dst[i] += gate * value[i];
1496 }
1497 }
1498 bf16_inplace(h);
1501}
1502
1503#[doc(hidden)]
1508pub fn dsv41_apply_engram_for_test(
1509 e: &Dsv41Engram,
1510 h: &mut [f32],
1511 hashes: &[usize],
1512 cfg: &Dsv41Cfg,
1513 token_mask: bool,
1514) {
1515 apply_engram(e, h, hashes, cfg, token_mask, None);
1516}
1517
1518fn compressor_step(
1519 cp: &Dsv41Compressor,
1520 x: &[f32],
1521 cfg: &Dsv41Cfg,
1522 pending_kv: &mut Vec<f32>,
1523 pending_score: &mut Vec<f32>,
1524 pool: Option<&Pool>,
1525) -> Option<Vec<f32>> {
1526 let mut kv = vec![0.0f32; cfg.head_dim];
1527 if cp.ratio == 1 {
1530 matvec_bf16(&cp.wkv, x, &mut kv, pool);
1531 } else {
1532 matvec(&cp.wkv, x, &mut kv, pool);
1533 }
1534 if cp.ratio == 1 {
1535 rms(&mut kv, &cp.norm, cfg.norm_eps);
1536 return Some(kv);
1537 }
1538 let mut score = vec![0.0f32; cfg.head_dim];
1539 if let Some(wg) = &cp.wgate {
1540 matvec(wg, x, &mut score, pool);
1541 }
1542 pending_kv.extend_from_slice(&kv);
1543 pending_score.extend_from_slice(&score);
1544 if pending_kv.len() < cp.ratio * cfg.head_dim {
1545 return None;
1546 }
1547 let mut out = vec![0.0f32; cfg.head_dim];
1548 for d in 0..cfg.head_dim {
1549 let m = (0..cp.ratio)
1550 .map(|i| pending_score[i * cfg.head_dim + d])
1551 .fold(f32::NEG_INFINITY, f32::max);
1552 let mut den = 0.0;
1553 for i in 0..cp.ratio {
1554 den += (pending_score[i * cfg.head_dim + d] - m).exp();
1555 }
1556 if den > 0.0 {
1557 for i in 0..cp.ratio {
1558 out[d] += (pending_score[i * cfg.head_dim + d] - m).exp() / den
1559 * pending_kv[i * cfg.head_dim + d];
1560 }
1561 }
1562 }
1563 pending_kv.clear();
1564 pending_score.clear();
1565 rms(&mut out, &cp.norm, cfg.norm_eps);
1566 Some(out)
1567}
1568
1569fn fp4_round(x: f32) -> f32 {
1570 let sign = if x.is_sign_negative() { -1.0 } else { 1.0 };
1571 let ax = x.abs();
1572 if !ax.is_finite() {
1573 return sign * 6.0;
1574 }
1575 const LEVELS: [f32; 8] = [0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0];
1576 const EVEN: [bool; 8] = [true, false, true, false, true, false, true, false];
1581 let mut best = 0usize;
1582 let mut best_dist = ax;
1583 for i in 1..LEVELS.len() {
1584 let dist = (ax - LEVELS[i]).abs();
1585 if dist < best_dist || (dist == best_dist && EVEN[i] && !EVEN[best]) {
1586 best = i;
1587 best_dist = dist;
1588 }
1589 }
1590 sign * LEVELS[best]
1591}
1592
1593fn fp4_inplace(v: &mut [f32], block: usize, e8m0_scale_fmt: bool) {
1594 for chunk in v.chunks_mut(block) {
1595 let min_amax = if e8m0_scale_fmt {
1601 6.0 * 2.0f32.powi(-126)
1602 } else {
1603 6.0 * 2.0f32.powi(-9)
1604 };
1605 let max = chunk.iter().map(|x| x.abs()).fold(min_amax, f32::max);
1606 let raw_scale = max / 6.0;
1607 let scale = if e8m0_scale_fmt {
1608 round_e8m0_scale(raw_scale)
1609 } else {
1610 e4m3_round(raw_scale.max(6.0 * 2.0f32.powi(-9)))
1613 };
1614 if scale == 0.0 || !scale.is_finite() {
1615 chunk.fill(0.0);
1616 continue;
1617 }
1618 for x in chunk {
1619 *x = bf16_roundtrip(fp4_round(*x / scale) * scale);
1620 }
1621 }
1622}
1623
1624fn fp8_activation_inplace(v: &mut [f32]) {
1625 for chunk in v.chunks_mut(32) {
1626 let max = chunk.iter().map(|x| x.abs()).fold(1e-4f32, f32::max);
1627 let scale = 2.0f32.powf((max / 448.0).log2().ceil());
1628 for x in chunk {
1629 *x = bf16_roundtrip(e4m3_round((*x / scale).clamp(-448.0, 448.0)) * scale);
1630 }
1631 }
1632}
1633
1634struct IndexResult {
1635 picked: Vec<usize>,
1636 scores: Vec<f32>,
1637}
1638
1639fn update_index(
1640 ix: &Dsv41Indexer,
1641 x: &[f32],
1642 qr: &[f32],
1643 source_k: &packed_kv::PackedRows,
1644 cfg: &Dsv41Cfg,
1645 pos: usize,
1646 ratio: usize,
1647 inv_freq: &[f32],
1648 candidate_mask: Option<&[bool]>,
1649 pool: Option<&Pool>,
1650) -> IndexResult {
1651 let ih = cfg.index_heads;
1652 let id = cfg.index_head_dim;
1653 let mut q = vec![0.0f32; ih * id];
1654 matvec_bf16(&ix.wq_b, qr, &mut q, pool);
1655 for head in 0..ih {
1658 crate::dsv4::rope_tail(
1659 &mut q[head * id..(head + 1) * id],
1660 inv_freq,
1661 pos,
1662 cfg.rope_head_dim.min(id) & !1,
1663 false,
1664 );
1665 }
1666 bf16_inplace(&mut q);
1668 fp4_inplace(&mut q, 32, true);
1669 let mut weights = vec![0.0f32; ih];
1670 matvec_bf16(&ix.weights_proj, x, &mut weights, pool);
1671 let sc = (id as f32).powf(-0.5) * (ih as f32).powf(-0.5);
1672 for w in &mut weights {
1673 *w = bf16_roundtrip(*w * sc);
1675 }
1676 let n = source_k.rows();
1677 let mut scores = vec![f32::NEG_INFINITY; n];
1678 let mut k = vec![0.0f32; id];
1679 for t in 0..n {
1680 if candidate_mask.is_some_and(|m| !m.get(t).copied().unwrap_or(false)) {
1681 continue;
1682 }
1683 assert!(
1684 source_k.row_into(t, &mut k),
1685 "packed index-K row {t} is unavailable"
1686 );
1687 let k = &k[..];
1688 let mut s = 0.0;
1689 for head in 0..ih {
1690 let d = bf16_roundtrip(
1693 q[head * id..(head + 1) * id]
1694 .iter()
1695 .zip(k)
1696 .map(|(a, b)| a * b)
1697 .sum::<f32>(),
1698 )
1699 .max(0.0);
1700 s += bf16_roundtrip(d * weights[head]);
1702 }
1703 if t >= (pos + 1) / ratio.max(1) {
1704 scores[t] = f32::NEG_INFINITY;
1705 } else {
1706 scores[t] = bf16_roundtrip(s);
1708 }
1709 }
1710 let mut picked = Vec::new();
1711 crate::dsv4::top_k_positions(&scores, cfg.index_topk, &mut picked);
1712 IndexResult { picked, scores }
1713}
1714
1715fn attention(
1716 l: &Dsv41Layer,
1717 cfg: &Dsv41Cfg,
1718 st: &mut Dsv41State,
1719 li: usize,
1720 x: &[f32],
1721 inv_freq: &[f32],
1722 pool: Option<&Pool>,
1723 out: &mut [f32],
1724) -> Vec<f32> {
1725 let attn_other_t0 = prof::start();
1726 let mut qr = vec![0.0f32; cfg.q_lora_rank];
1727 let mut kv = vec![0.0f32; cfg.head_dim];
1728 QTensor::matvec_many([&l.wq_a, &l.wkv], x, [&mut qr, &mut kv], pool);
1732 bf16_inplace(&mut qr);
1733 trace_stats("wq_a", st.pos, Some(li), &qr);
1734 rms(&mut qr, &l.q_norm, cfg.norm_eps);
1735 trace_stats("q_norm", st.pos, Some(li), &qr);
1736 bf16_inplace(&mut kv);
1737 trace_stats("wkv", st.pos, Some(li), &kv);
1738 rms(&mut kv, &l.kv_norm, cfg.norm_eps);
1739 trace_stats("kv_norm", st.pos, Some(li), &kv);
1740 crate::dsv4::rope_tail(&mut kv, inv_freq, st.pos, cfg.rope_head_dim, false);
1741 bf16_inplace(&mut kv);
1742
1743 let source = if cfg.ratio(li) > 0 {
1748 source_slot(&cfg.kv_sources, li)
1749 } else {
1750 None
1751 };
1752 let mut latent = None;
1753 if let (Some(cp), Some(si)) = (&l.compressor, source) {
1754 latent = compressor_step(
1755 cp,
1756 x,
1757 cfg,
1758 &mut st.pending_kv[si],
1759 &mut st.pending_score[si],
1760 pool,
1761 );
1762 if let Some(v) = latent.as_ref() {
1763 trace_stats("latent", st.pos, Some(li), v);
1764 let latent_pos = st.pos + 1 - cfg.ratio(li).max(1);
1768 let mut stored = v.clone();
1769 crate::dsv4::rope_tail(&mut stored, inv_freq, latent_pos, cfg.rope_head_dim, false);
1770 bf16_inplace(&mut stored);
1771 let row_id = st
1772 .packed
1773 .push_main(si, &stored)
1774 .expect("valid main KV source slot");
1775 if std::env::var_os("CMF_DSV41_TRACE").is_some() {
1776 let mut quantized = vec![0.0f32; cfg.head_dim];
1777 assert!(st.packed.main_row_into(si, row_id, &mut quantized));
1778 trace_stats("compressed", st.pos, Some(li), &quantized);
1779 }
1780 }
1781 }
1782 if let (Some(ix), Some(si), Some(lat)) = (&l.indexer, source, latent.as_ref()) {
1785 if let (Some(wk), Some(kn)) = (&ix.wk, &ix.k_norm) {
1786 let latent_pos = st.pos + 1 - cfg.ratio(li).max(1);
1787 let mut k = vec![0.0f32; cfg.index_head_dim];
1788 matvec_bf16(wk, lat, &mut k, pool);
1789 rms(&mut k, kn, cfg.norm_eps);
1790 crate::dsv4::rope_tail(
1791 &mut k,
1792 inv_freq,
1793 latent_pos,
1794 cfg.rope_head_dim.min(cfg.index_head_dim) & !1,
1795 false,
1796 );
1797 bf16_inplace(&mut k);
1798 let row_id = st
1799 .packed
1800 .push_index(si, &k)
1801 .expect("valid index-K source slot");
1802 if std::env::var_os("CMF_DSV41_TRACE").is_some() {
1803 let mut quantized = vec![0.0f32; cfg.index_head_dim];
1804 assert!(st.packed.index_row_into(si, row_id, &mut quantized));
1805 trace_stats("index_k", st.pos, Some(li), &quantized);
1806 }
1807 }
1808 let _ = ix;
1809 }
1810 let win_len = {
1815 let w = &mut st.window[li];
1816 fp8_activation_inplace(&mut kv);
1817 bf16_inplace(&mut kv);
1820 trace_stats("kv", st.pos, Some(li), &kv);
1821 w.extend_from_slice(&kv);
1822 let cap = cfg.window * cfg.head_dim;
1823 if w.len() > cap {
1824 let drop = w.len() - cap;
1825 w.drain(..drop);
1826 }
1827 w.len() / cfg.head_dim
1828 };
1829 let mut idxs: Vec<usize> = (0..win_len).collect();
1830 if let Some(si) = source {
1831 let comp_len = st.packed.main_rows(si);
1832 if comp_len > 0 {
1833 if let Some(ix) = &l.indexer {
1834 let candidates = if li > cfg.candidate_source && !st.candidates.is_empty() {
1835 Some(st.candidates.as_slice())
1836 } else {
1837 None
1838 };
1839 let result = update_index(
1840 ix,
1841 x,
1842 &qr,
1843 st.packed
1844 .index_store(si)
1845 .expect("index-K store for shared source"),
1846 cfg,
1847 st.pos,
1848 cfg.ratio(li),
1849 inv_freq,
1850 candidates,
1851 pool,
1852 );
1853 trace_indices(st.pos, li, &result.picked);
1854 if cfg.candidate_source == li {
1855 st.candidates = candidate_blocks(
1856 &result.scores,
1857 cfg.candidate_topk_blocks,
1858 cfg.candidate_block_size,
1859 );
1860 trace_index_scores(
1861 st.pos,
1862 li,
1863 &result.scores,
1864 &result.picked,
1865 Some(st.candidates.as_slice()),
1866 win_len,
1867 comp_len,
1868 st.pending_kv[si].len() / cfg.head_dim.max(1),
1869 );
1870 } else {
1871 trace_index_scores(
1872 st.pos,
1873 li,
1874 &result.scores,
1875 &result.picked,
1876 candidates,
1877 win_len,
1878 comp_len,
1879 st.pending_kv[si].len() / cfg.head_dim.max(1),
1880 );
1881 }
1882 st.topk = result.picked;
1883 st.topk_ready = true;
1884 }
1885 let all_picks: Vec<usize> = (0..comp_len).collect();
1886 let picks: &[usize] = if cfg.index_source(li).is_some() && st.topk_ready {
1887 &st.topk
1888 } else {
1889 &all_picks
1890 };
1891 idxs.extend(
1892 picks
1893 .iter()
1894 .copied()
1895 .filter(|&p| p < comp_len)
1896 .map(|p| win_len + p),
1897 );
1898 }
1899 }
1900
1901 let fused_q = v41_fused_q_enabled();
1907 let materialize_q = || {
1908 let mut q = vec![0.0f32; cfg.n_heads * cfg.head_dim];
1909 matvec_bf16(&l.wq_b, &qr, &mut q, pool);
1910 trace_stats("wq_b", st.pos, Some(li), &q);
1911 for h in 0..cfg.n_heads {
1912 let qh = &mut q[h * cfg.head_dim..(h + 1) * cfg.head_dim];
1913 crate::dsv4::rope_tail(qh, inv_freq, st.pos, cfg.rope_head_dim, false);
1914 }
1915 bf16_inplace(&mut q);
1916 trace_stats("q", st.pos, Some(li), &q);
1917 q
1918 };
1919 let mut q = if fused_q { None } else { Some(materialize_q()) };
1920
1921 let selected_comp_positions: Vec<usize> = idxs
1925 .iter()
1926 .copied()
1927 .filter(|&p| p >= win_len)
1928 .map(|p| p - win_len)
1929 .collect();
1930 let mut selected_compressed = vec![0.0f32; selected_comp_positions.len() * cfg.head_dim];
1931 if let Some(si) = source {
1932 assert!(
1933 st.packed
1934 .gather_main_rows(si, &selected_comp_positions, &mut selected_compressed,),
1935 "packed main-K gather failed for source {si}"
1936 );
1937 }
1938 let mut packed_idxs = Vec::with_capacity(idxs.len());
1939 for &logical in &idxs {
1940 if logical < win_len {
1941 packed_idxs.push(logical);
1942 } else {
1943 let comp = logical - win_len;
1944 let selected = selected_comp_positions
1945 .iter()
1946 .position(|&row| row == comp)
1947 .expect("selected compressed row mapping");
1948 packed_idxs.push(win_len + selected);
1949 }
1950 }
1951
1952 #[cfg(feature = "gpu")]
1961 if gpu_attention_tail_enabled() {
1962 let n_comp = selected_comp_positions.len();
1963 let cache_cap = (cfg.window + n_comp.next_power_of_two().max(64)) * cfg.head_dim;
1964 let cache_ok =
1965 crate::gpu_wgpu::dsv4_cache_write(st.gpu_kv_id, li, 0, &st.window[li], cache_cap)
1966 && (selected_compressed.is_empty()
1967 || crate::gpu_wgpu::dsv4_cache_write(
1968 st.gpu_kv_id,
1969 li,
1970 cfg.window * cfg.head_dim,
1971 &selected_compressed,
1972 cache_cap,
1973 ));
1974 let model = l.wq_b.model_arc();
1975 let idx32: Vec<u32> = packed_idxs
1979 .iter()
1980 .map(|&p| {
1981 if p < win_len {
1982 p as u32
1983 } else {
1984 (cfg.window + p - win_len) as u32
1985 }
1986 })
1987 .collect();
1988 let diag_tap = gpu_tail_tap();
1989 let diag_len = diag_tap.map(|tap| match tap {
1990 "q" | "attn" => cfg.n_heads * cfg.head_dim,
1991 "mid" => cfg.o_groups * cfg.o_lora_rank,
1992 _ => cfg.dim,
1993 });
1994 let mut gpu_attended = vec![0.0f32; cfg.dim.max(diag_len.unwrap_or(0))];
1995 let qn_in = fused_q.then_some(qr.as_slice());
2000 let q_in = q.as_deref();
2001 let gpu_ok = cache_ok
2002 && model.is_some_and(|model| {
2003 let w = crate::gpu_wgpu::Dsv4AttnW {
2004 wq_a: l.wq_a.model_idx().unwrap_or(usize::MAX),
2005 wq_b: l.wq_b.model_idx().unwrap_or(usize::MAX),
2006 wo_a: l.wo_a.model_idx().unwrap_or(usize::MAX),
2007 wo_b: l.wo_b.model_idx().unwrap_or(usize::MAX),
2008 q_norm: &l.q_norm,
2009 sink: &l.attn_sink,
2010 };
2011 let g = crate::gpu_wgpu::Dsv4AttnGeom {
2012 dim: cfg.dim,
2013 nh: cfg.n_heads,
2014 hd: cfg.head_dim,
2015 rd: cfg.rope_head_dim,
2016 q_lora: cfg.q_lora_rank,
2017 o_lora: cfg.o_lora_rank,
2018 o_groups: cfg.o_groups,
2019 eps: cfg.norm_eps,
2020 scale: (cfg.head_dim as f32).powf(-0.5),
2021 bf16: true,
2022 q_rms: false,
2023 };
2024 crate::gpu_wgpu::dsv4_attn_frame(
2025 &model,
2026 &w,
2027 g,
2028 &[],
2029 qn_in,
2030 q_in,
2031 st.gpu_kv_id,
2032 li,
2033 &idx32,
2034 inv_freq,
2035 st.pos,
2036 None,
2037 &mut gpu_attended,
2038 )
2039 });
2040 if gpu_ok {
2041 prof::note_gpu_attn();
2042 if let Some(tap) = diag_tap {
2043 let name = match tap {
2044 "q" => "gpu_q",
2045 "attn" => "gpu_attn",
2046 "mid" => "gpu_mid",
2047 _ => "gpu_tail",
2048 };
2049 trace_stats(name, st.pos, Some(li), &gpu_attended[..diag_len.unwrap()]);
2050 } else {
2051 prof::add(&prof::ATTN_OTHER_NS, attn_other_t0);
2055 bf16_inplace(&mut gpu_attended);
2056 out.copy_from_slice(&gpu_attended[..cfg.dim]);
2057 return qr;
2058 }
2059 }
2060 prof::note_gpu_attn_fallback();
2061 }
2062
2063 if q.is_none() {
2068 q = Some(materialize_q());
2069 }
2070 let q = q
2071 .as_deref()
2072 .expect("V4.1 query must be materialized before CPU attention");
2073
2074 let window = &st.window[li];
2075 let compressed = if selected_compressed.is_empty() {
2076 None
2077 } else {
2078 Some(selected_compressed.as_slice())
2079 };
2080 let mut attended = vec![0.0f32; cfg.n_heads * cfg.head_dim];
2081 prof::add(&prof::ATTN_OTHER_NS, attn_other_t0);
2082 let sparse_t0 = prof::start();
2083 for h in 0..cfg.n_heads {
2084 sparse_attend_split(
2085 &q[h * cfg.head_dim..(h + 1) * cfg.head_dim],
2086 window,
2087 compressed,
2088 &packed_idxs,
2089 l.attn_sink.get(h).copied().unwrap_or(0.0),
2090 (cfg.head_dim as f32).powf(-0.5),
2091 win_len,
2092 cfg.head_dim,
2093 &mut attended[h * cfg.head_dim..(h + 1) * cfg.head_dim],
2094 );
2095 }
2096 prof::add(&prof::SPARSE_NS, sparse_t0);
2097 let attn_other_t0 = prof::start();
2098 for h in 0..cfg.n_heads {
2099 crate::dsv4::rope_tail(
2100 &mut attended[h * cfg.head_dim..(h + 1) * cfg.head_dim],
2101 inv_freq,
2102 st.pos,
2103 cfg.rope_head_dim,
2104 true,
2105 );
2106 bf16_inplace(&mut attended[h * cfg.head_dim..(h + 1) * cfg.head_dim]);
2107 }
2108 trace_stats("attended", st.pos, Some(li), &attended);
2109 if gpu_tail_tap().is_some_and(|tap| tap == "mid") {
2110 let mut cpu_mid = vec![0.0f32; cfg.o_groups * cfg.o_lora_rank];
2111 let mut scratch = vec![0.0f32; l.wo_a.cols()];
2112 for (i, mid) in cpu_mid.iter_mut().enumerate() {
2113 let group = i / cfg.o_lora_rank;
2114 *mid = bf16_roundtrip(l.wo_a.row_dot(
2115 i,
2116 &attended[group * l.wo_a.cols()..(group + 1) * l.wo_a.cols()],
2117 &mut scratch,
2118 ));
2119 }
2120 trace_stats("cpu_mid", st.pos, Some(li), &cpu_mid);
2121 }
2122 crate::dsv4::o_project(
2123 &attended,
2124 &|r, v, scratch| bf16_roundtrip(l.wo_a.row_dot(r, v, scratch)),
2129 l.wo_a.cols(),
2130 &|m, o| l.wo_b.matvec(m, o, pool),
2131 cfg.o_groups,
2132 cfg.o_lora_rank,
2133 pool,
2134 out,
2135 );
2136 bf16_inplace(out);
2138 if gpu_tail_tap().is_some() {
2139 trace_stats("cpu_tail", st.pos, Some(li), out);
2140 }
2141 prof::add(&prof::ATTN_OTHER_NS, attn_other_t0);
2142 qr
2143}
2144
2145fn sparse_attend_split(
2153 q: &[f32],
2154 window: &[f32],
2155 compressed: Option<&[f32]>,
2156 idxs: &[usize],
2157 sink: f32,
2158 scale: f32,
2159 window_len: usize,
2160 head_dim: usize,
2161 out: &mut [f32],
2162) {
2163 let row = |logical: usize| -> Option<&[f32]> {
2164 if logical < window_len {
2165 window.get(logical * head_dim..(logical + 1) * head_dim)
2166 } else {
2167 compressed.and_then(|c| {
2168 let p = logical - window_len;
2169 c.get(p * head_dim..(p + 1) * head_dim)
2170 })
2171 }
2172 };
2173 let mut m = sink;
2174 let mut scores = Vec::with_capacity(idxs.len());
2175 for &p in idxs {
2176 let Some(k) = row(p) else {
2177 scores.push(f32::NEG_INFINITY);
2178 continue;
2179 };
2180 let dot: f32 = q.iter().zip(k).map(|(a, b)| a * b).sum::<f32>() * scale;
2181 m = m.max(dot);
2182 scores.push(dot);
2183 }
2184 let mut denom = (sink - m).exp();
2185 out.fill(0.0);
2186 for (&p, &score) in idxs.iter().zip(&scores) {
2187 let Some(v) = row(p) else {
2188 continue;
2189 };
2190 let weight = (score - m).exp();
2191 denom += weight;
2192 for (dst, &value) in out.iter_mut().zip(v) {
2193 *dst += weight * value;
2194 }
2195 }
2196 if denom > 0.0 && denom.is_finite() {
2197 let inv = 1.0 / denom;
2198 for dst in out.iter_mut() {
2199 *dst *= inv;
2200 }
2201 }
2202}
2203
2204fn candidate_blocks(scores: &[f32], top_blocks: usize, block: usize) -> Vec<bool> {
2205 let n = scores.len();
2206 let blocks = n.div_ceil(block.max(1));
2207 if blocks == 0 {
2208 return Vec::new();
2209 }
2210 let block = block.max(1);
2211 let mut order: Vec<usize> = (0..blocks).collect();
2212 order.sort_by(|&a, &b| {
2215 let sa = scores[a * block..((a + 1) * block).min(n)]
2216 .iter()
2217 .copied()
2218 .fold(f32::NEG_INFINITY, f32::max);
2219 let sb = scores[b * block..((b + 1) * block).min(n)]
2220 .iter()
2221 .copied()
2222 .fold(f32::NEG_INFINITY, f32::max);
2223 sb.partial_cmp(&sa)
2224 .unwrap_or(std::cmp::Ordering::Equal)
2225 .then_with(|| a.cmp(&b))
2226 });
2227 let reachable = scores.iter().filter(|x| x.is_finite()).count();
2228 if reachable == 0 {
2229 return vec![false; n];
2230 }
2231 let last = scores
2232 .iter()
2233 .rposition(|x| x.is_finite())
2234 .map(|p| p / block)
2235 .unwrap_or(0);
2236 let mut keep = vec![false; blocks];
2237 let budget = top_blocks.min(blocks);
2238 let mut selected = 0usize;
2239 if budget > 0 {
2240 keep[last] = true;
2241 selected = 1;
2242 }
2243 for &b in &order {
2244 if selected >= budget {
2245 break;
2246 }
2247 if b == last || keep[b] {
2248 continue;
2249 }
2250 let block_score = scores[b * block..((b + 1) * block).min(n)]
2251 .iter()
2252 .copied()
2253 .fold(f32::NEG_INFINITY, f32::max);
2254 if block_score.is_finite() {
2255 keep[b] = true;
2256 selected += 1;
2257 }
2258 }
2259 let mut out = vec![false; n];
2260 for b in 0..blocks {
2261 if keep[b] {
2262 for i in b * block..((b + 1) * block).min(n) {
2263 out[i] = true;
2264 }
2265 }
2266 }
2267 out
2268}
2269
2270#[cfg(feature = "gpu")]
2271fn dsv41_expert_cpu(
2272 expert: &Dsv41Expert,
2273 cfg: &Dsv41Cfg,
2274 x: &[f32],
2275 weight: f32,
2276 pool: Option<&Pool>,
2277 out: &mut [f32],
2278) {
2279 let mut g = vec![0.0f32; cfg.moe_inter];
2280 let mut u = vec![0.0f32; cfg.moe_inter];
2281 matvec_bf16(&expert.w1, x, &mut g, pool);
2282 matvec_bf16(&expert.w3, x, &mut u, pool);
2283 for i in 0..cfg.moe_inter {
2284 if cfg.swiglu_limit > 0.0 {
2285 g[i] = g[i].min(cfg.swiglu_limit);
2286 u[i] = u[i].clamp(-cfg.swiglu_limit, cfg.swiglu_limit);
2287 }
2288 g[i] = g[i] / (1.0 + (-g[i]).exp()) * u[i] * weight;
2289 }
2290 bf16_inplace(&mut g);
2294 let mut tmp = vec![0.0f32; cfg.dim];
2295 matvec_bf16(&expert.w2, &g, &mut tmp, pool);
2296 for (dst, value) in out.iter_mut().zip(tmp) {
2297 *dst += value;
2298 }
2299}
2300
2301#[cfg(feature = "gpu")]
2302fn dsv41_cold_experts_cpu(
2303 layer: &Dsv41Layer,
2304 cfg: &Dsv41Cfg,
2305 x: &[f32],
2306 cold: &[(usize, f32)],
2307 pool: Option<&Pool>,
2308) -> Vec<f32> {
2309 let mut out = vec![0.0f32; cfg.dim];
2310 for &(expert, weight) in cold {
2311 if let Some(expert) = layer.experts.get(expert) {
2312 dsv41_expert_cpu(expert, cfg, x, weight, pool, &mut out);
2313 }
2314 }
2315 out
2316}
2317
2318#[cfg(feature = "gpu")]
2324fn dynamic_moe_gpu(
2325 layer: &Dsv41Layer,
2326 cfg: &Dsv41Cfg,
2327 x: &[f32],
2328 pool: Option<&Pool>,
2329 logits: &[f32],
2330 picks: &[usize],
2331 weights: &[f32],
2332 layer_index: usize,
2333 n_layers: usize,
2334 state: &mut Dsv41State,
2335 out: &mut [f32],
2336) -> bool {
2337 if !crate::gpu::enabled_here()
2338 || !crate::gpu_wgpu::dsv4_global_moe_supported()
2339 || std::env::var("CMF_DSV41_DYNAMIC_MOE").as_deref() == Ok("0")
2340 || picks.len() != cfg.top_k
2341 || weights.len() != cfg.n_routed_experts
2342 || logits.len() != cfg.n_routed_experts
2343 || layer.gpu_expert_ids.len() != cfg.n_routed_experts
2344 || layer.gpu_shared_ids.is_none()
2345 {
2346 return false;
2347 }
2348 let first = match layer.experts.first() {
2349 Some(expert) => expert,
2350 None => return false,
2351 };
2352 let model = match first.w1.model_arc() {
2353 Some(model) => model,
2354 None => return false,
2355 };
2356 let gu_q2 = first.w1.model_dtype() == Some(TensorDtype::Q2TiledP)
2357 && first.w3.model_dtype() == Some(TensorDtype::Q2TiledP);
2358 if first.w2.model_dtype() != Some(TensorDtype::Q4TiledP) {
2359 return false;
2360 }
2361 let gu_dtype = if gu_q2 {
2364 TensorDtype::Q2TiledP
2365 } else {
2366 TensorDtype::Q4TiledP
2367 };
2368 let same_layout = layer.experts.iter().all(|expert| {
2369 expert
2370 .w1
2371 .model_arc()
2372 .is_some_and(|m| m.uid() == model.uid())
2373 && expert
2374 .w3
2375 .model_arc()
2376 .is_some_and(|m| m.uid() == model.uid())
2377 && expert
2378 .w2
2379 .model_arc()
2380 .is_some_and(|m| m.uid() == model.uid())
2381 && expert.w1.model_dtype() == Some(gu_dtype)
2382 && expert.w3.model_dtype() == Some(gu_dtype)
2383 && expert.w2.model_dtype() == Some(TensorDtype::Q4TiledP)
2384 });
2385 let shared_layout = layer
2386 .shared
2387 .w1
2388 .model_arc()
2389 .is_some_and(|m| m.uid() == model.uid())
2390 && layer
2391 .shared
2392 .w3
2393 .model_arc()
2394 .is_some_and(|m| m.uid() == model.uid())
2395 && layer
2396 .shared
2397 .w2
2398 .model_arc()
2399 .is_some_and(|m| m.uid() == model.uid())
2400 && layer.shared.w1.model_dtype() == Some(gu_dtype)
2401 && layer.shared.w3.model_dtype() == Some(gu_dtype)
2402 && layer.shared.w2.model_dtype() == Some(TensorDtype::Q4TiledP);
2403 if !same_layout || !shared_layout || layer_index >= n_layers {
2404 return false;
2405 }
2406 if state.gpu_pool.is_none() {
2407 state.gpu_pool = crate::qwen4_exp::QwenGpuPool::create_for_dsv41(
2408 &model,
2409 cfg.moe_inter,
2410 cfg.dim,
2411 n_layers,
2412 cfg.n_routed_experts,
2413 gu_q2,
2414 );
2415 }
2416 let (remap, shared_slot, segment_slots) = {
2417 let Some(gpu_pool) = state.gpu_pool.as_mut() else {
2418 return false;
2419 };
2420 let Some((remap, shared_slot)) = gpu_pool.ensure(
2421 &model,
2422 layer_index,
2423 picks,
2424 &layer.gpu_expert_ids,
2425 layer.gpu_shared_ids,
2426 ) else {
2427 return false;
2428 };
2429 (remap, shared_slot, gpu_pool.segment_slots)
2430 };
2431 let cold_ids: Vec<usize> = picks
2432 .iter()
2433 .copied()
2434 .filter(|&expert| remap.get(expert).copied() == Some(u32::MAX))
2435 .collect();
2436 let cold_jobs: Vec<(usize, f32)> = cold_ids
2437 .iter()
2438 .copied()
2439 .map(|expert| (expert, weights[expert]))
2440 .collect();
2441 let gpu_weights = crate::gpu_wgpu::Dsv4MoeW {
2442 router: &[],
2443 experts: &layer.gpu_expert_ids,
2444 logits,
2445 bias: Some(weights),
2448 mask: None,
2449 forced: Some(picks),
2450 remap: Some(&remap),
2451 global: Some(crate::gpu_wgpu::Dsv4GlobalMoe {
2452 pool_uid: model.uid(),
2453 shared_slot,
2454 segment_slots: segment_slots as u32,
2455 }),
2456 has_shared: true,
2457 shared_weight: 1.0,
2458 preweighted: true,
2459 qwen_softmax: false,
2460 };
2461 let geom = crate::gpu_wgpu::Dsv4MoeGeom {
2462 hidden: cfg.dim,
2463 inter: cfg.moe_inter,
2464 top_k: picks.len(),
2465 route_scale: 1.0,
2467 swiglu_limit: cfg.swiglu_limit,
2468 gu_q2,
2469 bf16: true,
2470 };
2471 let mut gpu_out = vec![0.0f32; cfg.dim];
2472 let mut cold_from_gpu = Vec::new();
2473 let mut cold_x = Vec::new();
2474 let (frame_ok, cold_cpu) = std::thread::scope(|scope| {
2475 let cpu = (!cold_jobs.is_empty()).then(|| {
2476 scope.spawn(|| {
2481 crate::gpu::cpu_scope(|| dsv41_cold_experts_cpu(layer, cfg, x, &cold_jobs, pool))
2482 })
2483 });
2484 let ok = crate::gpu_wgpu::dsv4_moe_frame(
2485 &model,
2486 &gpu_weights,
2487 geom,
2488 x,
2489 &mut cold_from_gpu,
2490 &mut cold_x,
2491 None,
2492 None,
2493 &mut gpu_out,
2494 );
2495 let cpu_out = cpu
2496 .and_then(|job| job.join().ok())
2497 .unwrap_or_else(|| vec![0.0; cfg.dim]);
2498 (ok, cpu_out)
2499 });
2500 if !frame_ok
2501 || cold_from_gpu.len() != cold_jobs.len()
2502 || cold_from_gpu
2503 .iter()
2504 .map(|&(expert, _)| expert)
2505 .ne(cold_ids.iter().copied())
2506 {
2507 return false;
2508 }
2509 prof::note_cold(cold_jobs.len());
2510 for (dst, src) in gpu_out.iter_mut().zip(cold_cpu) {
2511 *dst += src;
2512 }
2513 bf16_inplace(&mut gpu_out);
2515 out[..cfg.dim].copy_from_slice(&gpu_out);
2516 true
2517}
2518
2519fn moe(
2520 l: &Dsv41Layer,
2521 cfg: &Dsv41Cfg,
2522 x: &[f32],
2523 pool: Option<&Pool>,
2524 image: bool,
2525 position: usize,
2526 layer: usize,
2527 n_layers: usize,
2528 state: &mut Dsv41State,
2529 out: &mut [f32],
2530) {
2531 prof::note_moe();
2532 let mut logits = vec![0.0f32; cfg.n_routed_experts];
2533 matvec(&l.gate, x, &mut logits, pool);
2534 let bias = if image {
2535 l.gate_bias_vl.as_deref().unwrap_or(&l.gate_bias)
2536 } else {
2537 &l.gate_bias
2538 };
2539 let mut scores = Vec::with_capacity(logits.len());
2540 let temperature = cfg.gate_temp.max(f32::MIN_POSITIVE);
2541 for &v in &logits {
2542 let v = v / temperature;
2543 scores.push(if v > 20.0 { v } else { (1.0 + v.exp()).ln() }.sqrt());
2544 }
2545 let mut shifted: Vec<f32> = scores
2546 .iter()
2547 .enumerate()
2548 .map(|(i, s)| s + bias.get(i).copied().unwrap_or(0.0))
2549 .collect();
2550 let mut picks = Vec::with_capacity(cfg.top_k);
2551 for _ in 0..cfg.top_k.min(cfg.n_routed_experts) {
2552 let mut i = 0usize;
2553 let mut v = f32::NEG_INFINITY;
2554 for (j, &candidate) in shifted.iter().enumerate() {
2555 if candidate > v {
2556 i = j;
2557 v = candidate;
2558 }
2559 }
2560 if !v.is_finite() {
2561 break;
2562 }
2563 picks.push(i);
2564 shifted[i] = f32::NEG_INFINITY;
2565 }
2566 trace_moe(position, layer, image, &logits, &scores, bias, &picks);
2567 let sum = picks.iter().map(|&i| scores[i]).sum::<f32>().max(1e-20);
2568 let mut mix_weights = vec![0.0f32; cfg.n_routed_experts];
2569 if cfg.norm_topk_prob {
2570 for &e in &picks {
2571 mix_weights[e] = scores[e] / sum * cfg.route_scale;
2572 }
2573 } else {
2574 for &e in &picks {
2575 mix_weights[e] = scores[e] * cfg.route_scale;
2576 }
2577 }
2578 #[cfg(feature = "gpu")]
2579 if dynamic_moe_gpu(
2580 l,
2581 cfg,
2582 x,
2583 pool,
2584 &logits,
2585 &picks,
2586 &mix_weights,
2587 layer,
2588 n_layers,
2589 state,
2590 out,
2591 ) {
2592 prof::note_gpu_moe();
2593 return;
2594 }
2595 prof::note_cpu_moe();
2596 out.fill(0.0);
2597 let mut tmp = vec![0.0f32; cfg.dim];
2598 for &e in &picks {
2599 let ew = mix_weights[e];
2600 let ex = &l.experts[e];
2601 let mut g = vec![0.0f32; cfg.moe_inter];
2602 let mut u = vec![0.0f32; cfg.moe_inter];
2603 matvec_bf16(&ex.w1, x, &mut g, pool);
2604 matvec_bf16(&ex.w3, x, &mut u, pool);
2605 for i in 0..cfg.moe_inter {
2606 if cfg.swiglu_limit > 0.0 {
2607 g[i] = g[i].min(cfg.swiglu_limit);
2608 u[i] = u[i].clamp(-cfg.swiglu_limit, cfg.swiglu_limit);
2609 }
2610 g[i] = g[i] / (1.0 + (-g[i]).exp()) * u[i] * ew;
2611 }
2612 bf16_inplace(&mut g);
2613 matvec_bf16(&ex.w2, &g, &mut tmp, pool);
2614 for i in 0..cfg.dim {
2615 out[i] += tmp[i];
2616 }
2617 }
2618 let shared = &l.shared;
2619 let mut g = vec![0.0f32; cfg.moe_inter];
2620 let mut u = vec![0.0f32; cfg.moe_inter];
2621 matvec_bf16(&shared.w1, x, &mut g, pool);
2622 matvec_bf16(&shared.w3, x, &mut u, pool);
2623 for i in 0..cfg.moe_inter {
2624 if cfg.swiglu_limit > 0.0 {
2625 g[i] = g[i].min(cfg.swiglu_limit);
2626 u[i] = u[i].clamp(-cfg.swiglu_limit, cfg.swiglu_limit);
2627 }
2628 g[i] = g[i] / (1.0 + (-g[i]).exp()) * u[i];
2629 }
2630 bf16_inplace(&mut g);
2631 matvec_bf16(&shared.w2, &g, &mut tmp, pool);
2632 for i in 0..cfg.dim {
2633 out[i] += tmp[i];
2634 }
2635 bf16_inplace(out);
2638}
2639
2640fn hc_mixes(
2641 x: &[f32],
2642 fn_w: &[f32],
2643 base: &[f32],
2644 scale: &[f32; 3],
2645 cfg: &Dsv41Cfg,
2646 pool: Option<&Pool>,
2647 pre: &mut [f32],
2648 post: &mut [f32],
2649 comb: &mut [f32],
2650) {
2651 let mix_n = (2 + cfg.hc_mult) * cfg.hc_mult;
2652 let mut mixes = vec![0.0f32; mix_n];
2653 crate::dsv4::hc_mixes(x, fn_w, mix_n, cfg.norm_eps, pool, &mut mixes);
2654 crate::dsv4::hc_split_sinkhorn(
2655 &mixes,
2656 scale,
2657 base,
2658 cfg.hc_mult,
2659 cfg.hc_sinkhorn_iters,
2660 cfg.hc_eps,
2661 pre,
2662 post,
2663 comb,
2664 );
2665}
2666
2667pub fn forward_token(
2670 globals: &Dsv41Globals,
2671 layers: &[Dsv41Layer],
2672 cfg: &Dsv41Cfg,
2673 st: &mut Dsv41State,
2674 token_id: u32,
2675 position: usize,
2676 pool: Option<&Pool>,
2677 logits: &mut Vec<f32>,
2678) {
2679 forward_token_masked(
2680 globals, layers, cfg, st, token_id, position, true, pool, logits,
2681 )
2682}
2683
2684pub fn forward_token_masked(
2685 globals: &Dsv41Globals,
2686 layers: &[Dsv41Layer],
2687 cfg: &Dsv41Cfg,
2688 st: &mut Dsv41State,
2689 token_id: u32,
2690 position: usize,
2691 participates: bool,
2692 pool: Option<&Pool>,
2693 logits: &mut Vec<f32>,
2694) {
2695 forward_token_masked_with_embedding(
2696 globals,
2697 layers,
2698 cfg,
2699 st,
2700 token_id,
2701 position,
2702 participates,
2703 None,
2704 pool,
2705 logits,
2706 true,
2707 );
2708}
2709
2710pub fn forward_token_masked_with_embedding(
2714 globals: &Dsv41Globals,
2715 layers: &[Dsv41Layer],
2716 cfg: &Dsv41Cfg,
2717 st: &mut Dsv41State,
2718 token_id: u32,
2719 position: usize,
2720 participates: bool,
2721 embedding: Option<&[f32]>,
2722 pool: Option<&Pool>,
2723 logits: &mut Vec<f32>,
2724 want_logits: bool,
2725) {
2726 forward_token_impl(
2727 globals,
2728 layers,
2729 cfg,
2730 st,
2731 token_id,
2732 position,
2733 participates,
2734 embedding,
2735 pool,
2736 logits,
2737 want_logits,
2738 );
2739}
2740
2741fn forward_token_impl(
2742 globals: &Dsv41Globals,
2743 layers: &[Dsv41Layer],
2744 cfg: &Dsv41Cfg,
2745 st: &mut Dsv41State,
2746 token_id: u32,
2747 position: usize,
2748 participates: bool,
2749 embedding: Option<&[f32]>,
2750 pool: Option<&Pool>,
2751 logits: &mut Vec<f32>,
2752 want_logits: bool,
2753) {
2754 let total_t0 = prof::start();
2755 prof::note_token(layers.len());
2756 st.pos = position;
2757 let hashes = st.hash.as_mut().map(|h| h.push(token_id, participates));
2758 let mut embed = vec![0.0f32; cfg.dim];
2759 if let Some(embedding) = embedding {
2760 assert_eq!(embedding.len(), cfg.dim, "V4.1 override embedding width");
2761 embed.copy_from_slice(embedding);
2762 } else {
2763 globals.embed.row_f32(
2764 (token_id as usize).min(globals.embed.rows().saturating_sub(1)),
2765 &mut embed,
2766 );
2767 }
2768 trace_stats("embed", position, None, &embed);
2769 let mut h = vec![0.0f32; cfg.hc_mult * cfg.dim];
2770 for copy in 0..cfg.hc_mult {
2771 h[copy * cfg.dim..(copy + 1) * cfg.dim].copy_from_slice(&embed);
2772 }
2773 let mut pre_mix = vec![0.0f32; cfg.hc_mult];
2774 pre_mix[0] = 1.0;
2775 for (li, l) in layers.iter().enumerate() {
2776 if let (Some(e), Some(all)) = (&l.engram, hashes.as_ref()) {
2777 if let Some(ix) = cfg.engram_layers.iter().position(|&id| id == li) {
2778 let engram_t0 = prof::start();
2779 apply_engram(e, &mut h, &all[ix], cfg, participates, pool);
2780 prof::add(&prof::ENGRAM_NS, engram_t0);
2781 }
2782 }
2783 let residual = h.clone();
2784 let mut ap = vec![0.0; cfg.hc_mult];
2785 let mut apo = vec![0.0; cfg.hc_mult];
2786 let mut ac = vec![0.0; cfg.hc_mult * cfg.hc_mult];
2787 hc_mixes(
2788 &h,
2789 &l.hc_attn_fn,
2790 &l.hc_attn_base,
2791 &l.hc_attn_scale,
2792 cfg,
2793 pool,
2794 &mut ap,
2795 &mut apo,
2796 &mut ac,
2797 );
2798 let mut folded = vec![0.0f32; cfg.dim];
2799 crate::dsv4::hc_fold(&h, &pre_mix, cfg.hc_mult, cfg.dim, &mut folded);
2800 rms(&mut folded, &l.attn_norm, cfg.norm_eps);
2801 let mut attn_out = vec![0.0f32; cfg.dim];
2802 let attn_t0 = prof::start();
2803 let _qr = attention(
2804 l,
2805 cfg,
2806 st,
2807 li,
2808 &folded,
2809 if cfg.ratio(li) > 0 {
2810 &globals.inv_freq_compress
2811 } else {
2812 &globals.inv_freq_window
2813 },
2814 pool,
2815 &mut attn_out,
2816 );
2817 prof::add(&prof::ATTN_NS, attn_t0);
2818 trace_stats("attn", position, Some(li), &attn_out);
2819 crate::dsv4::hc_expand(
2820 &attn_out,
2821 &residual,
2822 &apo,
2823 &ac,
2824 cfg.hc_mult,
2825 cfg.dim,
2826 &mut h,
2827 );
2828 bf16_inplace(&mut h);
2829 let residual2 = h.clone();
2830 let mut fp = vec![0.0; cfg.hc_mult];
2831 let mut fpo = vec![0.0; cfg.hc_mult];
2832 let mut fc = vec![0.0; cfg.hc_mult * cfg.hc_mult];
2833 hc_mixes(
2834 &h,
2835 &l.hc_ffn_fn,
2836 &l.hc_ffn_base,
2837 &l.hc_ffn_scale,
2838 cfg,
2839 pool,
2840 &mut fp,
2841 &mut fpo,
2842 &mut fc,
2843 );
2844 let mut ff = vec![0.0f32; cfg.dim];
2845 crate::dsv4::hc_fold(&h, &ap, cfg.hc_mult, cfg.dim, &mut folded);
2846 rms(&mut folded, &l.ffn_norm, cfg.norm_eps);
2847 let moe_t0 = prof::start();
2850 moe(
2851 l,
2852 cfg,
2853 &folded,
2854 pool,
2855 !participates,
2856 position,
2857 li,
2858 layers.len(),
2859 st,
2860 &mut ff,
2861 );
2862 prof::add(&prof::MOE_NS, moe_t0);
2863 crate::dsv4::hc_expand(&ff, &residual2, &fpo, &fc, cfg.hc_mult, cfg.dim, &mut h);
2864 bf16_inplace(&mut h);
2865 pre_mix.copy_from_slice(&fp);
2866 trace_stats("block", position, Some(li), &h);
2867 trace_stats("pre", position, Some(li), &pre_mix);
2868 }
2869 let head_t0 = prof::start();
2870 let mut final_h = vec![0.0f32; cfg.dim];
2871 crate::dsv4::hc_fold(&h, &pre_mix, cfg.hc_mult, cfg.dim, &mut final_h);
2872 rms(&mut final_h, &globals.norm, cfg.norm_eps);
2873 if want_logits {
2874 logits.resize(globals.head.rows(), 0.0);
2875 globals.head.matvec(&final_h, logits, pool);
2876 trace_stats("final", position, None, &final_h);
2877 trace_stats("logits", position, None, logits);
2878 } else {
2879 logits.clear();
2880 }
2881 prof::add(&prof::HEAD_NS, head_t0);
2882 prof::add(&prof::TOTAL_NS, total_t0);
2883}
2884
2885pub fn profile_report() {
2887 prof::report();
2888}
2889
2890pub fn forward_chunk(
2891 globals: &Dsv41Globals,
2892 layers: &[Dsv41Layer],
2893 cfg: &Dsv41Cfg,
2894 st: &mut Dsv41State,
2895 ids: &[u32],
2896 start: usize,
2897 pool: Option<&Pool>,
2898 logits: &mut Vec<f32>,
2899) {
2900 for (i, &id) in ids.iter().enumerate() {
2901 forward_token_masked_with_embedding(
2902 globals,
2903 layers,
2904 cfg,
2905 st,
2906 id,
2907 start + i,
2908 true,
2909 None,
2910 pool,
2911 logits,
2912 i + 1 == ids.len(),
2913 );
2914 }
2915}
2916
2917pub fn forward_chunk_masked_with_embeddings(
2921 globals: &Dsv41Globals,
2922 layers: &[Dsv41Layer],
2923 cfg: &Dsv41Cfg,
2924 st: &mut Dsv41State,
2925 ids: &[u32],
2926 start: usize,
2927 embeddings: &[Option<Vec<f32>>],
2928 participates: &[bool],
2929 pool: Option<&Pool>,
2930 logits: &mut Vec<f32>,
2931) {
2932 assert_eq!(ids.len(), embeddings.len());
2933 assert_eq!(ids.len(), participates.len());
2934 for (i, &id) in ids.iter().enumerate() {
2935 forward_token_masked_with_embedding(
2936 globals,
2937 layers,
2938 cfg,
2939 st,
2940 id,
2941 start + i,
2942 participates[i],
2943 embeddings[i].as_deref(),
2944 pool,
2945 logits,
2946 i + 1 == ids.len(),
2947 );
2948 }
2949}
2950
2951pub mod packed_kv {
2959 const FP4_LEVELS: [f32; 8] = [0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0];
2960 const MAIN_BLOCK: usize = 16;
2961 const INDEX_BLOCK: usize = 32;
2962
2963 #[derive(Clone, Debug)]
2967 pub struct PackedRows {
2968 cols: usize,
2969 block: usize,
2970 e8m0_scale: bool,
2971 value_bytes: usize,
2972 scale_bytes: usize,
2973 values: Vec<u8>,
2974 scales: Vec<u8>,
2975 }
2976
2977 impl PackedRows {
2978 pub fn new(cols: usize, block: usize, e8m0_scale: bool) -> Result<Self, String> {
2981 if cols == 0 || block == 0 || cols % block != 0 {
2982 return Err(format!(
2983 "packed KV width {cols} must be a positive multiple of block {block}"
2984 ));
2985 }
2986 Ok(Self {
2987 cols,
2988 block,
2989 e8m0_scale,
2990 value_bytes: cols.div_ceil(2),
2991 scale_bytes: cols / block,
2992 values: Vec::new(),
2993 scales: Vec::new(),
2994 })
2995 }
2996
2997 #[inline]
2998 pub fn cols(&self) -> usize {
2999 self.cols
3000 }
3001
3002 #[inline]
3003 pub fn block(&self) -> usize {
3004 self.block
3005 }
3006
3007 #[inline]
3008 pub fn rows(&self) -> usize {
3009 self.scales.len() / self.scale_bytes
3010 }
3011
3012 #[inline]
3013 pub fn row_bytes(&self) -> usize {
3014 self.value_bytes + self.scale_bytes
3015 }
3016
3017 #[inline]
3018 pub fn bytes(&self) -> usize {
3019 self.values.len() + self.scales.len()
3020 }
3021
3022 #[inline]
3023 pub fn clear(&mut self) {
3024 self.values.clear();
3025 self.scales.clear();
3026 }
3027
3028 pub fn push(&mut self, row: &[f32]) -> usize {
3034 assert_eq!(row.len(), self.cols);
3035 let row_id = self.rows();
3036 let value_base = row_id * self.value_bytes;
3037 let scale_base = row_id * self.scale_bytes;
3038 self.values.resize(value_base + self.value_bytes, 0);
3039 self.scales.resize(scale_base + self.scale_bytes, 0);
3040 for block_id in 0..self.scale_bytes {
3041 let begin = block_id * self.block;
3042 let end = begin + self.block;
3043 let min_amax = if self.e8m0_scale {
3044 6.0 * 2.0f32.powi(-126)
3045 } else {
3046 6.0 * 2.0f32.powi(-9)
3047 };
3048 let max = row[begin..end]
3049 .iter()
3050 .map(|x| x.abs())
3051 .fold(min_amax, f32::max);
3052 let raw_scale = max / 6.0;
3053 let scale = if self.e8m0_scale {
3054 super::round_e8m0_scale(raw_scale)
3055 } else {
3056 super::e4m3_round(raw_scale.max(6.0 * 2.0f32.powi(-9)))
3057 };
3058 self.scales[scale_base + block_id] = if self.e8m0_scale {
3059 encode_e8m0_scale(scale)
3060 } else {
3061 encode_e4m3_scale(scale)
3062 };
3063 for i in begin..end {
3064 let code = fp4_code(row[i] / scale);
3065 let dst = value_base + i / 2;
3066 if i & 1 == 0 {
3067 self.values[dst] = (self.values[dst] & 0xf0) | code;
3068 } else {
3069 self.values[dst] = (self.values[dst] & 0x0f) | (code << 4);
3070 }
3071 }
3072 }
3073 row_id
3074 }
3075
3076 pub fn row_into(&self, row: usize, dst: &mut [f32]) -> bool {
3079 if row >= self.rows() || dst.len() != self.cols {
3080 return false;
3081 }
3082 let value_base = row * self.value_bytes;
3083 let scale_base = row * self.scale_bytes;
3084 for block_id in 0..self.scale_bytes {
3085 let scale_byte = self.scales[scale_base + block_id];
3086 let scale = if self.e8m0_scale {
3087 super::e8m0_scale(scale_byte)
3088 } else {
3089 super::fp8_e4m3(scale_byte)
3090 };
3091 let begin = block_id * self.block;
3092 let end = begin + self.block;
3093 for i in begin..end {
3094 let code = if i & 1 == 0 {
3095 self.values[value_base + i / 2] & 0x0f
3096 } else {
3097 self.values[value_base + i / 2] >> 4
3098 };
3099 let mag = FP4_LEVELS[(code & 0x07) as usize];
3100 let signed = if code & 0x08 != 0 { -mag } else { mag };
3101 let mut value = signed * scale;
3104 if mag == 0.0 && code & 0x08 != 0 {
3105 value = -0.0;
3106 }
3107 dst[i] = super::bf16_roundtrip(value);
3108 }
3109 }
3110 true
3111 }
3112
3113 pub fn gather_rows(&self, rows: &[usize], dst: &mut [f32]) -> bool {
3116 if dst.len() != rows.len() * self.cols {
3117 return false;
3118 }
3119 for (i, &row) in rows.iter().enumerate() {
3120 if !self.row_into(row, &mut dst[i * self.cols..(i + 1) * self.cols]) {
3121 return false;
3122 }
3123 }
3124 true
3125 }
3126
3127 pub fn all_into(&self, dst: &mut [f32]) -> bool {
3130 if dst.len() != self.rows() * self.cols {
3131 return false;
3132 }
3133 self.gather_rows(&(0..self.rows()).collect::<Vec<_>>(), dst)
3134 }
3135 }
3136
3137 #[derive(Clone, Debug)]
3140 pub struct Dsv41PackedKvCache {
3141 main: Vec<PackedRows>,
3142 index: Vec<PackedRows>,
3143 }
3144
3145 impl Dsv41PackedKvCache {
3146 pub fn new(
3147 source_count: usize,
3148 main_cols: usize,
3149 index_cols: usize,
3150 ) -> Result<Self, String> {
3151 let mut main = Vec::with_capacity(source_count);
3152 let mut index = Vec::with_capacity(source_count);
3153 for _ in 0..source_count {
3154 main.push(PackedRows::new(main_cols, MAIN_BLOCK, false)?);
3155 index.push(PackedRows::new(index_cols, INDEX_BLOCK, true)?);
3156 }
3157 Ok(Self { main, index })
3158 }
3159
3160 #[inline]
3161 pub fn main_store(&self, source: usize) -> Option<&PackedRows> {
3162 self.main.get(source)
3163 }
3164
3165 #[inline]
3166 pub fn index_store(&self, source: usize) -> Option<&PackedRows> {
3167 self.index.get(source)
3168 }
3169
3170 #[inline]
3171 pub fn main_rows(&self, source: usize) -> usize {
3172 self.main_store(source).map_or(0, PackedRows::rows)
3173 }
3174
3175 #[inline]
3176 pub fn index_rows(&self, source: usize) -> usize {
3177 self.index_store(source).map_or(0, PackedRows::rows)
3178 }
3179
3180 #[inline]
3181 pub fn main_row_bytes(&self, source: usize) -> usize {
3182 self.main_store(source).map_or(0, PackedRows::row_bytes)
3183 }
3184
3185 #[inline]
3186 pub fn index_row_bytes(&self, source: usize) -> usize {
3187 self.index_store(source).map_or(0, PackedRows::row_bytes)
3188 }
3189
3190 #[inline]
3191 pub fn main_bytes(&self) -> usize {
3192 self.main.iter().map(PackedRows::bytes).sum()
3193 }
3194
3195 #[inline]
3196 pub fn index_bytes(&self) -> usize {
3197 self.index.iter().map(PackedRows::bytes).sum()
3198 }
3199
3200 #[inline]
3201 pub fn bytes(&self) -> usize {
3202 self.main_bytes() + self.index_bytes()
3203 }
3204
3205 pub fn clear(&mut self) {
3206 for store in &mut self.main {
3207 store.clear();
3208 }
3209 for store in &mut self.index {
3210 store.clear();
3211 }
3212 }
3213
3214 pub fn push_main(&mut self, source: usize, row: &[f32]) -> Option<usize> {
3215 self.main.get_mut(source).map(|store| store.push(row))
3216 }
3217
3218 pub fn push_index(&mut self, source: usize, row: &[f32]) -> Option<usize> {
3219 self.index.get_mut(source).map(|store| store.push(row))
3220 }
3221
3222 pub fn main_row_into(&self, source: usize, row: usize, dst: &mut [f32]) -> bool {
3223 self.main_store(source)
3224 .is_some_and(|store| store.row_into(row, dst))
3225 }
3226
3227 pub fn index_row_into(&self, source: usize, row: usize, dst: &mut [f32]) -> bool {
3228 self.index_store(source)
3229 .is_some_and(|store| store.row_into(row, dst))
3230 }
3231
3232 pub fn gather_main_rows(&self, source: usize, rows: &[usize], dst: &mut [f32]) -> bool {
3234 self.main_store(source)
3235 .is_some_and(|store| store.gather_rows(rows, dst))
3236 }
3237
3238 pub fn gather_index_rows(&self, source: usize, rows: &[usize], dst: &mut [f32]) -> bool {
3241 self.index_store(source)
3242 .is_some_and(|store| store.gather_rows(rows, dst))
3243 }
3244 }
3245
3246 fn fp4_code(value: f32) -> u8 {
3247 let q = super::fp4_round(value);
3248 let sign = if q.is_sign_negative() { 0x08 } else { 0 };
3249 let aq = q.abs();
3250 let mag = FP4_LEVELS
3251 .iter()
3252 .position(|&level| level.to_bits() == aq.to_bits())
3253 .unwrap_or(7);
3254 sign | mag as u8
3255 }
3256
3257 fn encode_e4m3_scale(scale: f32) -> u8 {
3258 (0u8..=0x7e)
3261 .find(|&byte| super::fp8_e4m3(byte).to_bits() == scale.to_bits())
3262 .unwrap_or_else(|| panic!("non-E4M3 scale {scale:?}"))
3263 }
3264
3265 fn encode_e8m0_scale(scale: f32) -> u8 {
3266 if !scale.is_finite() || scale <= 0.0 {
3267 return 0;
3268 }
3269 let exponent = scale.log2().round() as i32;
3270 (exponent + 127).clamp(0, 254) as u8
3271 }
3272}
3273#[cfg(test)]
3274mod tests {
3275 use super::*;
3276
3277 #[test]
3278 fn fp8_reference_points() {
3279 assert_eq!(fp8_e4m3(0), 0.0);
3280 assert_eq!(fp8_e4m3(0x38), 1.0);
3281 assert_eq!(fp8_e4m3(0xb8), -1.0);
3282 assert_eq!(fp8_e4m3(0x3c), 1.5);
3283 assert_eq!(fp8_e4m3(0x7e), 448.0);
3284 assert!(fp8_e4m3(0x7f).is_nan());
3285 assert_eq!(e8m0_scale(127), 1.0);
3286 assert_eq!(e8m0_scale(128), 2.0);
3287 }
3288
3289 #[test]
3290 fn fp8_rounds_finite_top_band_and_ties_even() {
3291 for (input, expected) in [
3294 (256.0, 256.0),
3295 (288.0, 288.0),
3296 (320.0, 320.0),
3297 (352.0, 352.0),
3298 (384.0, 384.0),
3299 (416.0, 416.0),
3300 (448.0, 448.0),
3301 (480.0, 448.0),
3302 (-320.0, -320.0),
3303 ] {
3304 assert_eq!(e4m3_round(input), expected, "input={input}");
3305 }
3306 let q = 2.0f32.powi(-9);
3309 assert_eq!(e4m3_round(0.5 * q), 0.0);
3310 assert_eq!(e4m3_round(1.5 * q), 2.0 * q);
3311 assert_eq!(e4m3_round(7.5 * q), 8.0 * q);
3312 assert_eq!(e4m3_round(272.0), 256.0);
3313 assert_eq!(e4m3_round(304.0), 320.0);
3314 assert_eq!(e4m3_round(432.0), 448.0);
3315 }
3316
3317 #[test]
3318 fn fp4_rounds_ties_to_even_level() {
3319 assert_eq!(fp4_round(0.25), 0.0);
3320 assert_eq!(fp4_round(0.75), 1.0);
3321 assert_eq!(fp4_round(1.25), 1.0);
3322 assert_eq!(fp4_round(1.75), 2.0);
3323 assert_eq!(fp4_round(2.5), 2.0);
3324 assert_eq!(fp4_round(3.5), 4.0);
3325 assert_eq!(fp4_round(5.0), 4.0);
3326 assert_eq!(fp4_round(-0.75), -1.0);
3327 }
3328
3329 #[test]
3330 fn release_hash_multipliers_are_stable() {
3331 assert_eq!(
3332 hash_multipliers(1, 4, 99092),
3333 [
3334 76632096046245,
3335 4839876093313,
3336 35959672319349,
3337 73987337458391
3338 ]
3339 );
3340 assert_eq!(
3341 hash_multipliers(14, 4, 99092),
3342 [
3343 67716810739261,
3344 51510806800915,
3345 30921347202721,
3346 82619226485591
3347 ]
3348 );
3349 }
3350
3351 #[test]
3352 fn release_hash_layout_is_disjoint_and_stable() {
3353 let h = EngramHash::new(
3354 vec![1, 14],
3355 4,
3356 8,
3357 16_000_000,
3358 99_092,
3359 2,
3360 (0..99_092).map(|v| v as u32).collect(),
3361 )
3362 .unwrap();
3363 assert_eq!(
3364 h.primes[0][0],
3365 [
3366 16_000_057, 16_000_079, 16_000_081, 16_000_097, 16_000_121, 16_000_129, 16_000_133,
3367 16_000_183,
3368 ]
3369 );
3370 assert_eq!(h.offsets[0], [0, 128_000_880, 256_002_934]);
3374 assert_eq!(h.primes[1][2][7], 16_000_889);
3375 assert_eq!(h.offsets[1], [0, 128_004_290, 256_009_984]);
3376 }
3377
3378 #[test]
3379 fn dead_tokens_break_ngrams() {
3380 let map = (0..16).collect::<Vec<u32>>();
3381 let mut h = EngramHash::new(vec![1], 4, 2, 16, 16, 2, map).unwrap();
3382 let first = h.push(3, true);
3383 let second = h.push(4, false);
3384 let third = h.push(5, true);
3385 assert_ne!(first, second);
3386 assert_ne!(second, third);
3387 assert_eq!(h.history.last().copied(), Some(5));
3388 }
3389
3390 #[test]
3391 fn candidate_mask_is_bounded() {
3392 let mut scores = vec![f32::NEG_INFINITY; 32];
3393 scores[1] = 1.0;
3394 scores[2] = 2.0;
3395 scores[9] = 3.0;
3396 scores[31] = 0.0;
3397 let m = candidate_blocks(&scores, 2, 8);
3398 assert_eq!(m.len(), 32);
3399 assert!(m.iter().filter(|&&x| x).count() <= 24);
3400 }
3401
3402 #[test]
3403 fn split_attention_matches_materialized_stream() {
3404 let window = vec![
3405 0.10, 0.20, 0.30, 0.40, -0.20, 0.30, 0.50, -0.10, ];
3408 let compressed = vec![
3409 0.70, -0.40, 0.10, 0.20, -0.30, 0.60, 0.20, 0.90, ];
3412 let idxs = [0, 2, 3];
3413 let mut stream = window.clone();
3414 stream.extend_from_slice(&compressed);
3415 let q = [0.25, -0.10, 0.40, 0.05];
3416 let mut expected = [0.0; 4];
3417 crate::dsv4::sparse_attend(&q, &stream, &idxs, -0.2, 0.5, 4, &mut expected);
3418 let mut actual = [0.0; 4];
3419 sparse_attend_split(
3420 &q,
3421 &window,
3422 Some(&compressed),
3423 &idxs,
3424 -0.2,
3425 0.5,
3426 2,
3427 4,
3428 &mut actual,
3429 );
3430 for (a, b) in actual.iter().zip(expected) {
3431 assert!((a - b).abs() < 1e-7, "split={a} materialized={b}");
3432 }
3433 }
3434
3435 #[test]
3436 fn packed_rows_match_source_fp4_and_preserve_signed_zero() {
3437 let mut main_input = (0..32)
3438 .map(|i| (i as f32 - 13.0) * 0.137)
3439 .collect::<Vec<_>>();
3440 main_input[0] = -0.0;
3441 main_input[1] = 0.25;
3442 main_input[16] = 2688.0;
3443 let mut main_ref = main_input.clone();
3444 fp4_inplace(&mut main_ref, 16, false);
3445 let mut main = packed_kv::PackedRows::new(32, 16, false).unwrap();
3446 assert_eq!(main.push(&main_input), 0);
3447 let mut main_decoded = vec![0.0f32; 32];
3448 assert!(main.row_into(0, &mut main_decoded));
3449 for (i, (&expected, &actual)) in main_ref.iter().zip(&main_decoded).enumerate() {
3450 assert_eq!(expected.to_bits(), actual.to_bits(), "main row value {i}");
3451 }
3452 assert!(main_decoded[0].is_sign_negative());
3453
3454 let mut index_input = (0..64)
3455 .map(|i| ((i as f32 * 0.03125).sin()) * 3.0)
3456 .collect::<Vec<_>>();
3457 index_input[32] = -0.0;
3458 let mut index_ref = index_input.clone();
3459 fp4_inplace(&mut index_ref, 32, true);
3460 let mut index = packed_kv::PackedRows::new(64, 32, true).unwrap();
3461 index.push(&index_input);
3462 let mut index_decoded = vec![0.0f32; 64];
3463 assert!(index.row_into(0, &mut index_decoded));
3464 for (i, (&expected, &actual)) in index_ref.iter().zip(&index_decoded).enumerate() {
3465 assert_eq!(expected.to_bits(), actual.to_bits(), "index row value {i}");
3466 }
3467 assert!(index_decoded[32].is_sign_negative());
3468 assert_eq!(main.row_bytes(), 18);
3469 assert_eq!(index.row_bytes(), 34);
3470 }
3471
3472 #[test]
3473 fn packed_cache_gathers_once_and_tracks_source_rows() {
3474 let mut cache = packed_kv::Dsv41PackedKvCache::new(2, 32, 64).unwrap();
3475 let a = (0..32).map(|i| i as f32 * 0.01).collect::<Vec<_>>();
3476 let b = (0..32).map(|i| -(i as f32) * 0.02).collect::<Vec<_>>();
3477 let k = (0..64)
3478 .map(|i| (i as f32 - 20.0) * 0.03)
3479 .collect::<Vec<_>>();
3480 assert_eq!(cache.push_main(1, &a), Some(0));
3481 assert_eq!(cache.push_main(1, &b), Some(1));
3482 assert_eq!(cache.push_index(1, &k), Some(0));
3483 assert_eq!(cache.main_rows(0), 0);
3484 assert_eq!(cache.main_rows(1), 2);
3485 assert_eq!(cache.index_rows(1), 1);
3486 let mut gathered = vec![0.0f32; 64];
3487 assert!(cache.gather_main_rows(1, &[1, 0], &mut gathered));
3488 let mut row = vec![0.0f32; 32];
3489 assert!(cache.main_row_into(1, 1, &mut row));
3490 assert_eq!(&gathered[..32], &row[..]);
3491 assert_eq!(cache.main_row_bytes(1), 18);
3492 assert_eq!(cache.index_row_bytes(1), 34);
3493 assert_eq!(cache.bytes(), 2 * 18 + 34);
3494 }
3495
3496 #[test]
3497 fn v41_global_row_bytes_match_890_byte_slope() {
3498 let cache = packed_kv::Dsv41PackedKvCache::new(4, 512, 128).unwrap();
3499 assert_eq!(cache.main_row_bytes(0), 512 / 2 + 512 / 16);
3500 assert_eq!(cache.index_row_bytes(0), 128 / 2 + 128 / 32);
3501 assert_eq!(
3504 2.5 * (cache.main_row_bytes(0) + cache.index_row_bytes(0)) as f32,
3505 890.0
3506 );
3507 }
3508
3509 #[test]
3510 fn fp4_scales_keep_reference_zero_floors() {
3511 assert_eq!(round_e8m0_scale(2.0f32.powi(-126)), 2.0f32.powi(-126));
3512 assert_eq!(e4m3_round(2.0f32.powi(-9)), 2.0f32.powi(-9));
3513 let mut index = vec![0.0; 32];
3514 fp4_inplace(&mut index, 32, true);
3515 assert_eq!(index, vec![0.0; 32]);
3518 let mut compressed = vec![0.0; 16];
3519 fp4_inplace(&mut compressed, 16, false);
3520 assert_eq!(compressed, vec![0.0; 16]);
3521 }
3522}