rocmrc 0.4.0

Minimal safe ROCm bindings (HIP, hipRTC), modeled after cudarc
Documentation
use super::{result, result::RocblasError, sys};
use crate::hip::DevicePtr;
use crate::rocblas::RocBlas;

pub struct AsumConfig {
    pub n: sys::rocblas_int,
    pub incx: sys::rocblas_int,
}

pub trait Asum<T> {
    fn asum<X: DevicePtr<T>>(
        &self,
        cfg: AsumConfig,
        x: &X,
        result: &mut T,
    ) -> Result<(), RocblasError>;
}

impl Asum<f32> for RocBlas {
    fn asum<X: DevicePtr<f32>>(
        &self,
        cfg: AsumConfig,
        x: &X,
        result: &mut f32,
    ) -> Result<(), RocblasError> {
        let (x, _record_x) = x.device_ptr(&self.stream);
        unsafe {
            result::sasum(
                self.handle,
                cfg.n,
                x as *const _,
                cfg.incx,
                result as *mut _,
            )
        }
    }
}

impl Asum<f64> for RocBlas {
    fn asum<X: DevicePtr<f64>>(
        &self,
        cfg: AsumConfig,
        x: &X,
        result: &mut f64,
    ) -> Result<(), RocblasError> {
        let (x, _record_x) = x.device_ptr(&self.stream);
        unsafe {
            result::dasum(
                self.handle,
                cfg.n,
                x as *const _,
                cfg.incx,
                result as *mut _,
            )
        }
    }
}

#[cfg(test)]
mod tests {
    #![allow(clippy::needless_range_loop)]

    use super::*;
    use crate::hip::HipContext;
    use std::vec;

    fn dasum_truth(a: &[f64], c: &mut f64, n: usize, incx: usize) {
        *c = 0.0;
        for x in a.iter().step_by(incx).take(n) {
            *c += x.abs();
        }
    }
    fn sasum_truth(a: &[f32], c: &mut f32, n: usize, incx: usize) {
        *c = 0.0;
        for x in a.iter().step_by(incx).take(n) {
            *c += x.abs();
        }
    }

    #[test]
    fn test_sasum() {
        let ctx = HipContext::new(0).unwrap();
        let stream = ctx.default_stream();
        let blas = RocBlas::new(stream.clone()).unwrap();

        #[rustfmt::skip]
        let samples = [
            (vec![-0.5944882f32, 1.8055636, 0.52204555, -0.00397902], 0.0f32, 4usize, 1usize),
            (vec![-0.5944882, 1.8055636, 0.52204555, -0.00397902], -1.0, 4, 1),
            (vec![-0.5944882, 1.8055636, 0.52204555, -0.00397902], 3.0, 4, 1),
            (vec![-0.38346434, -0.38013917, 0.4198623], 0.0, 3, 1),
            (vec![-1.6661372, -0.4568837, -0.9043474, 0.39125723, 0.39125723], 0.0, 5, 1)
        ];
        for ref out @ (ref x, result, n, incx) in samples.into_iter() {
            let mut actual = result;
            let mut expected = result;
            sasum_truth(x, &mut actual, n, incx);

            let x = stream.clone_htod(x).unwrap();
            blas.asum(
                AsumConfig {
                    n: n as i32,
                    incx: incx as i32,
                },
                &x,
                &mut expected,
            )
            .unwrap();
            let delta = (actual - expected).abs();
            let epsilon = 2.0 * f32::EPSILON;
            assert!(
                delta <= epsilon,
                "({actual} - {expected}).abs() -> {delta:+e} <= {epsilon:+e}: {out:?}"
            );
        }
    }

    #[test]
    fn test_dasum() {
        let ctx = HipContext::new(0).unwrap();
        let stream = ctx.default_stream();
        let blas = RocBlas::new(stream.clone()).unwrap();

        #[rustfmt::skip]
        let samples = [
            (vec![-0.5944882f64, 1.8055636, 0.52204555, -0.00397902], 0.0f64, 4usize, 1usize),
            (vec![-0.5944882, 1.8055636, 0.52204555, -0.00397902], -1.0, 4, 1),
            (vec![-0.5944882, 1.8055636, 0.52204555, -0.00397902], 3.0, 4, 1),
            (vec![-0.38346434, -0.38013917, 0.4198623], 0.0, 3, 1),
            (vec![-1.6661372, -0.4568837, -0.9043474, 0.39125723, 0.39125723], 0.0, 5, 1)
        ];
        for ref out @ (ref x, result, n, incx) in samples.into_iter() {
            let mut actual = result;
            let mut expected = result;
            dasum_truth(x, &mut actual, n, incx);

            let x = stream.clone_htod(x).unwrap();
            blas.asum(
                AsumConfig {
                    n: n as i32,
                    incx: incx as i32,
                },
                &x,
                &mut expected,
            )
            .unwrap();
            let delta = (actual - expected).abs();
            let epsilon = 2.0 * f64::EPSILON;
            assert!(
                delta <= epsilon,
                "({actual} - {expected}).abs() -> {delta:+e} <= {epsilon:+e}: {out:?}"
            );
        }
    }
}