#![cfg(feature = "gpu")]
use std::path::PathBuf;
use cera::backend::wgpu::io_stats;
use cera::gguf::GgufFile;
use cera::kv_cache::InferenceState;
use cera::model::load_model_gpu;
const TOKENS: &[u32] = &[124894, 597, 5205, 302, 3980, 355, 20551];
const MAX_SUBMITS: u64 = 60;
fn model_path() -> Option<PathBuf> {
let p = std::env::var("CERA_LFM2MOE_MODEL")
.ok()
.map(PathBuf::from)?;
(p.exists() && GgufFile::open(&p).is_ok()).then_some(p)
}
#[test]
#[ignore = "needs an lfm2moe GGUF via CERA_LFM2MOE_MODEL"]
fn routed_prefill_submits_scale_with_chunks_not_tokens() {
let Some(path) = model_path() else {
eprintln!("[wgpu-moe-prefill] SKIP: set CERA_LFM2MOE_MODEL");
return;
};
let model = load_model_gpu(
GgufFile::open(&path).expect("model_path checked this opens"),
Some(&path),
4096,
)
.expect("lfm2moe loads on the wgpu backend");
assert!(
model.config().moe.is_some(),
"CERA_LFM2MOE_MODEL is not a mixture-of-experts model; this guard would pass vacuously"
);
let mut state = InferenceState::for_prefill(model.config(), TOKENS.len())
.expect("prefill state for a prompt this short");
io_stats::reset();
let logits = model.forward_prefill(TOKENS, 0, &mut state);
let stats = io_stats::snapshot();
assert_eq!(logits.len(), model.config().vocab_size);
eprintln!(
"[wgpu-moe-prefill] {} tokens in one chunk: {} submits, {} passes",
TOKENS.len(),
stats.submits,
stats.passes,
);
const MIN_SUBMITS: u64 = 5;
assert!(
stats.submits >= MIN_SUBMITS,
"routed prefill recorded only {} submits (floor {MIN_SUBMITS}); io_stats is not \
being fed, so the cap below would pass while measuring nothing",
stats.submits,
);
assert!(
stats.submits <= MAX_SUBMITS,
"routed prefill issued {} submits for {} tokens (cap {MAX_SUBMITS}); the batched path \
has bailed to the per-token decode loop, which would also make every assertion in \
wgpu_moe_oracle.rs pass vacuously",
stats.submits,
TOKENS.len(),
);
}