#[cfg(test)]
#[cfg(feature = "cuda")]
mod cb009_kv_handoff {
use super::*;
const LAYERS: usize = 3;
const NUM_HEADS: usize = 12;
const NUM_KV_HEADS: usize = 2;
const HEAD_DIM: usize = 128;
const MAX_LEN: usize = 256;
const KV_SLOTS: usize = 4;
const SEQ_LEN: usize = 17;
const TARGET_SLOT: usize = 2;
fn val(layer: usize, head: usize, pos: usize, d: usize, tag: f32) -> f32 {
tag + layer as f32 * 1000.0 + head as f32 * 100.0 + pos as f32 + d as f32 * 0.001
}
fn fill_single_cache(exec: &mut CudaExecutor, tag: f32, is_k: bool) -> Vec<Vec<f32>> {
let per_layer = NUM_KV_HEADS * MAX_LEN * HEAD_DIM;
let mut all = Vec::new();
for layer in 0..LAYERS {
let mut host = vec![0.0f32; per_layer];
for head in 0..NUM_KV_HEADS {
for pos in 0..SEQ_LEN {
let base = (head * MAX_LEN + pos) * HEAD_DIM;
for d in 0..HEAD_DIM {
host[base + d] = val(layer, head, pos, d, tag);
}
}
}
let key = if is_k {
format!("kv_{layer}_k")
} else {
format!("kv_{layer}_v")
};
exec.kv_cache_gpu
.get_mut(&key)
.expect("single cache present")
.copy_from_host(&host)
.expect("upload single cache");
all.push(host);
}
all
}
fn assert_slot_contents(got: &[f32], want_layer: &[f32], layer: usize, which: &str) {
let slot_stride = NUM_KV_HEADS * MAX_LEN * HEAD_DIM;
for head in 0..NUM_KV_HEADS {
for pos in 0..SEQ_LEN {
let src = (head * MAX_LEN + pos) * HEAD_DIM;
let dst = TARGET_SLOT * slot_stride + src;
let ok = (0..HEAD_DIM).all(|d| got[dst + d].to_bits() == want_layer[src + d].to_bits());
assert!(
ok,
"FALSIFY-CB-009: {which} layer {layer} head {head} pos {pos} did not arrive \
in batched slot {TARGET_SLOT}. scatter_single_kv_to_batched is the \
prefill->decode handoff; if it drops a head, a layer, or the slot offset, \
decode attends over the wrong bytes and every proof about the attention \
kernel and its wiring is beside the point. See aprender#2753."
);
}
}
}
fn assert_peers_untouched(got: &[f32], layer: usize, which: &str) {
let slot_stride = NUM_KV_HEADS * MAX_LEN * HEAD_DIM;
let live = NUM_KV_HEADS * SEQ_LEN * HEAD_DIM;
for slot in 0..KV_SLOTS {
if slot == TARGET_SLOT {
continue;
}
let base = slot * slot_stride;
let clean = got[base..base + live].iter().all(|&x| x == 0.0);
assert!(
clean,
"FALSIFY-CB-009: {which} layer {layer} scatter wrote into slot {slot} while \
targeting slot {TARGET_SLOT} — a stride error that corrupts a PEER request"
);
}
}
#[test]
fn scatter_single_kv_to_batched_moves_every_layer_and_head_to_the_right_slot() {
let Ok(mut exec) = CudaExecutor::new(0) else {
println!(
"cb009_kv_handoff: no CUDA device — SKIPPED. This covers the prefill->decode KV \
handoff, which is device memory movement and cannot be checked on the host."
);
return;
};
exec.init_kv_cache_gpu(LAYERS, NUM_HEADS, NUM_KV_HEADS, HEAD_DIM, MAX_LEN)
.expect("single kv cache");
exec.init_batched_kv_cache_gpu(LAYERS, KV_SLOTS)
.expect("batched kv cache");
let k_want = fill_single_cache(&mut exec, 1.0, true);
let v_want = fill_single_cache(&mut exec, 2.0, false);
exec.scatter_single_kv_to_batched(TARGET_SLOT, SEQ_LEN)
.expect("scatter");
exec.stream.synchronize().expect("sync");
assert_eq!(
exec.batched_kv_lengths[TARGET_SLOT], SEQ_LEN,
"FALSIFY-CB-009: batched_kv_lengths[{TARGET_SLOT}] must equal the prefilled length"
);
let slot_stride = NUM_KV_HEADS * MAX_LEN * HEAD_DIM;
let mut got = vec![0.0f32; KV_SLOTS * slot_stride];
for layer in 0..LAYERS {
exec.batched_kv_k_caches
.get(&layer)
.expect("batched k cache")
.copy_to_host(&mut got)
.expect("download k");
assert_slot_contents(&got, &k_want[layer], layer, "K");
assert_peers_untouched(&got, layer, "K");
exec.batched_kv_v_caches
.get(&layer)
.expect("batched v cache")
.copy_to_host(&mut got)
.expect("download v");
assert_slot_contents(&got, &v_want[layer], layer, "V");
assert_peers_untouched(&got, layer, "V");
}
}
}