use poly_kv::{AttentionType, KvTensorShape, SharedKVPool};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use serde_json::json;
use std::time::Instant;
fn make_shape(head_dim: usize, num_heads: usize) -> KvTensorShape {
KvTensorShape {
attention_type: AttentionType::MHA,
num_layers: 2,
num_heads: num_heads as u32,
num_kv_heads: num_heads as u32,
head_dim,
hidden_size: head_dim * num_heads,
}
}
fn make_corpus(n: usize, shape: &KvTensorShape, seed: u64) -> Vec<(String, Vec<f32>)> {
let mut rng = ChaCha8Rng::seed_from_u64(seed);
let vec_len = shape.num_layers as usize * shape.num_kv_heads as usize * shape.head_dim * 2;
(0..n)
.map(|i| {
let vec: Vec<f32> = (0..vec_len).map(|_| rng.gen_range(-1.0..1.0)).collect();
(format!("token_{}", i), vec)
})
.collect()
}
fn bench_fn<F: FnMut()>(mut f: F, warmup: usize, repeat: usize) -> u128 {
for _ in 0..warmup {
f();
}
let start = Instant::now();
for _ in 0..repeat {
f();
}
start.elapsed().as_nanos() / repeat as u128
}
fn naive_exact_attention(
keys: &[f32],
head_dim: usize,
query: &[f32],
top_k: usize,
) -> Vec<(usize, f32)> {
let num_tokens = keys.len() / head_dim;
let mut scored: Vec<(usize, f32)> = Vec::with_capacity(num_tokens);
for i in 0..num_tokens {
let start = i * head_dim;
let dot: f32 = query
.iter()
.zip(&keys[start..start + head_dim])
.map(|(a, b)| a * b)
.sum();
scored.push((i, dot));
}
scored.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
scored.truncate(top_k);
scored
}
fn optimized_exact_attention(
keys: &[f32],
head_dim: usize,
query: &[f32],
top_k: usize,
) -> Vec<(usize, f32)> {
let num_tokens = keys.len() / head_dim;
let mut heap: Vec<(f32, usize)> = Vec::with_capacity(top_k + 1);
let block_size = 64;
for block_start in (0..num_tokens).step_by(block_size) {
let block_end = (block_start + block_size).min(num_tokens);
for i in block_start..block_end {
let key_start = i * head_dim;
let key = &keys[key_start..key_start + head_dim];
let dot: f32 = query.iter().zip(key).map(|(q, k)| q * k).sum();
if heap.len() < top_k {
heap.push((dot, i));
heap.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
} else if dot > heap[0].0 {
heap[0] = (dot, i);
let mut idx = 0;
loop {
let left = 2 * idx + 1;
let right = 2 * idx + 2;
let smallest = if left < top_k
&& heap[left].0 < heap[idx].0
&& (right >= top_k || heap[left].0 <= heap[right].0)
{
left
} else if right < top_k && heap[right].0 < heap[idx].0 {
right
} else {
idx
};
if smallest == idx {
break;
}
heap.swap(idx, smallest);
idx = smallest;
}
}
}
}
heap.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
heap.into_iter().map(|(score, idx)| (idx, score)).collect()
}
fn optimized_exact_multihead(
keys: &[f32], num_heads: usize,
head_dim: usize,
queries: &[&[f32]], top_k: usize,
) -> Vec<Vec<(usize, f32)>> {
let num_tokens = keys.len() / (num_heads * head_dim);
let mut results: Vec<Vec<(usize, f32)>> = Vec::with_capacity(num_heads);
for head_idx in 0..num_heads {
let query = queries[head_idx];
let mut heap: Vec<(f32, usize)> = Vec::with_capacity(top_k + 1);
for i in 0..num_tokens {
let key_offset = i * num_heads * head_dim + head_idx * head_dim;
let key = &keys[key_offset..key_offset + head_dim];
let dot: f32 = query.iter().zip(key).map(|(q, k)| q * k).sum();
if heap.len() < top_k {
heap.push((dot, i));
heap.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
} else if dot > heap[0].0 {
heap[0] = (dot, i);
let mut idx = 0;
loop {
let left = 2 * idx + 1;
let right = 2 * idx + 2;
let smallest = if left < top_k
&& heap[left].0 < heap[idx].0
&& (right >= top_k || heap[left].0 <= heap[right].0)
{
left
} else if right < top_k && heap[right].0 < heap[idx].0 {
right
} else {
idx
};
if smallest == idx {
break;
}
heap.swap(idx, smallest);
idx = smallest;
}
}
}
heap.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
results.push(heap.into_iter().map(|(score, idx)| (idx, score)).collect());
}
results
}
fn run_scale(
num_tokens: usize,
head_dim: usize,
num_heads: usize,
top_k: usize,
warmup: usize,
repeat: usize,
) -> serde_json::Value {
let shape = make_shape(head_dim, num_heads);
let corpus = make_corpus(num_tokens, &shape, 42);
let (pool, _) = SharedKVPool::build(&corpus, &shape, 42).unwrap();
let queries: Vec<Vec<f32>> = (0..num_heads)
.map(|h| {
(0..head_dim)
.map(|x| (x as f32 + h as f32 * 0.1) * 0.05)
.collect()
})
.collect();
let query_refs: Vec<&[f32]> = queries.iter().map(|q| q.as_slice()).collect();
let decompressed = pool.decompress_layer(0).unwrap();
let per_head_keys: Vec<Vec<f32>> = decompressed.keys.clone();
let pre_decoded_keys = per_head_keys[0].clone();
let mut multihead_keys = vec![0.0f32; num_tokens * num_heads * head_dim];
for tok in 0..num_tokens {
for head in 0..num_heads {
let src_start = tok * head_dim;
let dst_start = tok * num_heads * head_dim + head * head_dim;
multihead_keys[dst_start..dst_start + head_dim]
.copy_from_slice(&per_head_keys[head][src_start..src_start + head_dim]);
}
}
let query = &queries[0];
let naive_ns = bench_fn(
|| {
let _ = naive_exact_attention(&pre_decoded_keys, head_dim, query, top_k);
},
warmup,
repeat,
);
let optimized_ns = bench_fn(
|| {
let _ = optimized_exact_attention(&pre_decoded_keys, head_dim, query, top_k);
},
warmup,
repeat,
);
let optimized_mh_ns = bench_fn(
|| {
let _ =
optimized_exact_multihead(&multihead_keys, num_heads, head_dim, &query_refs, top_k);
},
warmup,
repeat,
);
let fully_index = pool.prepare_fully_compressed_index(0, 0).unwrap();
let fully_prepared_ns = bench_fn(
|| {
let _ = pool
.attention_topk_fully_prepared(&fully_index, query, top_k)
.unwrap();
},
warmup,
repeat,
);
let batch_ns = bench_fn(
|| {
let _ = pool
.attention_topk_batch_heads(&fully_index, &query_refs, top_k)
.unwrap();
},
warmup,
repeat,
);
let exact_hits = optimized_exact_attention(&pre_decoded_keys, head_dim, query, top_k);
let comp = pool
.attention_topk_fully_prepared(&fully_index, query, top_k)
.unwrap();
let exact_top: std::collections::HashSet<usize> = exact_hits.iter().map(|(i, _)| *i).collect();
let comp_top: std::collections::HashSet<usize> =
comp.hits.iter().map(|h| h.token_index).collect();
let overlap = exact_top.intersection(&comp_top).count() as f64
/ exact_top.union(&comp_top).count().max(1) as f64;
let optimized_mh_per_head = optimized_mh_ns / num_heads as u128;
let batch_per_head = batch_ns / num_heads as u128;
json!({
"num_tokens": num_tokens,
"head_dim": head_dim,
"num_heads": num_heads,
"top_k": top_k,
"naive_exact_ns": naive_ns,
"optimized_exact_ns": optimized_ns,
"optimized_multihead_ns": optimized_mh_ns,
"optimized_multihead_per_head_ns": optimized_mh_per_head,
"fully_prepared_ns": fully_prepared_ns,
"batch_heads_ns": batch_ns,
"batch_per_head_ns": batch_per_head,
"ratio_fully_vs_optimized": optimized_ns as f64 / fully_prepared_ns as f64,
"ratio_batch_vs_optimized_mh": optimized_mh_per_head as f64 / batch_per_head as f64,
"ratio_fully_vs_naive": naive_ns as f64 / fully_prepared_ns as f64,
"topk_overlap": overlap,
})
}
fn main() {
let warmup = 10;
let top_k = 8;
let configs = [
(
64usize,
12usize,
[2048, 4096, 8192, 16384, 32768].as_slice(),
30usize,
),
(
128usize,
8usize,
[2048, 4096, 8192, 16384].as_slice(),
20usize,
),
];
let mut all_results = Vec::new();
for &(head_dim, num_heads, scales, base_repeat) in &configs {
eprintln!("\n=== head_dim={head_dim} num_heads={num_heads} ===");
for &n in scales {
let repeat = if n >= 16384 {
5
} else if n >= 8192 {
10
} else {
base_repeat
};
let repeat = repeat.max(3);
eprintln!(" n={n} repeat={repeat}...");
all_results.push(run_scale(n, head_dim, num_heads, top_k, warmup, repeat));
}
}
let receipt = json!({
"schema_version": "poly_kv_real_kernel_comparison_v1",
"claim_boundary": "fair isolated Rust CPU attention-operator benchmark; naive sequential exact vs optimized cache-blocked exact (production-like baseline) vs proveKV fully-prepared compressed; synthetic random vectors; release mode; not end-to-end model latency, not GPU evidence, not production serving speedup",
"config": {
"top_k": top_k,
"warmup": warmup,
"build_mode": "release",
"cpu": "AMD Ryzen 7 7730U (8 cores, 16 threads, 32KB L1d)",
"note": "optimized_exact uses cache-blocked traversal + partial top-k heap sort; this is the fairest CPU baseline representing what candle/llama.cpp would do",
},
"results": all_results,
"passed": true,
"blockers": [],
});
println!("{}", serde_json::to_string_pretty(&receipt).unwrap());
eprintln!("\n=== REAL-KERNEL COMPARISON SUMMARY ===");
eprintln!(
"{:>6} {:>4} {:>4} {:>10} {:>10} {:>10} {:>10} {:>10} {:>8} {:>8} {:>8}",
"tokens",
"dim",
"heads",
"naive_ns",
"opt_ns",
"opt_mh_ns",
"fully_ns",
"batch_ns",
"r_f/opt",
"r_b/optmh",
"overlap"
);
for r in &all_results {
eprintln!(
"{:>6} {:>4} {:>4} {:>10} {:>10} {:>10} {:>10} {:>10} {:>8.2} {:>8.2} {:>8.4}",
r["num_tokens"].as_u64().unwrap(),
r["head_dim"].as_u64().unwrap(),
r["num_heads"].as_u64().unwrap(),
r["naive_exact_ns"].as_u64().unwrap(),
r["optimized_exact_ns"].as_u64().unwrap(),
r["optimized_multihead_ns"].as_u64().unwrap(),
r["fully_prepared_ns"].as_u64().unwrap(),
r["batch_heads_ns"].as_u64().unwrap(),
r["ratio_fully_vs_optimized"].as_f64().unwrap(),
r["ratio_batch_vs_optimized_mh"].as_f64().unwrap(),
r["topk_overlap"].as_f64().unwrap(),
);
}
}