use cutile::prelude::*;
use crate::common;
#[cutile::module]
mod atomic_red_kernels {
use cutile::core::*;
use cutile::tileir::*;
#[cutile::entry()]
unsafe fn atomic_red_accumulate(out: &Tensor<f32, { [-1, -1] }>) {
let mut out_part: PartitionMut<f32, { [16, 16] }> =
unsafe { out.partition_full_mut(const_shape![16, 16]) };
let tile: Tile<f32, { [16, 16] }> = constant(1.0f32, const_shape![16, 16]);
let _tok: Token = unsafe {
atomic_red_view_tko(
&mut out_part,
tile,
[0i32, 0i32],
atomic::AddF,
ordering::Relaxed,
scope::Device,
)
};
}
}
use atomic_red_kernels::atomic_red_accumulate;
#[test]
fn atomic_red_view_accumulates_across_blocks() {
common::with_test_stack(|| {
let device = cuda_core::Device::new(0).expect("device");
let stream = device.new_stream().expect("stream");
const BLOCKS: usize = 32;
let out = api::zeros::<f32>(&[512, 16])
.sync_on(&stream)
.expect("zeros");
unsafe { atomic_red_accumulate(&out) }
.grid((BLOCKS as u32, 1, 1))
.sync_on(&stream)
.expect("launch");
let host: Vec<f32> = out.dup().to_host_vec().sync_on(&stream).expect("to_host");
assert_eq!(host.len(), 512 * 16);
let (first_tile, rest) = host.split_at(16 * 16);
assert!(
first_tile.iter().all(|&v| v == BLOCKS as f32),
"expected tile [0, 0] to accumulate to {BLOCKS}, got {:?}",
&first_tile[..8]
);
assert!(
rest.iter().all(|&v| v == 0.0),
"expected all other tiles untouched"
);
});
}