libmir-cuda 0.3.0

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

use super::super::{
    AffineQuantizedBf16Linear, AffineQuantizedBf16Qmm, AffineQuantizedConfig,
    AffineQuantizedWeight, CudaBackend,
};
use crate::{Result, backend::tuning::AffineProjectionExecution};

#[derive(Debug)]
pub(super) struct Candidate {
    pub(super) execution: AffineProjectionExecution,
    operation: Operation,
}

#[derive(Debug)]
enum Operation {
    Qmm(AffineQuantizedBf16Qmm),
    Gemv(AffineQuantizedBf16Linear),
}

impl Candidate {
    pub(super) fn new(
        backend: &CudaBackend,
        tokens: usize,
        config: AffineQuantizedConfig,
        execution: AffineProjectionExecution,
    ) -> Result<Self> {
        let operation = match execution {
            AffineProjectionExecution::Qmm => {
                Operation::Qmm(AffineQuantizedBf16Qmm::new(backend, tokens, config, 1)?)
            },
            AffineProjectionExecution::Gemv => Operation::Gemv(AffineQuantizedBf16Linear::new(
                backend,
                config.input_features,
                config.output_features,
                1,
                config.group_size,
                config.bits,
            )?),
        };
        Ok(Self { execution, operation })
    }

    pub(super) fn execute(
        &self,
        input: &DeviceBuffer<bf16>,
        weights: &AffineQuantizedWeight,
        output: &mut DeviceBuffer<bf16>,
    ) -> Result<()> {
        match &self.operation {
            Operation::Qmm(operation) => operation.execute(input, weights.tensors(), output, 0),
            Operation::Gemv(operation) => operation.execute(input, weights.tensors(), output, 0),
        }
    }
}