use std::path::Path;
use model_io::ArchConfig;
use crate::real_forward_types::RealForwardError;
use model_io::ExpertCacheSlots;
pub(crate) fn validate_arch_config(expecting: &ArchConfig) -> Result<(), RealForwardError> {
for (name, value) in [
("num_kv_heads", expecting.num_kv_heads),
("num_full_kv_heads", expecting.num_full_kv_heads),
("head_dim", expecting.head_dim),
("full_head_dim", expecting.full_head_dim),
] {
if value <= 0 {
return Err(RealForwardError::Unsupported(format!(
"{name} must be positive, got {value}"
)));
}
}
if expecting.family == model_io::ModelFamily::GptOss
&& (expecting.num_kv_heads != expecting.num_full_kv_heads
|| expecting.head_dim != expecting.full_head_dim)
{
return Err(RealForwardError::Unsupported(format!(
"gpt-oss requires identical sliding and full KV dimensions; got sliding {}x{} and \
full {}x{}",
expecting.num_kv_heads,
expecting.head_dim,
expecting.num_full_kv_heads,
expecting.full_head_dim
)));
}
let max_kind = expecting
.full_attention_layer_mask
.iter()
.copied()
.max()
.unwrap_or(0);
if max_kind == 5 && expecting.family != model_io::ModelFamily::Deepseek2 {
return Err(RealForwardError::Unsupported(format!(
"MLA (mask 5) layers need the deepseek2 family, not {}",
expecting.family.as_str()
)));
}
if max_kind > 2 && max_kind != 5 {
return Err(RealForwardError::Unsupported(
"compressed (DeepSeek CSA/HCA) attention layers are not supported yet".to_string(),
));
}
if max_kind == 2
&& !matches!(
expecting.family,
model_io::ModelFamily::QwenGdnMoe
| model_io::ModelFamily::QwenGdnDense
| model_io::ModelFamily::Qwen4Exp
)
{
return Err(RealForwardError::Unsupported(format!(
"linear-attention layers need a qwen36, qwen35 or qwen4exp family, not {}",
expecting.family.as_str()
)));
}
if expecting.full_attention_layer_mask.contains(&0) && expecting.sliding_window <= 0 {
return Err(RealForwardError::Unsupported(
"sliding-window layers require a positive sliding_window".to_string(),
));
}
Ok(())
}
pub(crate) fn kv_quant_unsupported_reason(
expecting: &ArchConfig,
kv_quant: model_io::KvQuant,
) -> Option<String> {
if !kv_quant.is_on() {
return None;
}
if !model_io::rht_supported(expecting.full_head_dim) {
return Some(format!(
"--kv-bits needs a full head_dim that is a power of two in 32..=512; this install's \
is {} (see docs/TRUBOQUANT.md)",
expecting.full_head_dim
));
}
let num_layers = expecting.num_layers as usize;
let has_eligible_layer = expecting
.full_attention_layer_mask
.iter()
.enumerate()
.any(|(layer, &mask)| model_io::layer_is_quantized(kv_quant, mask, layer, num_layers));
if !has_eligible_layer {
return Some(
"--kv-bits has nothing to quantize on this install: every full-attention layer is \
excluded by the last-layer rule, or there are no full-attention layers at all"
.to_string(),
);
}
None
}
pub(crate) type ExpertStreamersResult = (
Vec<Option<streaming::PreadExpertStreamer>>,
Vec<Vec<gpu::MetalBuffer>>,
Option<model_io::PackedExpertsLayout>,
usize,
model_io::ResolvedExpertResidency,
MappedResidency,
);
#[derive(Default)]
pub(crate) struct MappedResidency {
pub(crate) buffers: Vec<Option<gpu::MetalBuffer>>,
pub(crate) layers: Vec<Option<streaming::MappedExpertLayer>>,
}
pub(crate) fn mapped_residency_requested() -> bool {
std::env::var("TURBOSPARK_EXPERT_RESIDENCY")
.map(|v| v.eq_ignore_ascii_case("mapped"))
.unwrap_or(false)
}
pub fn resolve_expert_residency(
requested: model_io::ExpertResidency,
physical_bytes: u64,
resident_bytes: u64,
bytes_per_slot: u64,
mapped_supported: bool,
) -> model_io::ResolvedExpertResidency {
use model_io::{ExpertResidency, ResolvedExpertResidency};
match requested {
ExpertResidency::Mapped => ResolvedExpertResidency::Mapped,
ExpertResidency::Streamed => ResolvedExpertResidency::Streamed,
ExpertResidency::Auto => {
let should_map = mapped_residency_requested()
|| (mapped_supported
&& model_io::auto_residency_prefers_mapped(
physical_bytes,
resident_bytes,
bytes_per_slot,
));
if should_map {
ResolvedExpertResidency::Mapped
} else {
ResolvedExpertResidency::Streamed
}
}
}
}
#[cfg(target_os = "macos")]
pub fn resolve_expert_residency_for_install(
dir: &Path,
family: model_io::ModelFamily,
requested: model_io::ExpertResidency,
physical_bytes: u64,
) -> Result<model_io::ResolvedExpertResidency, String> {
let resident_bytes = std::fs::metadata(dir.join("model_weights.bin"))
.map(|m| m.len())
.unwrap_or(0);
let bytes_per_slot = model_io::load_packed_experts_layout(
dir,
model_io::PACKED_EXPERTS_LAYOUT_DEFAULT_MAX_BYTES,
)
.map(|layout| layout.layers.iter().map(|layer| layer.expert_stride).sum())
.unwrap_or(0);
Ok(resolve_expert_residency(
requested,
physical_bytes,
resident_bytes,
bytes_per_slot,
mapped_residency_supported(family),
))
}
fn mapped_residency_supported(family: model_io::ModelFamily) -> bool {
matches!(
family,
model_io::ModelFamily::Gemma4
| model_io::ModelFamily::QwenGdnMoe
| model_io::ModelFamily::Llama
| model_io::ModelFamily::Qwen3Moe
| model_io::ModelFamily::GptOss
)
}
pub(crate) fn mapped_residency_refusal(
family: model_io::ModelFamily,
) -> Result<(), RealForwardError> {
if matches!(
family,
model_io::ModelFamily::Gemma4
| model_io::ModelFamily::QwenGdnMoe
| model_io::ModelFamily::Llama
| model_io::ModelFamily::Qwen3Moe
| model_io::ModelFamily::GptOss
) {
return Ok(());
}
Err(RealForwardError::Unsupported(format!(
"TURBOSPARK_EXPERT_RESIDENCY=mapped is not wired for {}; \
unset it to use the pread expert streamer. Widening it is ROADMAP item 9, and \
each family REPLACES this refusal rather than adding a branch to a silent path",
family.as_str()
)))
}
pub(crate) fn open_expert_streamers(
dir: &Path,
expecting: &ArchConfig,
expert_cache_slots: ExpertCacheSlots,
residency: model_io::ExpertResidency,
resident_bytes: u64,
max_bytes: u64,
context: &mut gpu::MetalContext,
) -> Result<ExpertStreamersResult, RealForwardError> {
let layout =
model_io::load_packed_experts_layout(dir, max_bytes).map_err(RealForwardError::Model)?;
let num_layers = expecting.num_layers as usize;
if layout.num_layers > 0 && layout.experts_per_layer != expecting.num_experts as usize {
return Err(RealForwardError::Unsupported(format!(
"packed_experts layout declares {} experts per layer, but the architecture declares {}",
layout.experts_per_layer, expecting.num_experts
)));
}
let bytes_per_slot = layout.layers.iter().map(|l| l.expert_stride).sum::<u64>();
let resolved_residency = resolve_expert_residency(
residency,
gpu::physical_memory(),
resident_bytes,
bytes_per_slot,
mapped_residency_supported(expecting.family),
);
if resolved_residency == model_io::ResolvedExpertResidency::Mapped && layout.num_layers > 0 {
mapped_residency_refusal(expecting.family)?;
if !crate::expert_layout_validation::mapped_expert_count_matches(
expecting.num_experts,
layout.experts_per_layer,
) {
return Err(RealForwardError::Unsupported(format!(
"mapped expert residency needs packed_experts/layout.json expertsPerLayer \
({}) to match the architecture's num_experts ({})",
layout.experts_per_layer, expecting.num_experts
)));
}
let mut mapped = MappedResidency::default();
let lead = expecting.num_dense_leading_layers.max(0) as usize;
mapped.buffers.resize_with(num_layers, || None);
mapped.layers.resize_with(num_layers, || None);
for layer in lead..num_layers {
let entry = layout
.layers
.iter()
.find(|l| l.layer == layer - lead)
.ok_or_else(|| {
RealForwardError::Unsupported(format!(
"packed_experts layout missing blob position {} (checkpoint layer {layer})",
layer - lead
))
})?;
let stream_layout = streaming::StreamLayout::from_packed_experts_layer(entry, dir);
let mapped_layer = streaming::MappedExpertLayer::open(stream_layout).map_err(|e| {
RealForwardError::Unsupported(format!("mapped expert layer {layer}: {e}"))
})?;
let bytes = mapped_layer.page_aligned_bytes();
let buffer =
gpu::wrap_page_aligned_no_copy(context.device(), bytes.as_ptr(), bytes.len())
.map_err(RealForwardError::Gpu)?;
mapped.buffers[layer] = Some(buffer);
mapped.layers[layer] = Some(mapped_layer);
}
let resolved = expert_cache_slots
.resolve(
gpu::physical_memory(),
resident_bytes,
layout.layers.iter().map(|l| l.expert_stride).sum::<u64>(),
)
.min(layout.experts_per_layer.max(1));
let mut streamers: Vec<Option<streaming::PreadExpertStreamer>> = Vec::new();
streamers.resize_with(num_layers, || None);
let slot_buffers = vec![Vec::new(); num_layers];
return Ok((
streamers,
slot_buffers,
Some(layout),
resolved,
resolved_residency,
mapped,
));
}
let experts_per_layer = layout.experts_per_layer.max(1);
let bytes_per_slot = layout.layers.iter().map(|l| l.expert_stride).sum::<u64>();
let expert_cache_slots = expert_cache_slots
.resolve(gpu::physical_memory(), resident_bytes, bytes_per_slot)
.min(experts_per_layer);
let working_set = bytes_per_slot * expert_cache_slots as u64;
let mut streamers: Vec<Option<streaming::PreadExpertStreamer>> = Vec::new();
let experts_layout = if layout.num_layers > 0 {
let lead = expecting.num_dense_leading_layers.max(0) as usize;
for layer in 0..num_layers {
if layer < lead {
streamers.push(None);
continue;
}
let entry = layout
.layers
.iter()
.find(|l| l.layer == layer - lead)
.ok_or_else(|| {
RealForwardError::Unsupported(format!(
"packed_experts layout missing blob position {} (checkpoint layer \
{layer})",
layer - lead
))
})?;
let stream_layout = streaming::StreamLayout::from_packed_experts_layer(entry, dir);
let streamer = streaming::PreadExpertStreamer::open(
stream_layout,
expert_cache_slots,
streaming::ExpertCachePolicy::DEFAULT,
)
.map_err(|e| {
RealForwardError::Unsupported(format!(
"expert streamer: {e} (this install's slot cache wants {:.1} GiB of pinned \
host memory: {expert_cache_slots} slots x {num_layers} layers x \
{:.1} MiB per expert. That product is set by expert GRANULARITY -- a \
coarse MoE like Mixtral 8x7B has 8 experts of ~109 MiB where Gemma 4 has \
128 of ~3.2 MiB -- so lower `--expert-cache-slots`, or use a \
fine-grained checkpoint)",
working_set as f64 / (1024.0 * 1024.0 * 1024.0),
entry.expert_stride as f64 / (1024.0 * 1024.0),
))
})?;
streamers.push(Some(streamer));
}
Some(layout)
} else {
streamers.resize_with(num_layers, || None);
None
};
let mut slot_buffers: Vec<Vec<gpu::MetalBuffer>> = Vec::with_capacity(streamers.len());
for streamer in &streamers {
match streamer {
Some(s) => {
let mut wrapped = Vec::with_capacity(expert_cache_slots);
for slot in 0..expert_cache_slots {
let (ptr, len) = s.slot_allocation(slot);
wrapped.push(
gpu::wrap_page_aligned_no_copy(context.device(), ptr, len)
.map_err(RealForwardError::Gpu)?,
);
}
slot_buffers.push(wrapped);
}
None => slot_buffers.push(Vec::new()),
}
}
Ok((
streamers,
slot_buffers,
experts_layout,
expert_cache_slots,
resolved_residency,
MappedResidency::default(),
))
}
#[cfg(test)]
mod tests {
use super::{mapped_residency_refusal, resolve_expert_residency, validate_arch_config};
use model_io::ModelFamily;
const EVERY_FAMILY: &[ModelFamily] = &[
ModelFamily::Gemma4,
ModelFamily::QwenGdnMoe,
ModelFamily::DeepseekV4Flash,
ModelFamily::Llama,
ModelFamily::Qwen3Moe,
ModelFamily::GptOss,
ModelFamily::QwenGdnDense,
ModelFamily::MuseGlimmer,
ModelFamily::Qwen4Exp,
ModelFamily::Spark25,
ModelFamily::Qwen3Dense,
ModelFamily::MiniMaxM2,
ModelFamily::Qwen2Dense,
ModelFamily::Qwen3Vl,
ModelFamily::Deepseek2,
];
fn assert_invalid_kv_dimension(name: &str, value: i64, mutate: fn(&mut model_io::ArchConfig)) {
let mut arch = model_io::gemma4_26b_a4b();
mutate(&mut arch);
let error = validate_arch_config(&arch).expect_err(name);
assert_eq!(
error.to_string(),
format!("unsupported: {name} must be positive, got {value}")
);
}
#[test]
fn negative_swa_kv_heads_are_refused_before_gpu_allocation() {
assert_invalid_kv_dimension("num_kv_heads", -4_294_967_294, |arch| {
arch.num_kv_heads = -4_294_967_294
});
}
#[test]
fn zero_full_kv_heads_are_refused_before_gpu_allocation() {
assert_invalid_kv_dimension("num_full_kv_heads", 0, |arch| arch.num_full_kv_heads = 0);
}
#[test]
fn zero_swa_head_dim_is_refused_before_gpu_allocation() {
assert_invalid_kv_dimension("head_dim", 0, |arch| arch.head_dim = 0);
}
#[test]
fn negative_full_head_dim_is_refused_before_gpu_allocation() {
assert_invalid_kv_dimension("full_head_dim", -1, |arch| arch.full_head_dim = -1);
}
#[test]
fn mapped_residency_is_served_on_gemma4_and_refused_by_name_everywhere_else() {
assert_eq!(
EVERY_FAMILY.len(),
ModelFamily::ALL.len(),
"a ModelFamily variant was added without deciding whether it serves \
mapped expert residency; add it to EVERY_FAMILY and to the dispatch \
site, or leave it refused deliberately"
);
for &family in EVERY_FAMILY {
match mapped_residency_refusal(family) {
Ok(()) => assert!(
matches!(
family,
ModelFamily::Gemma4
| ModelFamily::QwenGdnMoe
| ModelFamily::Llama
| ModelFamily::Qwen3Moe
| ModelFamily::GptOss
),
"{} accepts mapped residency but has no mapped arm at its \
dispatch site; a family that accepts it and does not serve it \
runs the streamed engine under the mapped label",
family.as_str()
),
Err(err) => {
assert_ne!(family, ModelFamily::Gemma4);
let text = err.to_string();
assert!(
text.contains("TURBOSPARK_EXPERT_RESIDENCY"),
"the refusal must name the seam; got {text}"
);
assert!(
text.contains(family.as_str()),
"the refusal must name the family it declined; got {text}"
);
}
}
}
}
#[test]
fn auto_residency_uses_memory_headroom_only_for_wired_families() {
let bytes_per_slot = 30 * 3_355_443;
assert_eq!(
resolve_expert_residency(
model_io::ExpertResidency::Auto,
16 * 1024 * 1024 * 1024,
13 * 1024 * 1024 * 1024,
bytes_per_slot,
true,
),
model_io::ResolvedExpertResidency::Mapped
);
assert_eq!(
resolve_expert_residency(
model_io::ExpertResidency::Auto,
16 * 1024 * 1024 * 1024,
13 * 1024 * 1024 * 1024,
bytes_per_slot,
false,
),
model_io::ResolvedExpertResidency::Streamed
);
assert_eq!(
resolve_expert_residency(
model_io::ExpertResidency::Streamed,
16 * 1024 * 1024 * 1024,
13 * 1024 * 1024 * 1024,
bytes_per_slot,
true,
),
model_io::ResolvedExpertResidency::Streamed
);
}
}