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 super::geometry::{narrow, product, require};
use crate::{Error, Result};

cuda_export!(
    SigmoidMultiplyKernel = "libmir_cuda_sigmoid_multiply_bf16"(
        input: &DeviceBuffer<bf16>, gate: &DeviceBuffer<bf16>,
        output: &mut DeviceBuffer<bf16>, rows: u32, columns: u32,
    )
);

cuda_export!(
    SigmoidElementwiseKernel = "libmir_cuda_sigmoid_multiply_elementwise_bf16"(
        input: &DeviceBuffer<bf16>, gate: &DeviceBuffer<bf16>,
        output: &mut DeviceBuffer<bf16>, elements: u32,
    )
);

#[derive(Clone, Debug)]
pub struct SigmoidMultiplyBf16 {
    kernel: TypedKernel<SigmoidMultiplyKernel>,
    rows: usize,
    columns: usize,
}

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

impl SigmoidMultiplyBf16 {
    pub fn compile(compiler: &Compiler, rows: usize, columns: usize) -> Result<Self> {
        if rows == 0 || columns == 0 {
            return Err(Error::InvalidDecoderKernel("empty sigmoid multiply geometry"));
        }
        let source = cuda_kernel_file!("../../kernels/sigmoid_multiply_bf16.cu");
        let module = compiler.compile(source, &CompileOptions::default())?;
        Ok(Self { kernel: module.kernel()?, rows, columns })
    }

    pub fn execute(
        &self,
        stream: &Stream,
        input: &DeviceBuffer<bf16>,
        gate: &DeviceBuffer<bf16>,
        output: &mut DeviceBuffer<bf16>,
    ) -> Result<()> {
        let elements = product(self.rows, self.columns)?;
        require("sigmoid multiply input", elements, input.len())?;
        require("sigmoid multiply gate", self.rows, gate.len())?;
        require("sigmoid multiply output", elements, output.len())?;
        let threads = 256_usize;
        Ok(self.kernel.launch(
            stream,
            LaunchConfig {
                grid: (narrow(elements.div_ceil(threads))?, 1, 1),
                block: (narrow(threads)?, 1, 1),
                shared_memory_bytes: 0,
            },
            (input, gate, output, narrow(self.rows)?, narrow(self.columns)?),
        )?)
    }
}

impl SigmoidElementwiseBf16 {
    pub fn compile(compiler: &Compiler, elements: usize) -> Result<Self> {
        if elements == 0 {
            return Err(Error::InvalidDecoderKernel("empty elementwise sigmoid geometry"));
        }
        let source = cuda_kernel_file!("../../kernels/sigmoid_multiply_bf16.cu");
        let module = compiler.compile(source, &CompileOptions::default())?;
        Ok(Self { kernel: module.kernel()?, elements })
    }

    pub fn execute(
        &self,
        stream: &Stream,
        input: &DeviceBuffer<bf16>,
        gate: &DeviceBuffer<bf16>,
        output: &mut DeviceBuffer<bf16>,
    ) -> Result<()> {
        require("elementwise sigmoid input", self.elements, input.len())?;
        require("elementwise sigmoid gate", self.elements, gate.len())?;
        require("elementwise sigmoid output", self.elements, output.len())?;
        let threads = 256_usize;
        Ok(self.kernel.launch(
            stream,
            LaunchConfig {
                grid: (narrow(self.elements.div_ceil(threads))?, 1, 1),
                block: (narrow(threads)?, 1, 1),
                shared_memory_bytes: 0,
            },
            (input, gate, output, narrow(self.elements)?),
        )?)
    }
}