use anyhow::{Result, bail};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TensorEntry {
pub name: String,
pub dims: Vec<usize>,
pub bytes: u64,
}
impl TensorEntry {
pub fn new(name: impl Into<String>, dims: Vec<usize>, bytes: u64) -> Self {
Self {
name: name.into(),
dims,
bytes,
}
}
pub fn elements(&self) -> u64 {
self.dims.iter().product::<usize>() as u64
}
}
#[derive(Debug, Clone)]
pub struct CostOptions {
pub block_prefixes: Markers,
pub expert_markers: Markers,
pub embed_markers: Markers,
pub head_markers: Markers,
pub expert_active_fraction: f64,
pub per_layer_flops: f64,
pub kv: KvMarkers,
pub kv_dtype: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Markers(Vec<String>);
impl Markers {
pub fn new<I, S>(names: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
Self(names.into_iter().map(Into::into).collect())
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn names(&self) -> &[String] {
&self.0
}
pub fn matches(&self, name: &str) -> bool {
self.0.iter().any(|p| name.contains(p.as_str()))
}
pub fn find_in<'a>(&self, ts: &[&'a TensorEntry]) -> Option<&'a TensorEntry> {
ts.iter().copied().find(|t| self.matches(&t.name))
}
pub fn any_in(&self, ts: &[&TensorEntry]) -> bool {
ts.iter().any(|t| self.matches(&t.name))
}
pub fn rank1_len(&self, t: &TensorEntry) -> Option<usize> {
match t.dims.as_slice() {
[n] if self.matches(&t.name) => Some(*n),
_ => None,
}
}
}
impl<S: Into<String>> FromIterator<S> for Markers {
fn from_iter<I: IntoIterator<Item = S>>(iter: I) -> Self {
Self::new(iter)
}
}
#[derive(Debug, Clone)]
pub struct KvMarkers {
pub hidden_probe: Markers,
pub recurrent: Markers,
pub recurrent_heads: Markers,
pub recurrent_head_dim: Markers,
pub latent_kv: Markers,
pub attn_k: Markers,
}
impl Default for KvMarkers {
fn default() -> Self {
Self {
hidden_probe: Markers::new(["attn_norm.weight", "input_layernorm.weight"]),
recurrent: Markers::new(["ssm_", ".mamba", "conv1d"]),
recurrent_heads: Markers::new(["ssm_a", "A_log"]),
recurrent_head_dim: Markers::new(["ssm_norm.weight", "o_norm.weight"]),
latent_kv: Markers::new(["attn_kv_a_mqa", "kv_a_proj_with_mqa"]),
attn_k: Markers::new(["attn_k.weight", "k_proj.weight"]),
}
}
}
impl Default for CostOptions {
fn default() -> Self {
Self {
block_prefixes: Markers::new(["blk.", "model.layers.", "layers."]),
expert_markers: Markers::new(["_exps", ".experts."]),
embed_markers: Markers::new(["token_embd", "embed_tokens", "word_embeddings"]),
head_markers: Markers::new(["output.weight", "output_norm", "lm_head", "model.norm"]),
expert_active_fraction: 1.0,
per_layer_flops: 1.0,
kv: KvMarkers::default(),
kv_dtype: "f32".into(),
}
}
}
impl CostOptions {
pub fn with_experts(mut self, experts_per_tok: usize, n_routed: usize) -> Self {
if n_routed > 0 {
self.expert_active_fraction = experts_per_tok as f64 / n_routed as f64;
}
self
}
fn block_of(&self, name: &str) -> Option<usize> {
for p in self.block_prefixes.names() {
if let Some(rest) = name.strip_prefix(p.as_str())
&& let Some(idx) = rest.split('.').next()
&& let Ok(i) = idx.parse::<usize>()
{
return Some(i);
}
}
None
}
fn is_expert(&self, name: &str) -> bool {
self.expert_markers.matches(name)
}
}
pub fn kv_elem_bytes(dtype: &str) -> u64 {
match dtype {
"f16" | "bf16" | "half" => 2,
"f8" | "fp8" | "int8" | "i8" => 1,
_ => 4,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlockKv {
Recurrent { state_bytes: u64 },
Latent { bytes_per_token: u64 },
Attention { bytes_per_token: u64 },
}
impl BlockKv {
pub fn bytes_per_token(&self) -> u64 {
match *self {
Self::Recurrent { .. } => 0,
Self::Latent { bytes_per_token } | Self::Attention { bytes_per_token } => {
bytes_per_token
}
}
}
pub fn state_bytes(&self) -> u64 {
match *self {
Self::Recurrent { state_bytes } => state_bytes,
_ => 0,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KvDetail {
PerBlock(Vec<BlockKv>),
Flat { bytes_per_layer_token: u64 },
}
impl Default for KvDetail {
fn default() -> Self {
Self::Flat {
bytes_per_layer_token: 0,
}
}
}
fn infer_hidden(entries: &[TensorEntry], opts: &CostOptions) -> usize {
entries
.iter()
.filter(|t| opts.block_of(&t.name).is_some())
.filter_map(|t| opts.kv.hidden_probe.rank1_len(t))
.max()
.unwrap_or(0)
}
fn classify_block(ts: &[&TensorEntry], m: &KvMarkers, elem: u64) -> Option<BlockKv> {
let hidden = ts.iter().find_map(|t| m.hidden_probe.rank1_len(t));
let out_of = |t: &TensorEntry| -> Option<usize> {
let h = hidden?;
match t.dims.as_slice() {
[a, b] if *a == h && *b != h => Some(*b),
[a, b] if *b == h && *a != h => Some(*a),
_ => None,
}
};
if m.recurrent.any_in(ts) {
let heads = ts.iter().find_map(|t| m.recurrent_heads.rank1_len(t))?;
let head_dim = ts.iter().find_map(|t| m.recurrent_head_dim.rank1_len(t))?;
return Some(BlockKv::Recurrent {
state_bytes: (heads * head_dim * head_dim) as u64 * elem,
});
}
if let Some(t) = m.latent_kv.find_in(ts) {
return Some(BlockKv::Latent {
bytes_per_token: out_of(t)? as u64 * elem,
});
}
if let Some(t) = m.attn_k.find_in(ts) {
return Some(BlockKv::Attention {
bytes_per_token: 2 * out_of(t)? as u64 * elem,
});
}
None
}
fn infer_kv(entries: &[TensorEntry], opts: &CostOptions) -> KvProfile {
use std::collections::BTreeMap;
let elem = kv_elem_bytes(&opts.kv_dtype);
let mut blocks: BTreeMap<usize, Vec<&TensorEntry>> = BTreeMap::new();
for t in entries {
if let Some(i) = opts.block_of(&t.name) {
blocks.entry(i).or_default().push(t);
}
}
if blocks.is_empty() {
return KvProfile::unknown();
}
match blocks
.values()
.map(|ts| classify_block(ts, &opts.kv, elem))
.collect::<Option<Vec<_>>>()
{
Some(per_block) => KvProfile::inferred(per_block),
None => KvProfile::unknown(),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum KvSource {
Inferred,
Declared,
#[default]
Unknown,
}
#[derive(Debug, Clone, Default)]
pub struct KvProfile {
detail: KvDetail,
source: KvSource,
}
impl KvProfile {
pub fn declared(bytes_per_layer_token: u64) -> Self {
Self {
detail: KvDetail::Flat {
bytes_per_layer_token,
},
source: KvSource::Declared,
}
}
pub fn inferred(blocks: Vec<BlockKv>) -> Self {
Self {
detail: KvDetail::PerBlock(blocks),
source: KvSource::Inferred,
}
}
pub fn unknown() -> Self {
Self::default()
}
pub fn source(&self) -> KvSource {
self.source
}
pub fn is_known(&self) -> bool {
self.source != KvSource::Unknown
}
pub fn blocks(&self) -> &[BlockKv] {
match &self.detail {
KvDetail::PerBlock(b) => b,
KvDetail::Flat { .. } => &[],
}
}
pub fn bytes_per_layer_token(&self) -> u64 {
match &self.detail {
KvDetail::Flat {
bytes_per_layer_token,
} => *bytes_per_layer_token,
KvDetail::PerBlock(b) if !b.is_empty() => {
b.iter().map(BlockKv::bytes_per_token).sum::<u64>() / b.len() as u64
}
KvDetail::PerBlock(_) => 0,
}
}
pub fn state_bytes_per_layer(&self) -> u64 {
match &self.detail {
KvDetail::Flat { .. } => 0,
KvDetail::PerBlock(b) if !b.is_empty() => {
b.iter().map(BlockKv::state_bytes).sum::<u64>() / b.len() as u64
}
KvDetail::PerBlock(_) => 0,
}
}
pub fn bytes(&self, layers: u64, context: usize) -> u64 {
self.bytes_per_layer_token()
.saturating_mul(layers)
.saturating_mul(context as u64)
.saturating_add(self.state_bytes_per_layer().saturating_mul(layers))
}
pub fn bytes_for(&self, layers: std::ops::Range<usize>, context: usize) -> u64 {
let b = self.blocks();
if b.is_empty() {
return self.bytes(layers.len() as u64, context);
}
let hi = layers.end.min(b.len());
let lo = layers.start.min(hi);
window_bytes(&b[lo..hi], context)
}
pub fn max_window_bytes(&self, len: usize, context: usize) -> u64 {
let b = self.blocks();
if b.is_empty() || len == 0 {
return self.bytes(len as u64, context);
}
b.windows(len.min(b.len()))
.map(|w| window_bytes(w, context))
.max()
.unwrap_or(0)
}
pub fn summary(&self, layers: u64, context: usize) -> String {
let Some(kind) = (match self.source {
KvSource::Unknown => None,
KvSource::Inferred => Some("inferred"),
KvSource::Declared => Some("declared"),
}) else {
return "KV: unknown".into();
};
let state = self.state_bytes_per_layer() * layers;
format!(
"KV: {:.2} GB for {layers} layers @ {context} tokens ({kind}{})",
self.bytes(layers, context) as f64 / 1e9,
if state > 0 {
format!(", + {:.2} GB recurrent state", state as f64 / 1e9)
} else {
String::new()
},
)
}
}
fn window_bytes(blocks: &[BlockKv], context: usize) -> u64 {
let per_token: u64 = blocks.iter().map(BlockKv::bytes_per_token).sum();
let state: u64 = blocks.iter().map(BlockKv::state_bytes).sum();
per_token
.saturating_mul(context as u64)
.saturating_add(state)
}
#[derive(Debug, Clone, Default)]
pub struct ModelCost {
pub n_layers: usize,
pub per_layer_bytes: u64,
pub per_layer_expert_bytes: u64,
pub per_layer_expert_active_bytes: u64,
pub embed_bytes: u64,
pub head_bytes: u64,
pub per_layer_flops: f64,
pub kv: KvProfile,
pub params: u64,
pub hidden_size: usize,
}
struct Width {
bytes: u64,
bits_per_param: f64,
}
impl Width {
fn of(bytes: u64, total_bytes: u64, total_elems: u64) -> Self {
let bits_per_param = if total_elems > 0 {
total_bytes as f64 * 8.0 / total_elems as f64
} else {
0.0
};
Self {
bytes,
bits_per_param,
}
}
fn params(&self) -> f64 {
if self.bits_per_param > 0.0 {
self.bytes as f64 * 8.0 / self.bits_per_param
} else {
0.0
}
}
}
fn decode_flops_per_layer(dense: Width, active_experts: Width) -> f64 {
2.0 * (dense.params() + active_experts.params())
}
impl ModelCost {
pub fn at_bits(&self, target_bits: f64) -> Option<Self> {
if self.params == 0 || target_bits <= 0.0 {
return None;
}
let cur = self.total_bytes() as f64 * 8.0 / self.params as f64;
if cur <= 0.0 {
return None;
}
let r = target_bits / cur;
let sc = |b: u64| (b as f64 * r) as u64;
Some(Self {
per_layer_bytes: sc(self.per_layer_bytes),
per_layer_expert_bytes: sc(self.per_layer_expert_bytes),
per_layer_expert_active_bytes: sc(self.per_layer_expert_active_bytes),
embed_bytes: sc(self.embed_bytes),
head_bytes: sc(self.head_bytes),
..self.clone()
})
}
pub fn kv_bytes(&self, layers: u64, context: usize) -> u64 {
self.kv.bytes(layers, context)
}
pub fn total_bytes(&self) -> u64 {
self.embed_bytes
+ self.head_bytes
+ (self.per_layer_bytes + self.per_layer_expert_bytes) * self.n_layers as u64
}
pub fn total_resident_bytes(&self) -> u64 {
self.embed_bytes + self.head_bytes + self.per_layer_bytes * self.n_layers as u64
}
pub fn is_expert_dominated(&self) -> bool {
self.per_layer_expert_bytes > self.per_layer_bytes
}
pub fn from_tensor_index(entries: &[TensorEntry], opts: &CostOptions) -> Result<Self> {
if entries.is_empty() {
bail!("empty tensor index");
}
let mut max_block: Option<usize> = None;
let (mut layer_bytes, mut expert_bytes) = (0u64, 0u64);
let (mut layer_elems, mut expert_elems) = (0u64, 0u64);
let (mut embed, mut head) = (0u64, 0u64);
for t in entries {
match opts.block_of(&t.name) {
Some(i) => {
max_block = Some(max_block.map_or(i, |m: usize| m.max(i)));
if opts.is_expert(&t.name) {
expert_bytes += t.bytes;
expert_elems += t.elements();
} else {
layer_bytes += t.bytes;
layer_elems += t.elements();
}
}
None => {
if opts.embed_markers.matches(&t.name) {
embed += t.bytes;
} else if opts.head_markers.matches(&t.name) {
head += t.bytes;
}
}
}
}
let n_layers = max_block.map(|m| m + 1).unwrap_or(0);
if n_layers == 0 {
bail!(
"no numbered blocks found — checked prefixes {:?}; pass CostOptions \
with the checkpoint's naming convention",
opts.block_prefixes
);
}
let n = n_layers as u64;
let per_layer_expert_bytes = expert_bytes / n;
let per_layer_bytes = layer_bytes / n;
let per_layer_expert_active_bytes =
(per_layer_expert_bytes as f64 * opts.expert_active_fraction.clamp(0.0, 1.0)) as u64;
let params: u64 = entries.iter().map(|t| t.elements()).sum();
Ok(Self {
n_layers,
per_layer_bytes,
per_layer_expert_bytes,
per_layer_expert_active_bytes,
embed_bytes: embed,
head_bytes: head,
per_layer_flops: decode_flops_per_layer(
Width::of(per_layer_bytes, layer_bytes, layer_elems),
Width::of(per_layer_expert_active_bytes, expert_bytes, expert_elems),
) * opts.per_layer_flops,
hidden_size: infer_hidden(entries, opts),
kv: infer_kv(entries, opts),
params,
})
}
pub fn summary(&self) -> String {
let gb = |b: u64| b as f64 / 1e9;
if self.per_layer_expert_bytes > 0 {
format!(
"{} layers | {:.2} GB resident + {:.2} GB experts = {:.2} GB \
| per layer {:.2} GB + {:.2} GB experts ({:.2} GB active)",
self.n_layers,
gb(self.total_resident_bytes()),
gb(self.per_layer_expert_bytes * self.n_layers as u64),
gb(self.total_bytes()),
gb(self.per_layer_bytes),
gb(self.per_layer_expert_bytes),
gb(self.per_layer_expert_active_bytes),
)
} else {
format!(
"{} layers | {:.2} GB | per layer {:.2} GB",
self.n_layers,
gb(self.total_bytes()),
gb(self.per_layer_bytes),
)
}
}
}
#[cfg(feature = "gguf")]
mod from_gguf {
use super::*;
use std::path::Path;
pub fn tensor_index(path: impl AsRef<Path>) -> Result<Vec<TensorEntry>> {
tensor_index_multi(std::slice::from_ref(&path.as_ref().to_path_buf()))
}
pub fn tensor_index_multi(paths: &[std::path::PathBuf]) -> Result<Vec<TensorEntry>> {
let mut out = Vec::new();
for p in paths {
let f = rlx_gguf::GgufFile::from_path(p)?;
for t in f.tensors.values() {
let bytes =
rlx_gguf::bytes_for_public(t.dtype, t.n_elements()).ok_or_else(|| {
anyhow::anyhow!("{}: unsupported ggml type {:?}", t.name, t.dtype)
})? as u64;
out.push(TensorEntry::new(t.name.clone(), t.shape.clone(), bytes));
}
}
Ok(out)
}
impl ModelCost {
pub fn from_gguf(paths: &[std::path::PathBuf], opts: &CostOptions) -> Result<Self> {
Self::from_tensor_index(&tensor_index_multi(paths)?, opts)
}
}
}
#[cfg(feature = "gguf")]
pub use from_gguf::{tensor_index, tensor_index_multi};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn per_layer_flops_is_a_real_decode_flop_count() {
let idx = moe_index();
let opts = CostOptions {
expert_active_fraction: 8.0 / 288.0,
..Default::default()
};
let c = ModelCost::from_tensor_index(&idx, &opts).unwrap();
let dense_elems: u64 = idx
.iter()
.filter(|t| opts.block_of(&t.name).is_some() && !opts.is_expert(&t.name))
.map(|t| t.elements())
.sum();
let expert_elems: u64 = idx
.iter()
.filter(|t| opts.block_of(&t.name).is_some() && opts.is_expert(&t.name))
.map(|t| t.elements())
.sum();
let active = dense_elems as f64 + expert_elems as f64 * opts.expert_active_fraction;
let want = 2.0 * active;
let got = c.per_layer_flops * c.n_layers as f64;
assert!(
(got - want).abs() <= want * 0.02,
"stack FLOPs/token {got:.3e} against 2 x active params {want:.3e}"
);
assert!(
c.per_layer_flops > 1.0,
"still the dimensionless placeholder: {}",
c.per_layer_flops
);
}
#[test]
fn mixed_precision_groups_use_their_own_bit_width() {
let mut idx = moe_index();
for t in &mut idx {
if t.name.contains("_exps") {
t.bytes /= 4;
}
}
let opts = CostOptions {
expert_active_fraction: 8.0 / 288.0,
..Default::default()
};
let c = ModelCost::from_tensor_index(&idx, &opts).unwrap();
let dense_elems: u64 = idx
.iter()
.filter(|t| opts.block_of(&t.name).is_some() && !opts.is_expert(&t.name))
.map(|t| t.elements())
.sum();
let expert_elems: u64 = idx
.iter()
.filter(|t| opts.block_of(&t.name).is_some() && opts.is_expert(&t.name))
.map(|t| t.elements())
.sum();
let want = 2.0 * (dense_elems as f64 + expert_elems as f64 * opts.expert_active_fraction);
let got = c.per_layer_flops * c.n_layers as f64;
assert!(
(got - want).abs() <= want * 0.02,
"re-quantizing the experts moved the FLOP count to {got:.3e} from \
{want:.3e}; a single average width was used for both groups"
);
}
fn moe_index() -> Vec<TensorEntry> {
let mut v = vec![
TensorEntry::new("token_embd.weight", vec![4096, 154880], 357_000_000),
TensorEntry::new("output.weight", vec![4096, 154880], 357_000_000),
TensorEntry::new("output_norm.weight", vec![4096], 16_384),
];
for i in 0..4 {
v.push(TensorEntry::new(
format!("blk.{i}.attn_q.weight"),
vec![4096, 8192],
23_000_000,
));
v.push(TensorEntry::new(
format!("blk.{i}.attn_norm.weight"),
vec![4096],
16_384,
));
if i >= 1 {
for b in ["ffn_gate_exps", "ffn_up_exps", "ffn_down_exps"] {
v.push(TensorEntry::new(
format!("blk.{i}.{b}.weight"),
vec![288, 2048, 4096],
600_000_000,
));
}
}
}
v
}
#[test]
fn derives_layers_and_splits_experts_from_dense() {
let opts = CostOptions::default().with_experts(8, 288);
let c = ModelCost::from_tensor_index(&moe_index(), &opts).unwrap();
assert_eq!(c.n_layers, 4);
assert_eq!(c.embed_bytes, 357_000_000);
assert_eq!(c.head_bytes, 357_000_000 + 16_384);
assert_eq!(c.per_layer_bytes, 23_016_384);
assert_eq!(c.per_layer_expert_bytes, 3 * 3 * 600_000_000 / 4);
assert!(c.is_expert_dominated());
}
#[test]
fn active_expert_bytes_track_the_router() {
let all = CostOptions::default();
let sparse = CostOptions::default().with_experts(8, 288);
let idx = moe_index();
let a = ModelCost::from_tensor_index(&idx, &all).unwrap();
let s = ModelCost::from_tensor_index(&idx, &sparse).unwrap();
assert_eq!(a.per_layer_expert_active_bytes, a.per_layer_expert_bytes);
assert!(s.per_layer_expert_active_bytes * 30 < s.per_layer_expert_bytes);
assert_eq!(s.per_layer_expert_bytes, a.per_layer_expert_bytes);
}
#[test]
fn rank_three_non_expert_tensors_stay_resident() {
let idx = vec![
TensorEntry::new("blk.0.attn_k_b.weight", vec![64, 512, 256], 9_000_000),
TensorEntry::new("blk.0.attn_norm.weight", vec![4096], 16_384),
];
let c = ModelCost::from_tensor_index(&idx, &CostOptions::default()).unwrap();
assert_eq!(c.per_layer_expert_bytes, 0);
assert_eq!(c.per_layer_bytes, 9_016_384);
assert!(!c.is_expert_dominated());
}
#[test]
fn hf_naming_works_too() {
let idx = vec![
TensorEntry::new("model.embed_tokens.weight", vec![32, 8], 1024),
TensorEntry::new("model.layers.0.self_attn.q_proj.weight", vec![8, 8], 256),
TensorEntry::new("model.layers.1.self_attn.q_proj.weight", vec![8, 8], 256),
TensorEntry::new("model.layers.1.mlp.experts.0.up.weight", vec![8, 8], 4096),
TensorEntry::new("lm_head.weight", vec![32, 8], 1024),
];
let c = ModelCost::from_tensor_index(&idx, &CostOptions::default()).unwrap();
assert_eq!(c.n_layers, 2);
assert_eq!(c.embed_bytes, 1024);
assert_eq!(c.head_bytes, 1024);
assert_eq!(c.per_layer_expert_bytes, 2048);
}
#[test]
fn at_bits_scales_weights_only() {
let idx = moe_index();
let mut c = ModelCost::from_tensor_index(&idx, &CostOptions::default()).unwrap();
c.kv = KvProfile::declared(4096);
let before = c.total_bytes();
let half = c
.at_bits(c.total_bytes() as f64 * 8.0 / c.params as f64 / 2.0)
.unwrap();
assert!(
(half.total_bytes() as f64 - before as f64 / 2.0).abs() < before as f64 * 0.01,
"halving the width should roughly halve the bytes"
);
assert_eq!(half.n_layers, c.n_layers);
assert_eq!(
half.kv.bytes_per_layer_token(),
c.kv.bytes_per_layer_token()
);
}
#[test]
fn at_bits_is_none_without_a_parameter_count() {
let c = ModelCost {
params: 0,
..Default::default()
};
assert!(c.at_bits(4.0).is_none());
}
#[test]
fn kv_bytes_scale_with_layers_and_context() {
let c = ModelCost {
kv: KvProfile::declared(1024),
..Default::default()
};
assert_eq!(c.kv_bytes(4, 100), 4 * 100 * 1024);
assert_eq!(c.kv_bytes(0, 100), 0);
}
fn hybrid_index() -> Vec<TensorEntry> {
let (hidden, kv_lora, heads, head_dim) = (4096usize, 512usize, 64usize, 128usize);
let mut v = Vec::new();
for i in 0..45 {
v.push(TensorEntry::new(
format!("blk.{i}.attn_norm.weight"),
vec![hidden],
hidden as u64 * 4,
));
if i % 4 == 3 {
v.push(TensorEntry::new(
format!("blk.{i}.attn_kv_a_mqa.weight"),
vec![hidden, kv_lora],
1,
));
} else {
v.push(TensorEntry::new(format!("blk.{i}.ssm_a"), vec![heads], 1));
v.push(TensorEntry::new(
format!("blk.{i}.ssm_norm.weight"),
vec![head_dim],
1,
));
}
}
v
}
#[test]
fn infers_hybrid_recurrent_plus_latent_attention() {
let c = ModelCost::from_tensor_index(&hybrid_index(), &CostOptions::default()).unwrap();
assert_eq!(c.kv.source(), KvSource::Inferred);
assert_eq!(c.kv.bytes_per_layer_token(), 11 * 512 * 4 / 45);
assert_eq!(c.kv.state_bytes_per_layer(), 34 * 64 * 128 * 128 * 4 / 45);
let total = c.kv.bytes(45, 131_072);
assert!(
(total as f64 / 1e9 - 3.09).abs() < 0.05,
"expected ~3.09 GB, got {:.2} GB",
total as f64 / 1e9
);
}
#[test]
fn infers_gqa_attention_as_two_times_k_width() {
let (hidden, kv_width) = (4096usize, 1024usize);
let idx = vec![
TensorEntry::new("blk.0.attn_norm.weight", vec![hidden], 1),
TensorEntry::new("blk.0.attn_k.weight", vec![kv_width, hidden], 1),
];
let c = ModelCost::from_tensor_index(&idx, &CostOptions::default()).unwrap();
assert_eq!(c.kv.source(), KvSource::Inferred);
assert_eq!(c.kv.bytes_per_layer_token(), 2 * kv_width as u64 * 4);
}
#[test]
fn kv_inference_is_orientation_agnostic() {
let (hidden, w) = (4096usize, 1024usize);
let gguf = vec![
TensorEntry::new("blk.0.attn_norm.weight", vec![hidden], 1),
TensorEntry::new("blk.0.attn_k.weight", vec![hidden, w], 1),
];
let hf = vec![
TensorEntry::new("blk.0.attn_norm.weight", vec![hidden], 1),
TensorEntry::new("blk.0.attn_k.weight", vec![w, hidden], 1),
];
let a = ModelCost::from_tensor_index(&gguf, &CostOptions::default()).unwrap();
let b = ModelCost::from_tensor_index(&hf, &CostOptions::default()).unwrap();
assert_eq!(a.kv.bytes_per_layer_token(), b.kv.bytes_per_layer_token());
assert_eq!(a.kv.bytes_per_layer_token(), 2 * w as u64 * 4);
}
#[test]
fn unreadable_attention_is_unknown_not_zero() {
let idx = vec![
TensorEntry::new("blk.0.attn_norm.weight", vec![4096], 1),
TensorEntry::new("blk.0.mystery_attention.weight", vec![7, 9], 1),
];
let c = ModelCost::from_tensor_index(&idx, &CostOptions::default()).unwrap();
assert_eq!(c.kv.source(), KvSource::Unknown);
assert!(!c.kv.is_known());
assert_eq!(c.kv.bytes_per_layer_token(), 0);
}
#[test]
fn recurrent_block_with_unreadable_dims_is_unknown() {
let idx = vec![
TensorEntry::new("blk.0.attn_norm.weight", vec![4096], 1),
TensorEntry::new("blk.0.ssm_conv1d.weight", vec![8192, 1, 4], 1),
];
let c = ModelCost::from_tensor_index(&idx, &CostOptions::default()).unwrap();
assert_eq!(c.kv.source(), KvSource::Unknown);
assert!(!c.kv.is_known());
}
#[test]
fn recurrent_wins_over_attn_k_in_the_same_block() {
let idx = vec![
TensorEntry::new("blk.0.attn_norm.weight", vec![4096], 1),
TensorEntry::new("blk.0.attn_k.weight", vec![8192, 4096], 1),
TensorEntry::new("blk.0.ssm_a", vec![64], 1),
TensorEntry::new("blk.0.ssm_norm.weight", vec![128], 1),
];
let c = ModelCost::from_tensor_index(&idx, &CostOptions::default()).unwrap();
assert_eq!(
c.kv.blocks(),
[BlockKv::Recurrent {
state_bytes: 64 * 128 * 128 * 4
}]
);
assert_eq!(c.kv.bytes_per_layer_token(), 0, "no per-token cache");
}
#[test]
fn partially_readable_stack_is_unknown() {
let mut idx = hybrid_index();
idx.retain(|t| !t.name.starts_with("blk.7."));
idx.push(TensorEntry::new("blk.7.attn_norm.weight", vec![4096], 1));
idx.push(TensorEntry::new("blk.7.something.weight", vec![3, 5], 1));
let c = ModelCost::from_tensor_index(&idx, &CostOptions::default()).unwrap();
assert_eq!(c.kv.source(), KvSource::Unknown);
}
#[test]
fn square_projection_is_ambiguous_and_declines() {
let idx = vec![
TensorEntry::new("blk.0.attn_norm.weight", vec![4096], 1),
TensorEntry::new("blk.0.attn_k.weight", vec![4096, 4096], 1),
];
let c = ModelCost::from_tensor_index(&idx, &CostOptions::default()).unwrap();
assert_eq!(c.kv.source(), KvSource::Unknown);
}
#[test]
fn per_range_kv_beats_the_average_on_a_hybrid_stack() {
let c = ModelCost::from_tensor_index(&hybrid_index(), &CostOptions::default()).unwrap();
let ctx = 4096;
let none = c.kv.bytes_for(0..3, ctx); let one = c.kv.bytes_for(3..7, ctx); let avg3 = c.kv.bytes(3, ctx);
assert_eq!(
none,
c.kv.blocks()[0..3]
.iter()
.map(BlockKv::state_bytes)
.sum::<u64>()
);
assert_eq!(
one,
512 * 4 * ctx as u64
+ c.kv.blocks()[3..7]
.iter()
.map(BlockKv::state_bytes)
.sum::<u64>()
);
assert!(
avg3 > none,
"average over-reserves the recurrent-only range"
);
assert!(
c.kv.bytes(4, ctx) < one,
"average under-reserves the range holding an attention layer"
);
}
#[test]
fn window_max_bounds_every_placement_of_a_given_length() {
let c = ModelCost::from_tensor_index(&hybrid_index(), &CostOptions::default()).unwrap();
let ctx = 4096;
for len in [1usize, 3, 4, 8, 45] {
let worst = c.kv.max_window_bytes(len, ctx);
for start in 0..=(45 - len) {
assert!(
c.kv.bytes_for(start..start + len, ctx) <= worst,
"window {start}..{} exceeds the bound at len {len}",
start + len
);
}
assert!(
worst >= c.kv.bytes(len as u64, ctx),
"bound must cover the mean"
);
}
}
#[test]
fn cache_dtype_scales_the_reservation() {
let f32o = CostOptions::default();
let f16o = CostOptions {
kv_dtype: "f16".into(),
..Default::default()
};
let a = ModelCost::from_tensor_index(&hybrid_index(), &f32o).unwrap();
let b = ModelCost::from_tensor_index(&hybrid_index(), &f16o).unwrap();
assert_eq!(
a.kv.blocks()[3].bytes_per_token(),
2 * b.kv.blocks()[3].bytes_per_token()
);
assert_eq!(
a.kv.blocks()[0].state_bytes(),
2 * b.kv.blocks()[0].state_bytes()
);
assert!(a.kv.blocks()[0].state_bytes() > 0);
assert_eq!(kv_elem_bytes("bf16"), 2);
assert_eq!(kv_elem_bytes("int8"), 1);
assert_eq!(kv_elem_bytes("anything-else"), 4);
}
#[test]
fn hidden_size_comes_from_the_checkpoint() {
let c = ModelCost::from_tensor_index(&hybrid_index(), &CostOptions::default()).unwrap();
assert_eq!(c.hidden_size, 4096);
let guessed = ((c.per_layer_bytes as f64 / 12.0).sqrt()).max(1.0) as usize;
assert_ne!(guessed, c.hidden_size);
}
#[test]
fn declared_profile_falls_back_to_the_average_for_ranges() {
let k = KvProfile::declared(1000);
assert_eq!(k.bytes_for(0..4, 10), 4 * 10 * 1000);
assert_eq!(k.max_window_bytes(4, 10), 4 * 10 * 1000);
}
#[test]
fn unrecognized_naming_is_an_error_not_a_zero_layer_model() {
let idx = vec![TensorEntry::new("weird.0.w", vec![4], 16)];
let err = ModelCost::from_tensor_index(&idx, &CostOptions::default())
.unwrap_err()
.to_string();
assert!(err.contains("no numbered blocks"), "{err}");
}
}