use crate::bitio::DecodeError;
use crate::kvcodec::{gpu_prior_table, lane_chan, KvStream, GPU_CTX_MODELS};
pub const LANE_WORDS: usize = 16;
#[derive(Default)]
pub struct Batch {
pub stream: Vec<u32>,
pub lanes: Vec<u32>,
pub chans: Vec<u32>,
pub scratch_words: usize,
bytes: Vec<u8>,
}
pub struct Placement<'f> {
pub row: &'f dyn Fn(usize, usize) -> usize,
pub rope_theta: Option<f32>,
pub decode_only: bool,
}
impl Batch {
pub fn new() -> Self {
Self::default()
}
pub fn add(
&mut self,
bytes: &[u8],
place: &Placement,
t0: usize,
t1: usize,
) -> Result<(), DecodeError> {
let s = KvStream::parse(bytes)?;
let tb = s
.gpu_tables()
.ok_or(DecodeError::Invalid("not a gpu-layout stream"))?;
let p = &s.params;
let base = self.bytes.len();
self.bytes.extend_from_slice(bytes);
while !self.bytes.len().is_multiple_of(4) {
self.bytes.push(0);
}
let chan0 = self.chans.len() / 4;
let (w, ng) = (p.lane_width(), p.lane_groups());
if w > 128 {
return Err(DecodeError::Invalid("gpu lane wider than 128 channels"));
}
let mut ncls = vec![0usize; p.heads * ng];
for (hg, nc) in ncls.iter_mut().enumerate() {
let (hh, g) = (hg / ng, hg % ng);
let mut seen: Vec<u32> = Vec::new();
for i in 0..w {
let j = hh * p.hd + lane_chan(p.hd, w, g, i);
let cl = tb.class[j];
let di = seen.iter().position(|&v| v == cl).unwrap_or_else(|| {
seen.push(cl);
seen.len() - 1
});
self.chans
.extend_from_slice(&[tb.mu[j] as u32, tb.rho[j], cl, di as u32]);
}
*nc = seen.len();
}
let ctx_words = 3 * GPU_CTX_MODELS;
for l in &tb.lanes {
let [off, len, pos0, n, hh, g] = *l;
let (pos0, n, hh, g) = (pos0 as usize, n as usize, hh as usize, g as usize);
let hg = hh * ng + g;
if pos0 + n <= t0 || pos0 >= t1 {
continue;
}
let row0 = (place.row)(hh, pos0);
let stride = if n > 1 {
(place.row)(hh, pos0 + 1) - row0
} else {
p.hd
};
self.lanes.extend_from_slice(&[
(base + off as usize) as u32,
len,
pos0 as u32,
n as u32,
(chan0 + hg * w) as u32,
row0 as u32,
stride as u32,
self.scratch_words as u32,
p.unit().to_bits(),
p.sink as u32,
p.sink_div,
w as u32,
place.rope_theta.is_some() as u32 | (place.decode_only as u32) << 1,
place.rope_theta.unwrap_or(0.0).to_bits(),
(g * w / 2) as u32,
p.hd as u32,
]);
self.scratch_words += ncls[hg] * ctx_words;
}
self.stream = self
.bytes
.chunks(4)
.map(|w| u32::from_le_bytes([w[0], w[1], w[2], w[3]]))
.collect();
Ok(())
}
pub fn n_lanes(&self) -> usize {
self.lanes.len() / LANE_WORDS
}
pub fn prior() -> Vec<u32> {
gpu_prior_table()
}
}