use crate::pipeline::{MoeFfn, MoeRoute};
use crate::pool::Pool;
#[cfg(feature = "gpu")]
use std::sync::{Arc, Mutex, Once, OnceLock};
#[derive(Default)]
pub(crate) struct MiniCpmTailCache;
pub(crate) type MiniCpmTail = MiniCpmTailCache;
#[cfg(feature = "gpu")]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct PoolKey {
model_uid: u64,
hidden: usize,
inter: usize,
experts: usize,
layers: usize,
gu_q2: bool,
minimax: bool,
}
#[cfg(feature = "gpu")]
const MINICPM_35B_TOTAL_LAYERS: usize = 40;
#[cfg(feature = "gpu")]
const MINICPM_35B_ACTIVE_TAIL_LAYERS: usize = 13;
#[cfg(feature = "gpu")]
fn active_tail_layers(total_layers: usize) -> Option<usize> {
(total_layers == MINICPM_35B_TOTAL_LAYERS).then_some(MINICPM_35B_ACTIVE_TAIL_LAYERS)
}
#[cfg(feature = "gpu")]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct TailBankKey {
model_uid: u64,
device: usize,
}
#[cfg(feature = "gpu")]
#[derive(Clone, Debug, Eq, PartialEq)]
struct LayerLayout {
expert_ids: Arc<[(usize, usize, usize)]>,
shared_ids: (usize, usize, usize),
}
#[cfg(feature = "gpu")]
struct SharedTailBank {
gpu_pool: crate::qwen4_exp::QwenGpuPool,
pool_key: PoolKey,
layouts: Vec<Option<LayerLayout>>,
}
#[cfg(feature = "gpu")]
impl SharedTailBank {
fn accepts_layout_or_resets(
&mut self,
model: &Arc<cortiq_core::CmfModel>,
key: PoolKey,
li: usize,
candidate: LayerLayout,
) -> bool {
if self.pool_key != key {
return false;
}
let Some(slot) = self.layouts.get_mut(li) else {
return false;
};
let same = match slot {
Some(existing) => existing == &candidate,
None => {
*slot = Some(candidate);
return true;
}
};
if same {
return true;
}
let Some(gpu_pool) = create_tail_gpu_pool(model, key) else {
return false;
};
let mut layouts: Vec<Option<LayerLayout>> = (0..key.layers).map(|_| None).collect();
layouts[li] = Some(candidate);
self.gpu_pool = gpu_pool;
self.layouts = layouts;
true
}
}
#[cfg(feature = "gpu")]
fn create_tail_gpu_pool(
model: &Arc<cortiq_core::CmfModel>,
key: PoolKey,
) -> Option<crate::qwen4_exp::QwenGpuPool> {
let slots = if key.minimax {
minimax_tail_slots(&key)?
} else {
bounded_slots()
};
let mut gpu_pool = crate::qwen4_exp::QwenGpuPool::create_explicit(
model,
key.inter,
key.hidden,
key.layers,
key.experts,
key.gu_q2,
slots,
0,
)?;
if let Some(active_layers) = active_tail_layers(key.layers) {
gpu_pool.configure_minicpm_tail(active_layers);
}
Some(gpu_pool)
}
#[cfg(feature = "gpu")]
fn minimax_tail_slots(key: &PoolKey) -> Option<usize> {
if let Some(v) = std::env::var("CMF_MINIMAX_TAIL_SLOTS")
.ok()
.and_then(|raw| raw.parse::<usize>().ok())
{
return (v >= 64).then_some(v.min(4096));
}
let codec = crate::gpu_wgpu::MoeBankCodec::from_gu_q2(key.gu_q2);
let (gu, dn) = codec.lens(key.inter, key.hidden)?;
let per = (2usize.checked_mul(gu)? + dn) as u64;
let budget = crate::gpu_wgpu::device_vram_budget();
let resident = crate::gpu_wgpu::resident_bytes();
let free = budget.saturating_sub(resident);
let slots = ((free.saturating_mul(55) / 100) / per.max(1)) as usize;
(slots >= 64).then_some(slots.min(4096))
}
#[cfg(feature = "gpu")]
type SharedTailBankRef = Arc<Mutex<SharedTailBank>>;
#[cfg(feature = "gpu")]
fn tail_banks() -> &'static Mutex<Vec<(TailBankKey, SharedTailBankRef)>> {
static BANKS: OnceLock<Mutex<Vec<(TailBankKey, SharedTailBankRef)>>> = OnceLock::new();
BANKS.get_or_init(|| Mutex::new(Vec::new()))
}
#[cfg(feature = "gpu")]
pub(crate) fn shutdown_banks() {
let Ok(mut registry) = tail_banks().lock() else {
return;
};
let banks = std::mem::take(&mut *registry);
drop(registry);
drop(banks);
}
#[cfg(feature = "gpu")]
pub(crate) fn release_model_bank(model_uid: u64) {
let Ok(mut registry) = tail_banks().lock() else {
return;
};
let mut retired = Vec::new();
registry.retain(|(key, bank)| {
if key.model_uid == model_uid {
retired.push(bank.clone());
false
} else {
true
}
});
drop(registry);
drop(retired);
}
#[cfg(feature = "gpu")]
fn acquire_tail_bank(
model: &Arc<cortiq_core::CmfModel>,
pool_key: PoolKey,
) -> Option<SharedTailBankRef> {
let registry_key = TailBankKey {
model_uid: pool_key.model_uid,
device: crate::gpu::current_device(),
};
let mut registry = tail_banks().lock().ok()?;
if let Some((_, bank)) = registry.iter().find(|(key, _)| *key == registry_key) {
return Some(bank.clone());
}
let gpu_pool = create_tail_gpu_pool(model, pool_key)?;
let bank = Arc::new(Mutex::new(SharedTailBank {
gpu_pool,
pool_key,
layouts: (0..pool_key.layers).map(|_| None).collect(),
}));
registry.push((registry_key, bank.clone()));
Some(bank)
}
#[cfg(feature = "gpu")]
fn dynamic_tail_precision_safe() -> bool {
if std::env::var("CMF_MINICPM_DYNAMIC_TAIL").as_deref() != Ok("1") {
return false;
}
if !crate::qtensor::a8w8_enabled() {
return true;
}
static WARN: Once = Once::new();
WARN.call_once(|| {
tracing::warn!(
"MiniCPM dynamic tail disabled: its float-activation DSV4 frame cannot replace the \
normal A8W8 CPU q4tp path without changing precision; use CMF_SDOT=0 together with \
CMF_MINICPM_DYNAMIC_TAIL=1 to opt into the parity-checked exact mode"
);
});
false
}
#[cfg(feature = "gpu")]
fn m3_tail_debug(msg: &str) {
if std::env::var_os("CMF_M3_TAIL_DEBUG").is_some() {
eprintln!("m3-tail decline: {msg}");
}
}
#[cfg(feature = "gpu")]
fn minimax_tail_enabled() -> bool {
std::env::var("CMF_MINIMAX_DYNAMIC_TAIL").as_deref() == Ok("1")
}
#[cfg(feature = "gpu")]
fn prepared_frame_on() -> bool {
std::env::var("CMF_MINICPM_PREPARED_FRAME").as_deref() != Ok("0")
&& std::env::var_os("CMF_DSV4_MOE_CHECK").is_none()
}
impl MiniCpmTailCache {
#[cfg(feature = "gpu")]
pub(crate) fn is_requested_target(m: &MoeFfn) -> bool {
let Some(model) = m
.experts
.first()
.and_then(|expert| expert.gate_proj.model_arc())
else {
return false;
};
match model.arch().arch_name.as_str() {
"minicpmv4_7" => dynamic_tail_precision_safe(),
"minimax_m3_vl" => {
let on = minimax_tail_enabled();
m3_tail_debug(&format!("is_requested_target minimax → {on}"));
on
}
other => {
m3_tail_debug(&format!("arch not a tail target: {other}"));
false
}
}
}
#[cfg(not(feature = "gpu"))]
pub(crate) fn is_requested_target(_m: &MoeFfn) -> bool {
false
}
#[cfg(feature = "gpu")]
pub(crate) fn forward(
&mut self,
li: usize,
m: &MoeFfn,
x: &[f32],
route: &MoeRoute,
pool: Option<&Pool>,
total_layers: usize,
) -> Option<Vec<f32>> {
if !Self::is_requested_target(m)
|| !crate::gpu_wgpu::dsv4_global_moe_supported()
|| li >= total_layers
|| x.is_empty()
|| m.route_tau.is_some()
|| m.mask.is_some()
|| m.per_expert_scale.is_some()
|| m.router_input_norm
|| m.resonance.is_some()
|| !m.grown.is_empty()
{
m3_tail_debug(&format!(
"outer gate: target={} supported={} li={li}/{total_layers} empty={} tau={} mask={} pscale={} rin={} res={} grown={} top_k={} sigmoid={} normtopk={} scaling={}",
Self::is_requested_target(m),
crate::gpu_wgpu::dsv4_global_moe_supported(),
x.is_empty(),
m.route_tau.is_some(),
m.mask.is_some(),
m.per_expert_scale.is_some(),
m.router_input_norm,
m.resonance.is_some(),
!m.grown.is_empty(),
m.top_k,
m.router_sigmoid,
m.norm_topk_prob,
m.routed_scaling,
));
return None;
}
let first = m.experts.first()?;
let model = first.gate_proj.model_arc()?;
let minimax = match model.arch().arch_name.as_str() {
"minicpmv4_7" => {
if m.top_k != 8
|| route.idx.len() != 8
|| m.router_sigmoid
|| !m.norm_topk_prob
|| (m.routed_scaling - 1.0).abs() > 1e-9
|| m.expert_bias.is_some()
{
return None;
}
false
}
"minimax_m3_vl" => {
if m.top_k != 4
|| route.idx.len() != 4
|| !m.router_sigmoid
|| !m.norm_topk_prob
{
return None;
}
true
}
_ => return None,
};
if std::env::var_os("CMF_M3_TAIL_DEBUG").is_some() {
eprintln!(
"m3-tail: arch={} minimax={minimax} top_k={} idx={} act={:?}",
model.arch().arch_name,
m.top_k,
route.idx.len(),
first.gate_proj.model_dtype()
);
}
if minimax && !prepared_frame_on() {
return None;
}
let hidden = x.len();
let inter = first.gate_proj.rows();
if hidden % 32 != 0 || inter == 0 || inter % 32 != 0 {
return None;
}
let gu_q2 = if minimax {
match first.gate_proj.model_dtype() {
Some(cortiq_core::TensorDtype::Q2TiledP) => true,
Some(cortiq_core::TensorDtype::Q4TiledP) => false,
_ => return None,
}
} else {
false
};
let triple = |expert: &crate::pipeline::DenseFfn| {
if minimax {
m3_triple(expert, &model, hidden, inter, gu_q2)
} else {
q4tp_triple(expert, &model, hidden, inter)
}
};
let expert_ids: Vec<_> = match m.experts.iter().map(triple).collect::<Option<Vec<_>>>() {
Some(ids) => ids,
None => {
m3_tail_debug("expert triple refused (act/dtype/geometry)");
return None;
}
};
let Some((shared, shared_gate)) = m.shared.as_ref() else {
m3_tail_debug("no shared expert");
return None;
};
let Some(shared_ids) = triple(shared) else {
m3_tail_debug("shared triple refused");
return None;
};
if let Some(gate) = shared_gate
&& (gate.rows() != 1 || gate.cols() != hidden)
{
return None;
}
let candidate = LayerLayout {
expert_ids: expert_ids.into(),
shared_ids,
};
if m.router.rows() != candidate.expert_ids.len()
|| m.router.cols() != hidden
|| route.logits.len() != candidate.expert_ids.len()
|| route.p.len() != candidate.expert_ids.len()
|| !route.wsum.is_finite()
|| route.wsum <= 0.0
|| route
.idx
.iter()
.any(|&expert| expert >= candidate.expert_ids.len())
|| route
.idx
.iter()
.enumerate()
.any(|(i, &expert)| route.idx[..i].contains(&expert))
{
return None;
}
let mut mix_weights = vec![0.0f32; candidate.expert_ids.len()];
for &expert in &route.idx {
let weight = route.p[expert] / route.wsum;
if !weight.is_finite() {
return None;
}
mix_weights[expert] = weight;
}
let shared_weight = shared_gate.as_ref().map_or(1.0, |gate| {
let mut y = [0.0f32; 1];
crate::gpu::cpu_scope(|| gate.matvec(x, &mut y, pool));
1.0 / (1.0 + (-y[0]).exp())
});
if !shared_weight.is_finite() {
return None;
}
let key = PoolKey {
model_uid: model.uid(),
hidden,
inter,
experts: candidate.expert_ids.len(),
layers: total_layers,
gu_q2,
minimax,
};
let shared = acquire_tail_bank(&model, key)?;
let mut bank = shared.lock().ok()?;
if !bank.accepts_layout_or_resets(&model, key, li, candidate) {
return None;
}
let (expert_ids, shared_ids) = {
let layout = bank.layouts.get(li)?.as_ref()?;
(layout.expert_ids.clone(), layout.shared_ids)
};
let Some(pending) = bank.gpu_pool.begin_ensure(
&model,
li,
&route.idx,
expert_ids.as_ref(),
Some(shared_ids),
) else {
bank.gpu_pool.flush_uploads();
return None;
};
let Some(planned_cold_ids) = pending.cold_ids() else {
drop(pending);
bank.gpu_pool.flush_uploads();
return None;
};
let planned_cold_jobs: Vec<_> = planned_cold_ids
.iter()
.copied()
.map(|expert| (&m.experts[expert], mix_weights[expert]))
.collect();
let geom = crate::gpu_wgpu::Dsv4MoeGeom {
hidden,
inter,
top_k: if minimax { 4 } else { 8 },
route_scale: 1.0,
swiglu_limit: if minimax { 7.0 } else { 0.0 },
gu_q2,
bf16: false,
};
let mut out = vec![0.0f32; hidden];
let prepared = prepared_frame_on();
let (frame_ok, route_ok, cpu_ok, mut cold_cpu) = std::thread::scope(|scope| {
let cpu = (!planned_cold_jobs.is_empty()).then(|| {
scope.spawn(|| {
crate::qtensor::float_activations_scope(|| {
crate::gpu::cpu_scope(|| {
crate::pipeline::moe_cold_experts_cpu(&planned_cold_jobs, x, pool)
})
})
})
});
let ensured = pending.finish_and_flush();
let Some((remap, shared_slot, segment_slots)) = ensured else {
if let Some(job) = cpu
&& let Ok(mut discarded) = job.join()
{
crate::attention::recycle_buf(&mut discarded);
}
return (
false,
false,
false,
crate::attention::take_buf(hidden),
);
};
if remap.len() != expert_ids.len() {
if let Some(job) = cpu
&& let Ok(mut discarded) = job.join()
{
crate::attention::recycle_buf(&mut discarded);
}
return (
false,
false,
false,
crate::attention::take_buf(hidden),
);
}
let cold_ids: Vec<_> = route
.idx
.iter()
.copied()
.filter(|&expert| remap[expert] == u32::MAX)
.collect();
if cold_ids != planned_cold_ids {
if let Some(job) = cpu
&& let Ok(mut discarded) = job.join()
{
crate::attention::recycle_buf(&mut discarded);
}
return (
false,
false,
false,
crate::attention::take_buf(hidden),
);
}
let mut resident_slots = Vec::with_capacity(route.idx.len() + 1);
let mut resident_weights = Vec::with_capacity(route.idx.len() + 1);
for &expert in &route.idx {
let slot = remap[expert];
if slot != u32::MAX {
resident_slots.push(slot);
resident_weights.push(mix_weights[expert]);
}
}
resident_slots.push(shared_slot);
resident_weights.push(shared_weight);
let global = crate::gpu_wgpu::Dsv4GlobalMoe {
pool_uid: model.uid(),
shared_slot,
segment_slots: segment_slots as u32,
};
let (frame_ok, route_ok) = if prepared {
(
crate::gpu_wgpu::minicpm_tail_prepared_frame(
&model,
global,
geom,
u32::from(minimax) * 3,
x,
&resident_slots,
&resident_weights,
&mut out,
),
true,
)
} else {
let mut cold_from_gpu = Vec::new();
let mut cold_x = Vec::new();
let weights = crate::gpu_wgpu::Dsv4MoeW {
router: &[],
experts: expert_ids.as_ref(),
logits: &route.logits,
bias: Some(&mix_weights),
mask: None,
forced: Some(&route.idx),
remap: Some(&remap),
global: Some(global),
has_shared: true,
shared_weight,
preweighted: true,
qwen_softmax: true,
};
let frame_ok = crate::gpu_wgpu::dsv4_moe_frame(
&model,
&weights,
geom,
x,
&mut cold_from_gpu,
&mut cold_x,
None,
None,
&mut out,
);
let route_ok = cold_from_gpu.len() == cold_ids.len()
&& cold_from_gpu
.iter()
.map(|&(expert, _)| expert)
.eq(cold_ids.iter().copied());
(frame_ok, route_ok)
};
let cpu_out = cpu.and_then(|job| job.join().ok());
let cpu_ok = planned_cold_jobs.is_empty() || cpu_out.is_some();
let cold_cpu = cpu_out.unwrap_or_else(|| crate::attention::take_buf(hidden));
(frame_ok, route_ok, cpu_ok, cold_cpu)
});
drop(bank);
if !frame_ok || !route_ok || !cpu_ok {
crate::attention::recycle_buf(&mut cold_cpu);
return None;
}
for (dst, src) in out.iter_mut().zip(&cold_cpu) {
*dst += src;
}
crate::attention::recycle_buf(&mut cold_cpu);
Some(out)
}
#[cfg(not(feature = "gpu"))]
pub(crate) fn forward(
&mut self,
_li: usize,
_m: &MoeFfn,
_x: &[f32],
_route: &MoeRoute,
_pool: Option<&Pool>,
_total_layers: usize,
) -> Option<Vec<f32>> {
None
}
}
#[cfg(feature = "gpu")]
fn q4tp_triple(
expert: &crate::pipeline::DenseFfn,
model: &std::sync::Arc<cortiq_core::CmfModel>,
hidden: usize,
inter: usize,
) -> Option<(usize, usize, usize)> {
use cortiq_core::TensorDtype;
if expert.act != crate::pipeline::Act::Silu || !expert.segs.is_empty() {
return None;
}
let mapped_q4tp = |tensor: &crate::qtensor::QTensor| {
tensor.model_dtype() == Some(TensorDtype::Q4TiledP)
&& tensor.model_arc().is_some_and(|owner| owner.uid() == model.uid())
};
if !mapped_q4tp(&expert.gate_proj)
|| !mapped_q4tp(&expert.up_proj)
|| !mapped_q4tp(&expert.down_proj)
|| expert.gate_proj.rows() != inter
|| expert.gate_proj.cols() != hidden
|| expert.up_proj.rows() != inter
|| expert.up_proj.cols() != hidden
|| expert.down_proj.rows() != hidden
|| expert.down_proj.cols() != inter
{
return None;
}
Some((
expert.gate_proj.model_idx()?,
expert.up_proj.model_idx()?,
expert.down_proj.model_idx()?,
))
}
#[cfg(feature = "gpu")]
fn m3_triple(
expert: &crate::pipeline::DenseFfn,
model: &std::sync::Arc<cortiq_core::CmfModel>,
hidden: usize,
inter: usize,
gu_q2: bool,
) -> Option<(usize, usize, usize)> {
use cortiq_core::TensorDtype;
match expert.act {
crate::pipeline::Act::SwiGluOai { alpha, limit }
if (alpha - 1.702).abs() < 1e-6 && (limit - 7.0).abs() < 1e-6 => {}
_ => return None,
}
if !expert.segs.is_empty() {
return None;
}
let gu_dt = if gu_q2 {
TensorDtype::Q2TiledP
} else {
TensorDtype::Q4TiledP
};
let mapped = |t: &crate::qtensor::QTensor, dt: TensorDtype| {
t.model_dtype() == Some(dt)
&& t.model_arc().is_some_and(|owner| owner.uid() == model.uid())
};
if !mapped(&expert.gate_proj, gu_dt)
|| !mapped(&expert.up_proj, gu_dt)
|| !mapped(&expert.down_proj, TensorDtype::Q4TiledP)
|| expert.gate_proj.rows() != inter
|| expert.gate_proj.cols() != hidden
|| expert.up_proj.rows() != inter
|| expert.up_proj.cols() != hidden
|| expert.down_proj.rows() != hidden
|| expert.down_proj.cols() != inter
{
return None;
}
Some((
expert.gate_proj.model_idx()?,
expert.up_proj.model_idx()?,
expert.down_proj.model_idx()?,
))
}
#[cfg(feature = "gpu")]
const LARGE_TAIL_BUDGET: u64 = 20 * 1024 * 1024 * 1024;
#[cfg(feature = "gpu")]
fn default_tail_slots(vram_budget: u64) -> usize {
if vram_budget >= LARGE_TAIL_BUDGET {
512
} else {
224
}
}
#[cfg(feature = "gpu")]
fn bounded_slots() -> usize {
std::env::var("CMF_MINICPM_TAIL_SLOTS")
.ok()
.and_then(|raw| raw.parse::<usize>().ok())
.unwrap_or_else(|| default_tail_slots(crate::gpu_wgpu::device_vram_budget()))
.clamp(16, 512)
}
#[cfg(feature = "gpu")]
fn minimax_pool_ctx(
m: &MoeFfn,
li: usize,
total_layers: usize,
) -> Option<(
std::sync::Arc<cortiq_core::CmfModel>,
PoolKey,
Vec<(usize, usize, usize)>,
(usize, usize, usize),
)> {
if !minimax_tail_enabled() || !crate::gpu_wgpu::dsv4_global_moe_supported() {
return None;
}
if li >= total_layers
|| m.top_k != 4
|| !m.router_sigmoid
|| !m.norm_topk_prob
|| m.route_tau.is_some()
|| m.mask.is_some()
|| m.per_expert_scale.is_some()
|| m.router_input_norm
|| m.resonance.is_some()
|| !m.grown.is_empty()
{
return None;
}
let first = m.experts.first()?;
let model = first.gate_proj.model_arc()?;
if model.arch().arch_name != "minimax_m3_vl" {
return None;
}
let hidden = m.router.cols();
let inter = first.gate_proj.rows();
if hidden % 32 != 0 || inter % 32 != 0 || m.router.rows() != m.experts.len() {
return None;
}
let gu_q2 = match first.gate_proj.model_dtype() {
Some(cortiq_core::TensorDtype::Q2TiledP) => true,
Some(cortiq_core::TensorDtype::Q4TiledP) => false,
_ => return None,
};
let expert_ids: Vec<(usize, usize, usize)> = m
.experts
.iter()
.map(|e| m3_triple(e, &model, hidden, inter, gu_q2))
.collect::<Option<_>>()?;
let (shared, shared_gate) = m.shared.as_ref()?;
if shared_gate.is_some() {
return None;
}
let shared_ids = m3_triple(shared, &model, hidden, inter, gu_q2)?;
let key = PoolKey {
model_uid: model.uid(),
hidden,
inter,
experts: expert_ids.len(),
layers: total_layers,
gu_q2,
minimax: true,
};
Some((model, key, expert_ids, shared_ids))
}
#[cfg(feature = "gpu")]
pub(crate) fn minimax_pool_arm(
m: &MoeFfn,
li: usize,
total_layers: usize,
predicted: &[u32],
) -> Option<crate::gpu_wgpu::PooledFrame> {
let (model, key, expert_ids, shared_ids) = minimax_pool_ctx(m, li, total_layers)?;
let shared = acquire_tail_bank(&model, key)?;
let mut bank = shared.lock().ok()?;
let candidate = LayerLayout {
expert_ids: expert_ids.clone().into(),
shared_ids,
};
if !bank.accepts_layout_or_resets(&model, key, li, candidate) {
return None;
}
let pred: Vec<usize> = predicted
.iter()
.map(|&e| e as usize)
.filter(|&e| e < key.experts)
.collect();
let pending = bank
.gpu_pool
.begin_ensure(&model, li, &pred, &expert_ids, Some(shared_ids))?;
let Some((remap, shared_slot, _)) = pending.finish_and_flush() else {
bank.gpu_pool.flush_uploads();
return None;
};
if remap.len() != expert_ids.len() {
return None;
}
Some(crate::gpu_wgpu::PooledFrame {
remap,
shared_slot,
pool_uid: model.uid(),
})
}
#[cfg(feature = "gpu")]
pub(crate) fn minimax_pool_ensure(m: &MoeFfn, li: usize, total_layers: usize, cold: &[usize]) -> bool {
if cold.is_empty() {
return true;
}
let (model, key, _, shared_ids) = match minimax_pool_ctx(m, li, total_layers) {
Some(v) => v,
None => return false,
};
if cold.iter().any(|&e| e >= key.experts) {
return false;
}
let Some(shared) = acquire_tail_bank(&model, key) else {
return false;
};
let Ok(mut bank) = shared.lock() else {
return false;
};
let (expert_ids, layout_shared) = {
let Some(layout) = bank.layouts.get(li).and_then(|l| l.as_ref()) else {
return false;
};
(layout.expert_ids.clone(), layout.shared_ids)
};
debug_assert_eq!(layout_shared, shared_ids);
let Some(pending) =
bank.gpu_pool
.begin_ensure(&model, li, cold, expert_ids.as_ref(), Some(layout_shared))
else {
bank.gpu_pool.flush_uploads();
return false;
};
pending.finish_and_flush().is_some()
}
#[cfg(feature = "gpu")]
pub(crate) fn minimax_cold_device(
m: &MoeFfn,
li: usize,
total_layers: usize,
cold: &[(usize, f32)],
x: &[f32],
out: &mut [f32],
) -> bool {
if cold.is_empty() || cold.len() > 4 || out.len() < x.len() {
return false;
}
let Some((model, key, expert_ids, shared_ids)) = minimax_pool_ctx(m, li, total_layers) else {
return false;
};
let Some(shared) = acquire_tail_bank(&model, key) else {
return false;
};
let Ok(mut bank) = shared.lock() else {
return false;
};
let candidate = LayerLayout {
expert_ids: expert_ids.clone().into(),
shared_ids,
};
if !bank.accepts_layout_or_resets(&model, key, li, candidate) {
return false;
}
let ids: Vec<usize> = cold.iter().map(|&(e, _)| e).collect();
let Some(pending) = bank
.gpu_pool
.begin_ensure(&model, li, &ids, &expert_ids, Some(shared_ids))
else {
bank.gpu_pool.flush_uploads();
return false;
};
let Some((remap, shared_slot, segment_slots)) = pending.finish_and_flush() else {
return false;
};
if remap.len() != expert_ids.len() {
return false;
}
let mut slots: Vec<u32> = Vec::with_capacity(cold.len() + 1);
let mut weights: Vec<f32> = Vec::with_capacity(cold.len() + 1);
for &(e, w) in cold {
let slot = match remap.get(e) {
Some(&s) if s != u32::MAX => s,
_ => return false,
};
slots.push(slot);
weights.push(w);
}
slots.push(shared_slot);
weights.push(0.0);
let hidden = x.len();
let Some(inter) = m.experts.first().map(|e| e.gate_proj.rows()) else {
return false;
};
let geom = crate::gpu_wgpu::Dsv4MoeGeom {
hidden,
inter,
top_k: 4,
route_scale: 1.0,
swiglu_limit: 7.0,
gu_q2: key.gu_q2,
bf16: false,
};
let global = crate::gpu_wgpu::Dsv4GlobalMoe {
pool_uid: model.uid(),
shared_slot,
segment_slots: segment_slots as u32,
};
drop(bank);
out[..hidden].fill(0.0);
crate::gpu_wgpu::minicpm_tail_prepared_frame(
&model,
global,
geom,
3,
x,
&slots,
&weights,
&mut out[..hidden],
)
}
#[cfg(not(feature = "gpu"))]
pub(crate) fn minimax_cold_device(
_m: &MoeFfn,
_li: usize,
_total_layers: usize,
_cold: &[(usize, f32)],
_x: &[f32],
_out: &mut [f32],
) -> bool {
false
}
#[cfg(not(feature = "gpu"))]
pub(crate) fn minimax_pool_arm(
_m: &MoeFfn,
_li: usize,
_total_layers: usize,
_predicted: &[u32],
) -> Option<()> {
None
}
#[cfg(not(feature = "gpu"))]
pub(crate) fn minimax_pool_ensure(
_m: &MoeFfn,
_li: usize,
_total_layers: usize,
_cold: &[usize],
) -> bool {
false
}
pub(crate) fn minimax_n_experts(layers: &[crate::pipeline::LayerWeights], from: usize) -> usize {
layers
.iter()
.skip(from)
.find_map(|lw| match &lw.ffn {
crate::pipeline::FfnKind::Moe(m) => Some(m.experts.len()),
_ => None,
})
.unwrap_or(0)
}
pub(crate) fn minimax_pool_on() -> bool {
#[cfg(feature = "gpu")]
{
minimax_tail_enabled()
}
#[cfg(not(feature = "gpu"))]
{
false
}
}
#[cfg(all(test, feature = "gpu"))]
mod tests {
use super::{
LARGE_TAIL_BUDGET, MINICPM_35B_ACTIVE_TAIL_LAYERS,
MINICPM_35B_TOTAL_LAYERS, active_tail_layers, default_tail_slots,
};
#[test]
fn tail_slot_policy_is_bounded_before_allocator_rounding() {
assert!((16..=512).contains(&default_tail_slots(0)));
}
#[test]
fn high_budget_default_expands_without_exceeding_tail_cap() {
assert_eq!(default_tail_slots(LARGE_TAIL_BUDGET - 1), 224);
assert_eq!(default_tail_slots(LARGE_TAIL_BUDGET), 512);
assert_eq!(default_tail_slots(u64::MAX), 512);
}
#[test]
fn active_floor_is_only_enabled_for_the_known_35b_tail_topology() {
assert_eq!(
active_tail_layers(MINICPM_35B_TOTAL_LAYERS),
Some(MINICPM_35B_ACTIVE_TAIL_LAYERS)
);
assert_eq!(active_tail_layers(24), None);
}
}