use crate::Engine;
use cudarc::driver::{CudaSlice, DevicePtr, DevicePtrMut};
use std::os::raw::c_void;
pub static MLA_DECODE_SPLIT_DISPATCHES: std::sync::atomic::AtomicU64 =
std::sync::atomic::AtomicU64::new(0);
fn mla_decode_split_on() -> bool {
std::env::var("MEMRA_MLA_DECODE_SPLIT").as_deref() == Ok("1")
}
fn mla_decode_split_for(blocks: usize, out_dim: usize) -> Option<i32> {
if !mla_decode_split_on() || blocks == 0 || blocks >= 1024 {
return None;
}
let want = 1024usize.div_ceil(blocks);
let cap = (out_dim / 32).max(1);
let split = want.min(cap);
if split <= 1 { None } else { Some(split as i32) }
}
fn mla_split_announce(kind: &str, t_q: usize, n_head: usize, split: i32) {
use std::sync::atomic::Ordering;
if MLA_DECODE_SPLIT_DISPATCHES.fetch_add(1, Ordering::Relaxed) == 0 {
eprintln!(
"[mla-decode-split] engaged {kind} t={t_q} heads={n_head} split={split} \
(output-range split of the (token, head) blocks; MEMRA_MLA_DECODE_SPLIT=1)"
);
}
}
pub static MLA_B200_DECODE_ARM_DISPATCHES: std::sync::atomic::AtomicU64 =
std::sync::atomic::AtomicU64::new(0);
fn mla_b200_decode_arm_on() -> bool {
cfg!(memra_sm100_tcgen05) && std::env::var("MEMRA_B200_MLA_DECODE_ARM").as_deref() == Ok("1")
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MlaB200Kernel {
AbsorbQ,
DecompressV,
AttnGathered,
}
impl MlaB200Kernel {
pub const ALL: [MlaB200Kernel; 3] = [
MlaB200Kernel::AbsorbQ,
MlaB200Kernel::DecompressV,
MlaB200Kernel::AttnGathered,
];
pub fn name(self) -> &'static str {
match self {
MlaB200Kernel::AbsorbQ => "absorb_q",
MlaB200Kernel::DecompressV => "decompress_v",
MlaB200Kernel::AttnGathered => "attn_gathered",
}
}
}
pub const MLA_B200_ARM_T_MAX: usize = 8;
pub const MLA_B200_ABSORB_Q_SPLIT: [i32; MLA_B200_ARM_T_MAX + 1] = [1, 4, 1, 1, 4, 1, 1, 1, 1];
pub const MLA_B200_DECOMPRESS_V_SPLIT: [i32; MLA_B200_ARM_T_MAX + 1] = [1, 4, 1, 1, 1, 1, 1, 1, 1];
pub const MLA_B200_ATTN_GATHERED_SPLIT: [i32; MLA_B200_ARM_T_MAX + 1] = [1, 2, 1, 1, 1, 1, 1, 1, 1];
pub const MLA_B200_ARM_REGRESSION_MARGIN: f64 = 1.05;
pub fn mla_b200_arm_table_split(kernel: MlaB200Kernel, t_q: usize) -> i32 {
if t_q == 0 || t_q > MLA_B200_ARM_T_MAX {
return 1;
}
match kernel {
MlaB200Kernel::AbsorbQ => MLA_B200_ABSORB_Q_SPLIT[t_q],
MlaB200Kernel::DecompressV => MLA_B200_DECOMPRESS_V_SPLIT[t_q],
MlaB200Kernel::AttnGathered => MLA_B200_ATTN_GATHERED_SPLIT[t_q],
}
}
fn mla_b200_split_for(kernel: MlaB200Kernel, t_q: usize, out_dim: usize) -> Option<i32> {
if !mla_b200_decode_arm_on() {
return None;
}
let split = mla_b200_arm_table_split(kernel, t_q);
let cap = (out_dim / 32).max(1) as i32;
if split <= 1 || split > cap {
None
} else {
Some(split)
}
}
fn mla_b200_split_announce(kind: &str, t_q: usize, n_head: usize, split: i32) {
use std::sync::atomic::Ordering;
if MLA_B200_DECODE_ARM_DISPATCHES.fetch_add(1, Ordering::Relaxed) == 0 {
eprintln!(
"[mla-b200-decode-arm] engaged {kind} t={t_q} heads={n_head} split={split} \
(sm_100a output-range split; MEMRA_B200_MLA_DECODE_ARM=1)"
);
}
}
pub static MLA_DSA_DECODE_DISPATCHES: std::sync::atomic::AtomicU64 =
std::sync::atomic::AtomicU64::new(0);
fn mla_dsa_decode_level() -> u32 {
if !cfg!(memra_sm100_tcgen05) {
return 0;
}
match std::env::var("MEMRA_B200_DSA_DECODE").as_deref() {
Ok("1") => 1,
Ok("2") => 2,
_ => 0,
}
}
pub const MLA_DSA_ARM_T_MAX: usize = 8;
pub const MLA_DSA_ATTN_ARM: [i32; MLA_DSA_ARM_T_MAX + 1] = [0, 32, 0, 0, 1, 0, 0, 0, 0];
pub const MLA_DSA_NAMED_CLASS_T_MAX: usize = 1;
pub const MLA_DSA_ATTN_CHUNK_SWEEP: [i32; 4] = [4, 8, 16, 32];
pub const MLA_DSA_SCORE_MIN_POOLS: usize = 4096;
pub const MLA_DSA_REGRESSION_MARGIN: f64 = 1.05;
pub fn mla_dsa_attn_arm(t_q: usize) -> i32 {
if t_q == 0 || t_q > MLA_DSA_ARM_T_MAX {
return 0;
}
MLA_DSA_ATTN_ARM[t_q]
}
pub fn mla_dsa_attn_arm_effective(t_q: usize) -> i32 {
let arm = mla_dsa_attn_arm(t_q);
if arm >= 2 && t_q > MLA_DSA_NAMED_CLASS_T_MAX {
return 0;
}
arm
}
pub static MLA_DSA_SELECT_DISPATCHES: std::sync::atomic::AtomicU64 =
std::sync::atomic::AtomicU64::new(0);
fn mla_dsa_select_on() -> bool {
cfg!(memra_sm100_tcgen05) && std::env::var("MEMRA_B200_DSA_SELECT").as_deref() == Ok("1")
}
pub const MLA_DSA_SELECT_MIN_POOLS: usize = 65_536;
pub const MLA_DSA_SELECT_T_MAX: usize = 8;
pub fn mla_dsa_select_engages(t_q: usize, n_pools: usize) -> bool {
(1..=MLA_DSA_SELECT_T_MAX).contains(&t_q) && n_pools >= MLA_DSA_SELECT_MIN_POOLS
}
fn mla_dsa_select_announce(t_q: usize, n_pools: usize, n_ctas: i32) {
use std::sync::atomic::Ordering;
if MLA_DSA_SELECT_DISPATCHES.fetch_add(1, Ordering::Relaxed) == 0 {
eprintln!(
"[mla-b200-dsa-select] engaged kpool_select t={t_q} pools={n_pools} ctas={n_ctas} \
class=exact (sm_100a; MEMRA_B200_DSA_SELECT=1)"
);
}
}
fn mla_dsa_geometry_refusal(rc: i32) -> bool {
matches!(rc, 40020 | 40021 | 40023)
}
fn mla_dsa_announce(kind: &str, t_q: usize, detail: &str) {
use std::sync::atomic::Ordering;
if MLA_DSA_DECODE_DISPATCHES.fetch_add(1, Ordering::Relaxed) == 0 {
eprintln!(
"[mla-b200-dsa-decode] engaged {kind} t={t_q} {detail} \
(sm_100a; MEMRA_B200_DSA_DECODE)"
);
}
}
unsafe extern "C" {
pub fn memra_mla_rope_interleaved_f32(
x: *mut f32,
n_pos: i32,
n_vec: i32,
d_rope: i32,
positions: *const i32,
base: f32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_split_latent_f32(
kv: *const f32,
c_kv: *mut f32,
k_pe: *mut f32,
t: i32,
kv_rank: i32,
d_rope: i32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_append_latent_f32(
cache: *mut f32,
c_kv: *const f32,
k_pe: *const f32,
slot: i32,
t: i32,
kv_rank: i32,
d_rope: i32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_absorb_q_f32(
q_nope: *const f32,
wk_b: *const f32,
q_lat: *mut f32,
t_q: i32,
n_head: i32,
d_nope: i32,
kv_rank: i32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_decompress_v_f32(
o_lat: *const f32,
wv_b: *const f32,
out: *mut f32,
t_q: i32,
n_head: i32,
d_v: i32,
kv_rank: i32,
stream: *mut c_void,
) -> i32;
#[allow(clippy::too_many_arguments)]
pub fn memra_mla_absorb_q_split_f32(
q_nope: *const f32,
wk_b: *const f32,
q_lat: *mut f32,
t_q: i32,
n_head: i32,
d_nope: i32,
kv_rank: i32,
split: i32,
stream: *mut c_void,
) -> i32;
#[allow(clippy::too_many_arguments)]
pub fn memra_mla_decompress_v_split_f32(
o_lat: *const f32,
wv_b: *const f32,
out: *mut f32,
t_q: i32,
n_head: i32,
d_v: i32,
kv_rank: i32,
split: i32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_attn_absorbed_f32(
q_lat: *const f32,
q_pe: *const f32,
cache: *const f32,
o_lat: *mut f32,
n_head: i32,
kv_rank: i32,
d_rope: i32,
t_q: i32,
t_kv: i32,
scale: f32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_index_append_ring_f32(
plane: *mut f32,
a: *const f32,
b: *const f32,
slot: i32,
t: i32,
wa: i32,
wb: i32,
rows: i32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_kpool_pool_keys_f32(
state: *const f32,
ape: *const f32,
pool_keys: *mut f32,
pool_begin: i32,
n_pools: i32,
pool: i32,
d: i32,
state_rows: i32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_kpool_score_f32(
q: *const f32,
pool_keys: *const f32,
hw: *const f32,
score: *mut f32,
t_q: i32,
heads: i32,
d: i32,
n_pools: i32,
pool: i32,
first_pos: i32,
qk_scale: f32,
head_scale: f32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_kpool_score_ref_f32(
q: *const f32,
pool_keys: *const f32,
hw: *const f32,
score: *mut f32,
t_q: i32,
heads: i32,
d: i32,
n_pools: i32,
pool: i32,
first_pos: i32,
qk_scale: f32,
head_scale: f32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_kpool_select_ws_ints(n_ctas: i32) -> i64;
pub fn memra_mla_kpool_select_ctas(n_pools: i32) -> i32;
#[allow(clippy::too_many_arguments)]
pub fn memra_mla_kpool_select_dsa_f32(
score: *const f32,
idx: *mut i32,
ws: *mut i32,
t_q: i32,
n_pools: i32,
pool: i32,
select_k: i32,
width: i32,
first_pos: i32,
always_tail: i32,
stream: *mut c_void,
) -> i32;
#[allow(clippy::too_many_arguments)]
pub fn memra_mla_kpool_select_dsa_redarm_f32(
score: *const f32,
idx: *mut i32,
ws: *mut i32,
t_q: i32,
n_pools: i32,
pool: i32,
select_k: i32,
width: i32,
first_pos: i32,
always_tail: i32,
bump: i32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_kpool_select_f32(
score: *const f32,
idx: *mut i32,
t_q: i32,
n_pools: i32,
pool: i32,
select_k: i32,
width: i32,
first_pos: i32,
always_tail: i32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_kpool_select_ref_f32(
score: *const f32,
idx: *mut i32,
t_q: i32,
n_pools: i32,
pool: i32,
select_k: i32,
width: i32,
first_pos: i32,
always_tail: i32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_attn_gathered_f32(
q_lat: *const f32,
q_pe: *const f32,
cache: *const f32,
idx: *const i32,
o_lat: *mut f32,
n_head: i32,
kv_rank: i32,
d_rope: i32,
t_q: i32,
n_slots: i32,
scale: f32,
stream: *mut c_void,
) -> i32;
#[allow(clippy::too_many_arguments)]
pub fn memra_mla_attn_gathered_dsa_f32(
q_lat: *const f32,
q_pe: *const f32,
cache: *const f32,
idx: *const i32,
o_lat: *mut f32,
n_head: i32,
kv_rank: i32,
d_rope: i32,
t_q: i32,
n_slots: i32,
scale: f32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_dsa_attn_chunk_span(n_slots: i32, chunks: i32) -> i32;
pub fn memra_mla_dsa_attn_split_f32(
q_lat: *const f32,
q_pe: *const f32,
cache: *const f32,
idx: *const i32,
o_lat: *mut f32,
part_m: *mut f32,
part_d: *mut f32,
part_acc: *mut f32,
n_head: i32,
kv_rank: i32,
d_rope: i32,
t_q: i32,
n_slots: i32,
chunks: i32,
scale: f32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_kpool_score_dsa_f32(
q: *const f32,
pool_keys: *const f32,
hw: *const f32,
score: *mut f32,
t_q: i32,
heads: i32,
d: i32,
n_pools: i32,
pool: i32,
first_pos: i32,
qk_scale: f32,
head_scale: f32,
stream: *mut c_void,
) -> i32;
pub fn memra_mla_attn_gathered_split_f32(
q_lat: *const f32,
q_pe: *const f32,
cache: *const f32,
idx: *const i32,
o_lat: *mut f32,
n_head: i32,
kv_rank: i32,
d_rope: i32,
t_q: i32,
n_slots: i32,
scale: f32,
split: i32,
stream: *mut c_void,
) -> i32;
fn memra_bf16_gemm_sb(
w_bf16: *const c_void,
x_bf16: *const c_void,
y: *mut c_void,
m: i32,
n: i32,
k: i32,
x_rs: i64,
x_bs: i64,
y_rs: i64,
y_bs: i64,
batch: i32,
y_is_bf16: i32,
ws: *mut c_void,
ws_bytes: usize,
stream: *mut c_void,
) -> i32;
}
type Res<T> = Result<T, Box<dyn std::error::Error>>;
fn ck(what: &str, rc: i32) -> Res<()> {
if rc == 0 {
return Ok(());
}
let detail = match rc {
40001 => " (d_rope must be even — interleaved rope rotates (2j, 2j+1) pairs)",
40002 => " (kv_rank exceeds the kernel's MLA_MAX_RANK shared-memory ceiling)",
40003 => " (d_rope exceeds the kernel's MLA_MAX_ROPE ceiling)",
40004 => " (t_q > t_kv — queries must be a suffix of the latent cache)",
40010 => " (k-pool size out of range — 1..=MLA_MAX_POOL)",
40011 => " (indexer head count out of range — 1..=1024, one thread per head)",
40012 => " (t_q * n_pools exceeds the grid.x contract)",
40017 => " (indexer head dim must be positive)",
40013 => {
" (always_select_tail=false: queries before the first complete pool would have an \
empty candidate set, which the memra-reference oracle refuses outright)"
}
40014 => " (index-list width is narrower than select_k * pool + pool - 1)",
40015 => " (empty gathered candidate list — a zero softmax denominator)",
40020 => " (latent row width is not a multiple of 4 — the DSA float4 staging needs it)",
40021 => " (DSA tile staging exceeds MLA_DSA_KV_SMEM_MAX)",
40022 => " (DSA slot-chunk count out of range — 1..=64)",
40023 => " (no DSA scorer instantiation for this (heads, d))",
r if (10000..20000).contains(&r) => " (cudaError)",
_ => "",
};
Err(format!("mla kernel `{what}` failed: rc {rc}{detail}").into())
}
impl Engine {
pub fn mla_rope_interleaved(
&self,
x: &mut CudaSlice<f32>,
pos_d: &CudaSlice<i32>,
n_pos: usize,
n_vec: usize,
d_rope: usize,
base: f32,
) -> Res<()> {
if d_rope == 0 {
return Ok(());
}
let s = self.stream();
unsafe {
ck(
"rope_interleaved",
memra_mla_rope_interleaved_f32(
x.device_ptr_mut(&s).0 as *mut f32,
n_pos as i32,
n_vec as i32,
d_rope as i32,
pos_d.device_ptr(&s).0 as *const i32,
base,
s.cu_stream() as *mut c_void,
),
)
}
}
pub fn mla_split_latent(
&self,
kv: &CudaSlice<f32>,
c_kv: &mut CudaSlice<f32>,
k_pe: &mut CudaSlice<f32>,
t: usize,
kv_rank: usize,
d_rope: usize,
) -> Res<()> {
let s = self.stream();
unsafe {
ck(
"split_latent",
memra_mla_split_latent_f32(
kv.device_ptr(&s).0 as *const f32,
c_kv.device_ptr_mut(&s).0 as *mut f32,
k_pe.device_ptr_mut(&s).0 as *mut f32,
t as i32,
kv_rank as i32,
d_rope as i32,
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)] pub fn mla_append_latent(
&self,
cache: &mut CudaSlice<f32>,
c_kv: &CudaSlice<f32>,
k_pe: &CudaSlice<f32>,
slot: usize,
t: usize,
kv_rank: usize,
d_rope: usize,
) -> Res<()> {
let s = self.stream();
unsafe {
ck(
"append_latent",
memra_mla_append_latent_f32(
cache.device_ptr_mut(&s).0 as *mut f32,
c_kv.device_ptr(&s).0 as *const f32,
k_pe.device_ptr(&s).0 as *const f32,
slot as i32,
t as i32,
kv_rank as i32,
d_rope as i32,
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)] pub fn mla_absorb_q(
&self,
q_nope: &CudaSlice<f32>,
wk_b: &CudaSlice<f32>,
q_lat: &mut CudaSlice<f32>,
t_q: usize,
n_head: usize,
d_nope: usize,
kv_rank: usize,
) -> Res<()> {
let s = self.stream();
if let Some(split) = mla_b200_split_for(MlaB200Kernel::AbsorbQ, t_q, kv_rank) {
mla_b200_split_announce("absorb_q", t_q, n_head, split);
return unsafe {
ck(
"absorb_q_split_b200",
memra_mla_absorb_q_split_f32(
q_nope.device_ptr(&s).0 as *const f32,
wk_b.device_ptr(&s).0 as *const f32,
q_lat.device_ptr_mut(&s).0 as *mut f32,
t_q as i32,
n_head as i32,
d_nope as i32,
kv_rank as i32,
split,
s.cu_stream() as *mut c_void,
),
)
};
}
if let Some(split) = mla_decode_split_for(t_q * n_head, kv_rank) {
mla_split_announce("absorb_q", t_q, n_head, split);
return unsafe {
ck(
"absorb_q_split",
memra_mla_absorb_q_split_f32(
q_nope.device_ptr(&s).0 as *const f32,
wk_b.device_ptr(&s).0 as *const f32,
q_lat.device_ptr_mut(&s).0 as *mut f32,
t_q as i32,
n_head as i32,
d_nope as i32,
kv_rank as i32,
split,
s.cu_stream() as *mut c_void,
),
)
};
}
unsafe {
ck(
"absorb_q",
memra_mla_absorb_q_f32(
q_nope.device_ptr(&s).0 as *const f32,
wk_b.device_ptr(&s).0 as *const f32,
q_lat.device_ptr_mut(&s).0 as *mut f32,
t_q as i32,
n_head as i32,
d_nope as i32,
kv_rank as i32,
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)] pub fn mla_decompress_v(
&self,
o_lat: &CudaSlice<f32>,
wv_b: &CudaSlice<f32>,
out: &mut CudaSlice<f32>,
t_q: usize,
n_head: usize,
d_v: usize,
kv_rank: usize,
) -> Res<()> {
let s = self.stream();
if let Some(split) = mla_b200_split_for(MlaB200Kernel::DecompressV, t_q, d_v) {
mla_b200_split_announce("decompress_v", t_q, n_head, split);
return unsafe {
ck(
"decompress_v_split_b200",
memra_mla_decompress_v_split_f32(
o_lat.device_ptr(&s).0 as *const f32,
wv_b.device_ptr(&s).0 as *const f32,
out.device_ptr_mut(&s).0 as *mut f32,
t_q as i32,
n_head as i32,
d_v as i32,
kv_rank as i32,
split,
s.cu_stream() as *mut c_void,
),
)
};
}
if let Some(split) = mla_decode_split_for(t_q * n_head, d_v) {
mla_split_announce("decompress_v", t_q, n_head, split);
return unsafe {
ck(
"decompress_v_split",
memra_mla_decompress_v_split_f32(
o_lat.device_ptr(&s).0 as *const f32,
wv_b.device_ptr(&s).0 as *const f32,
out.device_ptr_mut(&s).0 as *mut f32,
t_q as i32,
n_head as i32,
d_v as i32,
kv_rank as i32,
split,
s.cu_stream() as *mut c_void,
),
)
};
}
unsafe {
ck(
"decompress_v",
memra_mla_decompress_v_f32(
o_lat.device_ptr(&s).0 as *const f32,
wv_b.device_ptr(&s).0 as *const f32,
out.device_ptr_mut(&s).0 as *mut f32,
t_q as i32,
n_head as i32,
d_v as i32,
kv_rank as i32,
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)] pub fn mla_attn_absorbed(
&self,
q_lat: &CudaSlice<f32>,
q_pe: &CudaSlice<f32>,
cache: &CudaSlice<f32>,
o_lat: &mut CudaSlice<f32>,
n_head: usize,
kv_rank: usize,
d_rope: usize,
t_q: usize,
t_kv: usize,
scale: f32,
) -> Res<()> {
let s = self.stream();
unsafe {
ck(
"attn_absorbed",
memra_mla_attn_absorbed_f32(
q_lat.device_ptr(&s).0 as *const f32,
q_pe.device_ptr(&s).0 as *const f32,
cache.device_ptr(&s).0 as *const f32,
o_lat.device_ptr_mut(&s).0 as *mut f32,
n_head as i32,
kv_rank as i32,
d_rope as i32,
t_q as i32,
t_kv as i32,
scale,
s.cu_stream() as *mut c_void,
),
)
}
}
}
impl Engine {
#[allow(clippy::too_many_arguments)]
pub fn mla_kpool_pool_keys(
&self,
state: &CudaSlice<f32>,
ape: &CudaSlice<f32>,
pool_keys: &mut CudaSlice<f32>,
pool_begin: usize,
n_pools: usize,
pool: usize,
d: usize,
state_rows: usize,
) -> Res<()> {
let s = self.stream();
unsafe {
ck(
"kpool_pool_keys",
memra_mla_kpool_pool_keys_f32(
state.device_ptr(&s).0 as *const f32,
ape.device_ptr(&s).0 as *const f32,
pool_keys.device_ptr_mut(&s).0 as *mut f32,
pool_begin as i32,
n_pools as i32,
pool as i32,
d as i32,
state_rows as i32,
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)]
pub fn mla_index_append(
&self,
plane: &mut CudaSlice<f32>,
a: &CudaSlice<f32>,
b: &CudaSlice<f32>,
src_row: usize,
slot: usize,
t: usize,
wa: usize,
wb: usize,
rows: usize,
) -> Res<()> {
let s = self.stream();
unsafe {
ck(
"index_append_ring",
memra_mla_index_append_ring_f32(
plane.device_ptr_mut(&s).0 as *mut f32,
(a.device_ptr(&s).0 as *const f32).add(src_row * wa),
(b.device_ptr(&s).0 as *const f32).add(src_row * wb),
slot as i32,
t as i32,
wa as i32,
wb as i32,
rows as i32,
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)]
pub fn mla_kpool_score(
&self,
q: &CudaSlice<f32>,
pool_keys: &CudaSlice<f32>,
head_weights: &CudaSlice<f32>,
score: &mut CudaSlice<f32>,
t_q: usize,
heads: usize,
d: usize,
n_pools: usize,
pool: usize,
first_pos: usize,
qk_scale: f32,
head_scale: f32,
) -> Res<()> {
let s = self.stream();
if mla_dsa_decode_level() >= 1
&& (1..=MLA_DSA_ARM_T_MAX).contains(&t_q)
&& n_pools >= MLA_DSA_SCORE_MIN_POOLS
{
let rc = unsafe {
memra_mla_kpool_score_dsa_f32(
q.device_ptr(&s).0 as *const f32,
pool_keys.device_ptr(&s).0 as *const f32,
head_weights.device_ptr(&s).0 as *const f32,
score.device_ptr_mut(&s).0 as *mut f32,
t_q as i32,
heads as i32,
d as i32,
n_pools as i32,
pool as i32,
first_pos as i32,
qk_scale,
head_scale,
s.cu_stream() as *mut c_void,
)
};
if !mla_dsa_geometry_refusal(rc) {
mla_dsa_announce(
"kpool_score",
t_q,
&format!("arm=head-blocked heads={heads} pools={n_pools} class=bit-identical"),
);
return ck("kpool_score_dsa", rc);
}
}
unsafe {
ck(
"kpool_score",
memra_mla_kpool_score_f32(
q.device_ptr(&s).0 as *const f32,
pool_keys.device_ptr(&s).0 as *const f32,
head_weights.device_ptr(&s).0 as *const f32,
score.device_ptr_mut(&s).0 as *mut f32,
t_q as i32,
heads as i32,
d as i32,
n_pools as i32,
pool as i32,
first_pos as i32,
qk_scale,
head_scale,
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)]
pub fn mla_kpool_score_ref(
&self,
q: &CudaSlice<f32>,
pool_keys: &CudaSlice<f32>,
head_weights: &CudaSlice<f32>,
score: &mut CudaSlice<f32>,
t_q: usize,
heads: usize,
d: usize,
n_pools: usize,
pool: usize,
first_pos: usize,
qk_scale: f32,
head_scale: f32,
) -> Res<()> {
let s = self.stream();
unsafe {
ck(
"kpool_score_ref",
memra_mla_kpool_score_ref_f32(
q.device_ptr(&s).0 as *const f32,
pool_keys.device_ptr(&s).0 as *const f32,
head_weights.device_ptr(&s).0 as *const f32,
score.device_ptr_mut(&s).0 as *mut f32,
t_q as i32,
heads as i32,
d as i32,
n_pools as i32,
pool as i32,
first_pos as i32,
qk_scale,
head_scale,
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)]
pub fn mla_kpool_select(
&self,
score: &CudaSlice<f32>,
idx: &mut CudaSlice<i32>,
t_q: usize,
n_pools: usize,
pool: usize,
select_k: usize,
width: usize,
first_pos: usize,
always_tail: bool,
) -> Res<()> {
let s = self.stream();
if mla_dsa_select_on() && mla_dsa_select_engages(t_q, n_pools) {
let n_ctas = unsafe { memra_mla_kpool_select_ctas(n_pools as i32) };
let stride = unsafe { memra_mla_kpool_select_ws_ints(n_ctas) };
let mut ws = self.uninit_i32(t_q * stride as usize)?;
mla_dsa_select_announce(t_q, n_pools, n_ctas);
return unsafe {
ck(
"kpool_select_dsa",
memra_mla_kpool_select_dsa_f32(
score.device_ptr(&s).0 as *const f32,
idx.device_ptr_mut(&s).0 as *mut i32,
ws.device_ptr_mut(&s).0 as *mut i32,
t_q as i32,
n_pools as i32,
pool as i32,
select_k as i32,
width as i32,
first_pos as i32,
i32::from(always_tail),
s.cu_stream() as *mut c_void,
),
)
};
}
unsafe {
ck(
"kpool_select",
memra_mla_kpool_select_f32(
score.device_ptr(&s).0 as *const f32,
idx.device_ptr_mut(&s).0 as *mut i32,
t_q as i32,
n_pools as i32,
pool as i32,
select_k as i32,
width as i32,
first_pos as i32,
i32::from(always_tail),
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)]
pub fn mla_kpool_select_ref(
&self,
score: &CudaSlice<f32>,
idx: &mut CudaSlice<i32>,
t_q: usize,
n_pools: usize,
pool: usize,
select_k: usize,
width: usize,
first_pos: usize,
always_tail: bool,
) -> Res<()> {
let s = self.stream();
unsafe {
ck(
"kpool_select_ref",
memra_mla_kpool_select_ref_f32(
score.device_ptr(&s).0 as *const f32,
idx.device_ptr_mut(&s).0 as *mut i32,
t_q as i32,
n_pools as i32,
pool as i32,
select_k as i32,
width as i32,
first_pos as i32,
i32::from(always_tail),
s.cu_stream() as *mut c_void,
),
)
}
}
#[allow(clippy::too_many_arguments)]
pub fn mla_bf16_gemm_sb_raw(
&self,
w_bf16: &CudaSlice<u8>,
x_bf16: &CudaSlice<u8>,
y_ptr: u64,
m: usize,
n: usize,
k: usize,
x_rs: usize,
x_bs: usize,
y_rs: usize,
y_bs: usize,
batch: usize,
y_bf16: bool,
) -> Res<i32> {
let mut guard = self.f16_scratch.lock().unwrap();
if guard.is_none() {
*guard = Some(crate::f16_ffi::F16Scratch::with_capacity(self, 2)?);
}
let s_scr = guard.as_mut().unwrap();
let s = self.stream();
let rc = unsafe {
memra_bf16_gemm_sb(
w_bf16.device_ptr(&s).0 as *const c_void,
x_bf16.device_ptr(&s).0 as *const c_void,
y_ptr as *mut c_void,
m as i32,
n as i32,
k as i32,
x_rs as i64,
x_bs as i64,
y_rs as i64,
y_bs as i64,
batch as i32,
i32::from(y_bf16),
s_scr.ws.device_ptr_mut(&s).0 as *mut c_void,
crate::f16_ffi::F16_WS_BYTES,
s.cu_stream() as *mut c_void,
)
};
Ok(rc)
}
#[allow(clippy::too_many_arguments)]
pub fn mla_bf16_gemm_sb_bf16out(
&self,
w_bf16: &CudaSlice<u8>,
x_bf16: &CudaSlice<u8>,
y_bf16: &mut CudaSlice<u8>,
m: usize,
n: usize,
k: usize,
x_rs: usize,
x_bs: usize,
y_rs: usize,
y_bs: usize,
batch: usize,
) -> Res<bool> {
let s = self.stream();
let (y_ptr, _gy) = y_bf16.device_ptr_mut(&s);
let rc = self.mla_bf16_gemm_sb_raw(
w_bf16, x_bf16, y_ptr, m, n, k, x_rs, x_bs, y_rs, y_bs, batch, true,
)?;
match rc {
0 => Ok(true),
r if (20000..30000).contains(&r) => Ok(false),
r => Err(format!(
"mla bf16 strided-batched GEMM (bf16 out) failed: rc {r} \
(m={m} n={n} k={k} batch={batch})"
)
.into()),
}
}
#[allow(clippy::too_many_arguments)]
pub fn mla_bf16_gemm_sb_f32out(
&self,
w_bf16: &CudaSlice<u8>,
x_bf16: &CudaSlice<u8>,
y_f32: &mut CudaSlice<f32>,
m: usize,
n: usize,
k: usize,
x_rs: usize,
x_bs: usize,
y_rs: usize,
y_bs: usize,
batch: usize,
) -> Res<bool> {
let s = self.stream();
let (y_ptr, _gy) = y_f32.device_ptr_mut(&s);
let rc = self.mla_bf16_gemm_sb_raw(
w_bf16, x_bf16, y_ptr, m, n, k, x_rs, x_bs, y_rs, y_bs, batch, false,
)?;
match rc {
0 => Ok(true),
r if (20000..30000).contains(&r) => Ok(false),
r => Err(format!(
"mla bf16 strided-batched GEMM (f32 out) failed: rc {r} \
(m={m} n={n} k={k} batch={batch})"
)
.into()),
}
}
#[allow(clippy::too_many_arguments)]
pub fn mla_attn_gathered(
&self,
q_lat: &CudaSlice<f32>,
q_pe: &CudaSlice<f32>,
cache: &CudaSlice<f32>,
idx: &CudaSlice<i32>,
o_lat: &mut CudaSlice<f32>,
n_head: usize,
kv_rank: usize,
d_rope: usize,
t_q: usize,
n_slots: usize,
scale: f32,
) -> Res<()> {
let s = self.stream();
let dsa_level = mla_dsa_decode_level();
let dsa_arm = if dsa_level >= 1 && t_q <= MLA_DSA_ARM_T_MAX {
let a = mla_dsa_attn_arm_effective(t_q);
if a >= 2 && dsa_level < 2 { 0 } else { a }
} else {
0
};
if dsa_arm >= 2 {
let cells = t_q * n_head * dsa_arm as usize;
let mut part_m = self.uninit(cells)?;
let mut part_d = self.uninit(cells)?;
let mut part_acc = self.uninit(cells * kv_rank)?;
let rc = unsafe {
memra_mla_dsa_attn_split_f32(
q_lat.device_ptr(&s).0 as *const f32,
q_pe.device_ptr(&s).0 as *const f32,
cache.device_ptr(&s).0 as *const f32,
idx.device_ptr(&s).0 as *const i32,
o_lat.device_ptr_mut(&s).0 as *mut f32,
part_m.device_ptr_mut(&s).0 as *mut f32,
part_d.device_ptr_mut(&s).0 as *mut f32,
part_acc.device_ptr_mut(&s).0 as *mut f32,
n_head as i32,
kv_rank as i32,
d_rope as i32,
t_q as i32,
n_slots as i32,
dsa_arm,
scale,
s.cu_stream() as *mut c_void,
)
};
if !mla_dsa_geometry_refusal(rc) {
mla_dsa_announce(
"attn_gathered",
t_q,
&format!("arm=warp-online chunks={dsa_arm} class=dsa-warp-online-f32"),
);
return ck("attn_gathered_dsa_warp", rc);
}
} else if dsa_arm == 1 {
let rc = unsafe {
memra_mla_attn_gathered_dsa_f32(
q_lat.device_ptr(&s).0 as *const f32,
q_pe.device_ptr(&s).0 as *const f32,
cache.device_ptr(&s).0 as *const f32,
idx.device_ptr(&s).0 as *const i32,
o_lat.device_ptr_mut(&s).0 as *mut f32,
n_head as i32,
kv_rank as i32,
d_rope as i32,
t_q as i32,
n_slots as i32,
scale,
s.cu_stream() as *mut c_void,
)
};
if !mla_dsa_geometry_refusal(rc) {
mla_dsa_announce("attn_gathered", t_q, "arm=single-pass class=bit-identical");
return ck("attn_gathered_dsa", rc);
}
}
if let Some(split) = mla_b200_split_for(MlaB200Kernel::AttnGathered, t_q, kv_rank) {
mla_b200_split_announce("attn_gathered", t_q, n_head, split);
return unsafe {
ck(
"attn_gathered_split_b200",
memra_mla_attn_gathered_split_f32(
q_lat.device_ptr(&s).0 as *const f32,
q_pe.device_ptr(&s).0 as *const f32,
cache.device_ptr(&s).0 as *const f32,
idx.device_ptr(&s).0 as *const i32,
o_lat.device_ptr_mut(&s).0 as *mut f32,
n_head as i32,
kv_rank as i32,
d_rope as i32,
t_q as i32,
n_slots as i32,
scale,
split,
s.cu_stream() as *mut c_void,
),
)
};
}
unsafe {
ck(
"attn_gathered",
memra_mla_attn_gathered_f32(
q_lat.device_ptr(&s).0 as *const f32,
q_pe.device_ptr(&s).0 as *const f32,
cache.device_ptr(&s).0 as *const f32,
idx.device_ptr(&s).0 as *const i32,
o_lat.device_ptr_mut(&s).0 as *mut f32,
n_head as i32,
kv_rank as i32,
d_rope as i32,
t_q as i32,
n_slots as i32,
scale,
s.cu_stream() as *mut c_void,
),
)
}
}
}