libmir-cuda 0.2.0

CUDA inference backend for libmir
use mircuda::{
    CompileOptions, Compiler, DeviceBuffer, LaunchConfig, Stream, TypedKernel, bf16, cuda_export,
    cuda_kernel_file,
};

use crate::{Error, Result};

cuda_export!(
    NormalizeKernel = "libmir_cuda_l2_normalize_bf16"(
        input: &DeviceBuffer<bf16>, output: &mut DeviceBuffer<bf16>,
        elements: u32, epsilon: f32,
    )
);

#[derive(Clone, Debug)]
pub struct L2NormalizeBf16 {
    kernel: TypedKernel<NormalizeKernel>,
    elements: usize,
}

impl L2NormalizeBf16 {
    pub fn compile(compiler: &Compiler, elements: usize) -> Result<Self> {
        if elements == 0 || elements > 65_536 {
            return Err(Error::InvalidDecoderKernel("invalid L2 normalization width"));
        }
        let source = cuda_kernel_file!("../../../kernels/text/normalize_bf16.cu");
        let module = compiler.compile(source, &CompileOptions::default())?;
        Ok(Self { kernel: module.kernel()?, elements })
    }

    pub fn execute(
        &self,
        stream: &Stream,
        input: &DeviceBuffer<bf16>,
        output: &mut DeviceBuffer<bf16>,
    ) -> Result<()> {
        if input.len() != self.elements || output.len() != self.elements {
            return Err(Error::InvalidDecoderKernel("L2 normalization buffer geometry differs"));
        }
        Ok(self.kernel.launch(
            stream,
            LaunchConfig {
                grid: (1, 1, 1),
                block: (256, 1, 1),
                shared_memory_bytes: 0,
            },
            (input, output, u32::try_from(self.elements)?, 1.0e-12),
        )?)
    }
}