libmir-cuda 0.1.0

CUDA inference backend for libmir
use mircuda::{
    BlockScaledFp4Plan, BlockScaledFp4Spec, BlockScaledFp4VectorPlan, BlockScaledFp4VectorSpec,
    Context, DeviceBuffer, Stream, bf16,
};

use crate::Result;

#[derive(Debug)]
pub(super) enum NativeNvFp4Plan {
    Matrix(BlockScaledFp4Plan),
    Vector(BlockScaledFp4VectorPlan),
}

impl NativeNvFp4Plan {
    pub(super) fn new(
        context: &Context,
        stream: &Stream,
        tokens: usize,
        output_features: usize,
        input_features: usize,
    ) -> Result<Self> {
        if use_vector(tokens, output_features, input_features) {
            Ok(Self::Vector(BlockScaledFp4VectorPlan::new(
                context,
                stream,
                BlockScaledFp4VectorSpec::new(output_features, input_features)?,
            )?))
        } else {
            Ok(Self::Matrix(BlockScaledFp4Plan::new(
                context,
                stream,
                BlockScaledFp4Spec::new(tokens, output_features, input_features)?,
            )?))
        }
    }

    #[allow(clippy::too_many_arguments)]
    pub(super) fn execute(
        &mut self,
        stream: &Stream,
        input: &DeviceBuffer<u8>,
        input_scales: &DeviceBuffer<u8>,
        weight: &DeviceBuffer<u8>,
        weight_scales: &DeviceBuffer<u8>,
        output: &mut DeviceBuffer<bf16>,
        alpha: f32,
    ) -> Result<()> {
        match self {
            Self::Matrix(plan) => {
                Ok(plan
                    .execute(stream, input, input_scales, weight, weight_scales, output, alpha)?)
            },
            Self::Vector(plan) => {
                Ok(plan
                    .execute(stream, input, input_scales, weight, weight_scales, output, alpha)?)
            },
        }
    }
}

fn use_vector(tokens: usize, output_features: usize, input_features: usize) -> bool {
    const VALIDATED: [(usize, usize); 3] = [(1_024, 4_096), (4_096, 4_096), (12_288, 4_096)];
    tokens == 1 && VALIDATED.contains(&(output_features, input_features))
}

#[cfg(test)]
mod tests {
    use super::use_vector;

    #[test]
    fn admits_only_validated_single_token_geometries() {
        for output in [1_024, 4_096, 12_288] {
            assert!(use_vector(1, output, 4_096));
            assert!(!use_vector(2, output, 4_096));
        }
        assert!(!use_vector(1, 4_096, 12_288));
        assert!(!use_vector(1, 2_816, 4_096));
    }
}