Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions crates/gpu-gates/src/bin/gate_deepseek41_prefill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@
//! still carries the ids as they came), with ids inside it raise nothing.
//! The same for `ds41_ffn_handoff_8` through the launcher, which picks it
//! for an 8-slot `PageLayout` (a past id at slot 7 among them), writing no
//! word of the image but its fields; a handoff of 5, 7 or 9 slots is
//! refused by name. The same for `ds41_ffn_handoff_10` over a 10-slot
//! `PageLayout` (past ids at slots 3 and 9), a handoff of 9 or 11 slots
//! word of the image but its fields; a handoff of 5 or 7 slots is
//! refused by name. The same for `ds41_ffn_handoff_9` over a 9-slot
//! `PageLayout` (past ids at slots 4 and 8), a handoff of 5, 7 or 11 slots
//! refused by name, and for `ds41_ffn_handoff_10` over a 10-slot
//! `PageLayout` (past ids at slots 3 and 9), a handoff of 11 slots
//! refused by name. Then the prompt batch's 8-slot entries through their
//! launchers: `ds41_ffn_card_acc_8` against the host rule
//! `runtime::combine::card_sum` bit for bit (the six-slot entry against the
Expand Down Expand Up @@ -1135,6 +1137,7 @@ mod gate {
let mut ok = places_cases(gpu)?;
ok &= handoff_cases(gpu)?;
ok &= handoff8_cases(gpu)?;
ok &= handoff9_cases(gpu)?;
ok &= handoff10_cases(gpu)?;
ok &= batch8_cases(gpu)?;
ok &= tile_case(gpu, w, layers, hp)?;
Expand Down Expand Up @@ -1330,24 +1333,46 @@ mod gate {
/// as they came, the weights and the activation and nothing else of the
/// image, and every slot's place, the one at slot 7 included; ids at and
/// past the stack (slots 3 and 7) raise `expert_id` and place [`HOST`].
/// A handoff of 5, 7 or 9 slots is refused by name, nothing written.
/// A handoff of 5 or 7 slots is refused by name, nothing written.
fn handoff8_cases(gpu: &Gpu) -> Result<bool, GateError> {
let past = N_EXPERT as u32;
handoff_slots_cases::<SLOTS8>(
gpu,
[0, 3, 5, 383, 9, 12, 300, 6],
[0, 3, 5, past, 9, 12, 300, past + 616],
[0.25, 0.125, 0.25, 0.125, 0.0625, 0.0625, 0.0625, 0.0625],
&[5, 7, 9],
// PIN(2026-10-16): handoff8/10 stop refusing 9; the built
// nine-slot entry is checked by handoff9_cases.
&[5, 7],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Date why handoff8/10 remove the nine-slot refusal cases.

Suggested change
&[5, 7],
// PIN(2026-10-16): handoff8/10 stop refusing 9; the built nine-slot entry is checked by handoff9_cases.
&[5, 7],

)
}

/// Slots a token of the handoff's third entry (Qwen3.8's).
/// Slots a token of the handoff's third entry (Bolt's).
const SLOTS9: usize = 9;

/// [`handoff8_cases`] at nine slots: `ds41_ffn_handoff_9` into an image
/// laid out by a 9-slot `PageLayout`, ids at and past the stack at slots
/// 4 and 8 (the last); a handoff of 5, 7 or 11 slots is refused by name,
/// nothing written.
fn handoff9_cases(gpu: &Gpu) -> Result<bool, GateError> {
let past = N_EXPERT as u32;
handoff_slots_cases::<SLOTS9>(
gpu,
[0, 3, 5, 383, 9, 12, 300, 6, 200],
[0, 3, 5, 383, past, 12, 300, 6, past + 616],
[
0.25, 0.125, 0.125, 0.125, 0.125, 0.0625, 0.0625, 0.0625, 0.0625,
],
&[5, 7, 11],
)
}

/// Slots a token of the handoff's fourth entry (Qwen3.8's).
const SLOTS10: usize = 10;

/// [`handoff8_cases`] at ten slots: `ds41_ffn_handoff_10` into an image
/// laid out by a 10-slot `PageLayout`, ids at and past the stack at slots
/// 3 and 9 (the last); a handoff of 9 or 11 slots is refused by name,
/// 3 and 9 (the last); a handoff of 11 slots is refused by name,
/// nothing written.
fn handoff10_cases(gpu: &Gpu) -> Result<bool, GateError> {
let past = N_EXPERT as u32;
Expand All @@ -1358,7 +1383,7 @@ mod gate {
[
0.25, 0.125, 0.125, 0.125, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625,
],
&[9, 11],
&[11],
)
}

Expand Down Expand Up @@ -1590,7 +1615,10 @@ mod gate {
verdict(pass)
);
}
for n_used in [5, 7, 9] {
// PIN(2026-10-16): the card sum stops refusing 9 (`CardSlots::Nine`);
// the nine-slot entry is checked by gate_hybrid's combine clauses and
// gate-gpu-lib's places test.
for n_used in [5, 7] {
let z = DeviceBuffer::from_host(stream, &vec![0.0f32; SLOTS8 * N * M])?;
let s = DeviceBuffer::from_host(stream, &[HOST; SLOTS8 * M])?;
let mut acc = DeviceBuffer::from_host(stream, &[SENT; N * M])?;
Expand Down
155 changes: 155 additions & 0 deletions crates/gpu-gates/src/bin/gate_hybrid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@
//! The card's slot list (`card_sel`) on the same boundary: an id past the
//! card's prefix is written `HOST` with the word clean, and an id past the
//! whole stack is written `HOST` and raises the layer's `ExpertId`.
//! The card's routed combine (`ds41_ffn_card_acc_9`, the card slots' family
//! at nine) there, nine slots a token: with every place a card slot it is
//! `weighted_sum` bit for bit; with HOST slots (their down rows NaN, unread
//! by the contract) the kept slots give the oracle `card_sum` bit for bit —
//! fused, the fma the device compiles both kernels' `acc += w·down` to; a
//! place in `[n_card, HOST)` at its first value raises the layer's
//! `ExpertId` and NaNs every value of its token, the other tokens the
//! oracle's.
//! Last, on the engine itself (`n_l` = 32): a NaN in a hybrid layer's input
//! residual through `step_layer_hybrid` returns the card's fault at that
//! layer — its norm's and its router's sites in the mask, printed in the
Expand Down Expand Up @@ -107,6 +115,7 @@ fn main() -> std::process::ExitCode {

#[cfg(feature = "gpu")]
mod gate {
use bloomery_gpu::card_slots::{CardAcc, CardSlotKernels};
use bloomery_gpu::fused::FusedKernels;
use bloomery_gpu::hybrid::{
Boundary, BoundaryShape, HOST, HostExperts, Hybrid, HybridConfig, Poison, PoisonKind,
Expand All @@ -127,6 +136,7 @@ mod gate {
use gguf::{GgmlType, Gguf, Split};
use model::arch::deepseek2::derived::Derived;
use model::{Tensor2, Tensor2View};
use runtime::combine::card_sum;
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicU64, Ordering};

Expand Down Expand Up @@ -1342,6 +1352,151 @@ mod gate {
);
ok &= pass;
}

// The card's routed combine (`ds41_ffn_card_acc_9`, the card slots'
// family at nine) over this boundary's places, nine slots a token
// (Bolt's count), three tokens: with every place a card slot it is
// `weighted_sum` bit for bit — the two kernels are the same
// expression, order and contraction; with HOST slots their down
// rows hold NaN (the contract leaves them unread) and the kept
// slots still give the oracle bit for bit; a place in
// `[n_card, HOST)` names neither a card slot nor the host, so the
// layer's ExpertId is raised and every value of its token is NaN
// while the other tokens keep theirs.
{
const E: usize = 9;
const M: usize = 3;
let rows = R_HIDDEN;
let n_card = R_CARD as u32;
let w: Vec<f32> = (0..M * E)
.map(|i| 0.05 + 0.04 * ((i / E + i % E) % 7) as f32)
.collect();
let val =
|t: usize, e: usize, d: usize| ((t * 31 + e * 17 + d * 5) % 97) as f32 * 0.25 - 3.0;
let down: Vec<f32> = (0..M * E)
.flat_map(|i| (0..rows).map(move |d| val(i / E, i % E, d)))
.collect();
let sel_all: Vec<u32> = (0..M * E)
.map(|i| ((i / E + i % E) % R_CARD) as u32)
.collect();
// The rule itself, as the host reads it: the shared oracle
// `runtime::combine::card_sum`, ascending slots from zero —
// fused, because the device compiles the kernels'
// `acc += w * down` (both entries, `weighted_sum` included) to
// an fma.
let sum_over = |down: &[f32], sel: &[u32], t: usize, d: usize| {
card_sum::<E>(
std::array::from_fn(|e| down[(t * E + e) * rows + d]),
std::array::from_fn(|e| w[t * E + e]),
std::array::from_fn(|e| sel[t * E + e] < n_card),
)
};
let transcription = |down: &[f32], sel: &[u32]| -> Vec<f32> {
(0..M)
.flat_map(|t| (0..rows).map(move |d| sum_over(down, sel, t, d)))
.collect()
};
let down_dev = DeviceBuffer::from_host(stream, &down)?;
let w_dev = DeviceBuffer::from_host(stream, &w)?;
let kernels = CardSlotKernels::load(gpu.context())?;
// The nine-slot card sum through the card slots' family, the
// buffers and extents the engine's card leg passes it.
let sum =
|down: &DeviceBuffer<f32>, sel: &DeviceBuffer<u32>, acc: &mut DeviceBuffer<f32>| {
kernels.enqueue_card_acc(
stream,
&CardAcc {
down,
w: &w_dev,
sel,
n: rows,
m: M,
n_card: R_CARD,
n_used: E,
w_pitch: E,
fault: gpu.layer_sink(R_LAYER)?,
},
acc,
)
};

// Every place a card slot: the card combine is the plain one,
// bit for bit, and reruns identical.
gpu.clear_fault()?;
let sel_dev = DeviceBuffer::from_host(stream, &sel_all)?;
let mut full = DeviceBuffer::<f32>::zeroed(stream, rows * M)?;
let mut card = DeviceBuffer::<f32>::zeroed(stream, rows * M)?;
gpu.elem()
.enqueue_weighted_sum(stream, &down_dev, &w_dev, rows, E as u32, M, &mut full)?;
sum(&down_dev, &sel_dev, &mut card)?;
stream.synchronize()?;
let full_y = full.to_host_vec(stream)?;
let card_y = card.to_host_vec(stream)?;
sum(&down_dev, &sel_dev, &mut card)?;
stream.synchronize()?;
let rerun = bits_equal(&card_y, &card.to_host_vec(stream)?);
let same = bits_equal(&full_y, &card_y);
let pass = same && rerun && gpu.take_fault()?.is_none();
println!(
"refusal card_acc_9 every slot a card slot: == weighted_sum bits {same}, \
rerun identical {rerun}, word clean {}",
verdict(pass)
);
ok &= pass;

// HOST slots at chosen places, their down rows NaN: the kept
// slots' sum is `card_sum` bit for bit.
gpu.clear_fault()?;
let mut down_h = down.clone();
let mut sel_h = sel_all.clone();
let host_slots = [&[2usize, 5][..], &[0, 8][..], &[3][..]];
for (t, slots) in host_slots.iter().enumerate() {
for &e in *slots {
sel_h[t * E + e] = HOST;
for d in 0..rows {
down_h[(t * E + e) * rows + d] = f32::NAN;
}
}
}
let want_h = transcription(&down_h, &sel_h);
let down_h_dev = DeviceBuffer::from_host(stream, &down_h)?;
let sel_h_dev = DeviceBuffer::from_host(stream, &sel_h)?;
sum(&down_h_dev, &sel_h_dev, &mut card)?;
stream.synchronize()?;
let host_y = card.to_host_vec(stream)?;
let pass = bits_equal(&host_y, &want_h) && gpu.take_fault()?.is_none();
println!(
"refusal card_acc_9 HOST slots skipped, their rows unread (NaN): == card_sum \
bits {}",
verdict(pass)
);
ok &= pass;

// A place in [n_card, HOST), at its first value: the layer's
// ExpertId, that token every value NaN, the others the oracle.
gpu.clear_fault()?;
let mut sel_bad = sel_h.clone();
sel_bad[E + 6] = n_card;
let want_bad = transcription(&down_h, &sel_bad);
let sel_bad_dev = DeviceBuffer::from_host(stream, &sel_bad)?;
sum(&down_h_dev, &sel_bad_dev, &mut card)?;
stream.synchronize()?;
let bad_y = card.to_host_vec(stream)?;
let token = |y: &[f32], t: usize| y[t * rows..(t + 1) * rows].to_vec();
let bad_nan = token(&bad_y, 1).iter().all(|v| v.is_nan());
let others = bits_equal(&token(&bad_y, 0), &token(&want_bad, 0))
&& bits_equal(&token(&bad_y, 2), &token(&want_bad, 2));
let word = gpu.take_fault()?;
let word_ok = word == Some(Fault::at(layer, FaultSite::ExpertId));
let pass = bad_nan && others && word_ok;
println!(
"refusal card_acc_9 a place in [n_card, HOST) at n_card: token NaN {bad_nan}, \
other tokens the oracle {others}, word \"{}\" {}",
word.map_or_else(|| "none".to_string(), |f| f.to_string()),
verdict(pass)
);
ok &= pass;
}
stream.synchronize()?;
println!("refusal verdict {}", verdict(ok));
Ok(ok)
Expand Down
Loading
Loading