use std::time::Instant;
use crate::moe_prefill_pipeline::{encode_routes, next_routed_sub_batch};
use crate::real_forward::RealForwardRunner;
use crate::real_forward_dispatch::router_topk_gemma4;
use crate::real_forward_layout::RoutedBlobLayout;
use crate::real_forward_types::RealForwardError;
use crate::real_forward_utils::f16_slice_to_le_bytes;
use crate::resid_capture::encode_resid_capture;
use crate::steering::encode_steering;
impl RealForwardRunner {
#[allow(clippy::too_many_arguments)]
pub(crate) fn encode_gpt_oss_layer_routed_moe_batched(
&mut self,
layer: usize,
hidden: usize,
moe_inter: u32,
num_experts: usize,
top_k: usize,
m: usize,
) -> Result<gpu::CommittedPass, RealForwardError> {
let gpu_err = RealForwardError::Gpu;
let layout = self.routed_layouts[layer];
if layout.phase1 != RoutedBlobLayout::GgufMxfp4
|| layout.phase2 != RoutedBlobLayout::GgufMxfp4
{
return Err(RealForwardError::Unsupported(format!(
"batched routed prefill for this family is wired for MXFP4 blobs only; \
layer {layer} phase1 {:?} phase2 {:?}",
layout.phase1, layout.phase2
)));
}
if self.mapped.buffers.get(layer).is_some_and(Option::is_some) {
return Err(RealForwardError::Unsupported(format!(
"batched routed prefill (TURBOSPARK_ROUTED_BATCH) and mapped expert \
residency (TURBOSPARK_EXPERT_RESIDENCY=mapped) cannot be combined: this \
pair binds one buffer per CACHE SLOT and mapped residency has no slot \
cache (layer {layer}). Pick one"
)));
}
if self.slot_buffers[layer].len() > gpu::MAX_PREFILL_EXPERT_BINDINGS {
return Err(RealForwardError::Unsupported(format!(
"batched routed prefill needs slot indices below {}; this install has {} slots",
gpu::MAX_PREFILL_EXPERT_BINDINGS,
self.slot_buffers[layer].len()
)));
}
if self
.router_hist
.as_ref()
.is_some_and(crate::router_hist::RouterHistogram::pilot_enabled)
{
return Err(RealForwardError::Unsupported(format!(
"batched routed prefill (TURBOSPARK_ROUTED_BATCH) and the router pilot probe \
(TURBOSPARK_PILOT_PROBE) cannot be combined (layer {layer})"
)));
}
let t_router = Instant::now();
let router_logits = {
let state = self
.real_gpt_oss
.as_ref()
.expect("real gpt-oss state present");
gpu::read_f32_buffer_at(&state.router_logits_f32, 0, m * num_experts)
};
let mut selected_all = Vec::with_capacity(m);
let mut weights_all = Vec::with_capacity(m);
for t in 0..m {
let state = self
.real_gpt_oss
.as_ref()
.expect("real gpt-oss state present");
let mut row = router_logits[t * num_experts..(t + 1) * num_experts].to_vec();
for (logit, bias) in row.iter_mut().zip(&state.router_bias[layer]) {
*logit += bias;
}
let (selected, route_weights) = router_topk_gemma4(&row, top_k, &state.per_expert_ones);
if let Some(hist) = self.router_hist.as_mut() {
hist.record(layer, &selected);
}
selected_all.push(selected);
weights_all.push(route_weights);
}
self.phases.router_nanos += t_router.elapsed().as_nanos() as u64;
let blob_refs: Vec<(gpu::MetalBuffer, u64)> = self.slot_buffers[layer]
.iter()
.map(|b| (b.clone(), 0u64))
.collect();
let wide = self
.real_gpt_oss
.as_ref()
.expect("real gpt-oss state present")
.batched()
.wide_blobs
.clone();
let t_bind = Instant::now();
let bind_refs: Vec<(&gpu::MetalBuffer, u64)> =
blob_refs.iter().map(|(b, o)| (b, *o)).collect();
gpu::bind_routed_blobs_wide_mxfp4(&wide, &mut self.context, &bind_refs).map_err(gpu_err)?;
self.phases.bind_nanos += t_bind.elapsed().as_nanos() as u64;
let cap = self
.expert_cache_slots
.min(gpu::MAX_PREFILL_EXPERT_BINDINGS);
let moe_inter_us = moe_inter as usize;
let mut committed: Option<gpu::CommittedPass> = None;
let mut sub_start = 0usize;
while sub_start < m {
self.retire_routed(&mut committed);
let sub = next_routed_sub_batch(&selected_all, sub_start, cap, layer, top_k)?;
let slot_of = self.plan_routed_union(layer, "gpt-oss", &sub.union)?;
let (routes, routing16) =
encode_routes(&selected_all, &weights_all, &sub, &slot_of, top_k);
let sub_len = sub.sub_len;
let state = self
.real_gpt_oss
.as_ref()
.expect("real gpt-oss state present");
let x_off = (sub_start * hidden * 2) as u64;
let acts_off = (sub_start * top_k * moe_inter_us * 2) as u64;
let rw_off = (sub_start * top_k * 2) as u64;
let routes_off = (sub_start * top_k * gpu::MoePrefillRoute::STRIDE_BYTES) as u64;
gpu::write_buffer_bytes(
&state.batched().batch_routing_w,
rw_off as usize,
&f16_slice_to_le_bytes(&routing16),
);
gpu::write_buffer_bytes(
&state.batched().batch_routes,
routes_off as usize,
&gpu::MoePrefillRoute::bytes(&routes),
);
let offsets = &self.moe_offsets[layer];
let pass = self
.context
.begin_pass_labeled("gpt-oss routed cb (batched)");
for (blob, _) in &blob_refs {
pass.use_read_buffer(blob);
}
gpu::encode_moe_prefill_phase1_mxfp4(
&mut self.context,
&pass,
&wide,
offsets,
(&state.moe_x, x_off),
(&state.batched().batch_acts, acts_off),
(&state.batched().batch_routes, routes_off),
hidden as u32,
moe_inter,
top_k as u32,
(sub_len * top_k) as u32,
gpu::Mxfp4Activation {
has_bias: offsets.gate_b != 0,
..gpu::Mxfp4Activation::GPT_OSS
},
)
.map_err(gpu_err)?;
gpu::encode_moe_prefill_phase2_fused_mxfp4(
&mut self.context,
&pass,
&wide,
offsets,
(&state.batched().batch_acts, acts_off),
(&state.batched().batch_routing_w, rw_off),
(&state.batched().batch_routes, routes_off),
(&state.batched().batch_zero, x_off),
(&state.batched().batch_y, x_off),
hidden as u32,
moe_inter,
top_k as u32,
sub_len as u32,
offsets.down_b != 0,
)
.map_err(gpu_err)?;
for i in 0..sub_len {
let row_off = x_off + (i * hidden * 2) as u64;
let x_row = ((sub_start + i) * hidden * 2) as u64;
gpu::encode_residual_add(
&mut self.context,
&pass,
(&self.scratch.x, x_row),
(&state.batched().batch_y, row_off),
hidden as u32,
)
.map_err(gpu_err)?;
encode_steering(
&mut self.context,
&pass,
&self.scratch,
self.steering.as_ref(),
layer,
hidden,
1,
x_row,
)?;
encode_resid_capture(
&mut self.context,
&pass,
&self.scratch,
self.resid_capture.as_ref(),
layer,
hidden,
x_row,
)?;
}
sub_start += sub_len;
committed = Some(pass.commit());
}
Ok(committed.expect("m >= 1 guarantees at least one sub-batch"))
}
}