libmir-cuda 0.3.0

CUDA inference backend for libmir
use mircuda::{DeviceBuffer, bf16};

use super::{
    DecodeAttentionBf16, DecodeAttentionWeights, PrefillAttentionBf16, QkvProjectionBuffers,
};
use crate::{Error, PagedPrefillBatch, Result};

impl PrefillAttentionBf16 {
    pub fn execute_batch(
        &mut self,
        state: &mut DecodeAttentionBf16,
        input: &DeviceBuffer<bf16>,
        weights: DecodeAttentionWeights<'_>,
        batch: &PagedPrefillBatch,
        output: &mut DeviceBuffer<bf16>,
    ) -> Result<()> {
        let mut state_config = state.config;
        let mut prefill_config = self.config;
        state_config.layer = 0;
        prefill_config.layer = 0;
        if state_config != prefill_config || batch.tokens() != self.tokens {
            return Err(Error::InvalidPagedKv(
                "prefill attention batch state or token count differs",
            ));
        }
        let separate = self.qkv.execute(
            input,
            &self.input_norm,
            weights.input_norm,
            weights.qkv,
            &mut QkvProjectionBuffers {
                normalized: &mut self.scratch.normalized,
                packed: &mut self.scratch.qkv,
                separate: &mut self.scratch.qkv_separate,
            },
        )?;
        let inputs = if separate {
            [
                &self.scratch.qkv_separate[0],
                &self.scratch.qkv_separate[1],
                &self.scratch.qkv_separate[2],
            ]
        } else {
            [&self.scratch.qkv, &self.scratch.qkv, &self.scratch.qkv]
        };
        self.qkv_postprocess_batch.execute(
            &self.stream,
            inputs,
            separate,
            weights.query_norm,
            weights.key_norm,
            batch.positions(),
            &mut self.scratch.query_rope,
            &mut self.scratch.key_rope,
            &mut self.scratch.value_norm,
        )?;
        state
            .cache
            .store_prefill_batch(batch, &self.scratch.key_rope, &self.scratch.value_norm)?;
        if self.config.sliding_window.is_none() && self.fmha.is_some() {
            return self.execute_paged_varlen_attention(state, weights, batch, output);
        }
        let mut packed = 0;
        for row in batch.rows() {
            self.scratch.ensure_row(
                &self.pool,
                &self.stream,
                row.tokens(),
                self.query_width,
                self.attention_width,
            )?;
            let row_scratch = self
                .scratch
                .rows
                .get_mut(&row.tokens())
                .ok_or(Error::InvalidPagedKv("missing packed prefill row scratch"))?;
            self.query_rows.execute(
                &self.stream,
                &self.scratch.query_rope,
                &mut row_scratch.query,
                packed,
                0,
                row.tokens(),
            )?;
            state.attention.execute_prefill(
                &row_scratch.query,
                &state.cache,
                row.table(),
                &mut row_scratch.attention,
                row.tokens(),
                row.start(),
                self.config.sliding_window,
                self.config.attention_scale,
            )?;
            self.output_rows.execute(
                &self.stream,
                &row_scratch.attention,
                &mut self.scratch.attention,
                0,
                packed,
                row.tokens(),
            )?;
            packed += row.tokens();
        }
        self.output_projection.execute(
            &self.stream,
            &self.scratch.attention,
            weights.output,
            output,
        )
    }
}