use crate::Hardware;
use crate::microkernel::{CubeFootprint, CubePlanes, KernelEstimate};
use crate::routine::{ADMITTED_PLAN_RUNS, LaunchSettings};
use cubecl::CubeCount;
use cubecl::client::Client;
use cubecl::tile::launch::Grid as LaunchGrid;
use cubecl::tile::launch::Refusal;
use cubecl::tile::{Launcher, Partitioning, Space};
use cubecl_environment::sync::{Arc, SyncOnceCell};
#[derive(Debug, Clone)]
pub struct Grid {
pub launch: LaunchSettings,
pub shared_memory: usize,
launcher: SettledLauncher,
}
#[derive(Clone, Default)]
struct SettledLauncher(Arc<SyncOnceCell<Launcher>>);
impl core::fmt::Debug for SettledLauncher {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("SettledLauncher")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CubeResources {
pub plane_width: u32,
pub shared_memory: usize,
}
impl Grid {
pub fn launcher(
&self,
client: &Client,
settle: impl FnOnce() -> (Partitioning, Space),
) -> Launcher {
self.launcher
.0
.get_or_init(|| {
let (kernel, concrete) = settle();
Launcher::new(
client,
kernel,
&concrete,
LaunchGrid::Stated {
cube_count: self.launch.cube_count.clone(),
cube_dim: self.launch.cube_dim,
},
)
.and_then(|launcher| launcher.holding(self.shared_memory))
.expect(ADMITTED_PLAN_RUNS)
})
.clone()
}
pub fn new(
hw: &Hardware,
partitioning: &Partitioning,
cube: CubeResources,
) -> Result<Self, Refusal> {
let launch = LaunchSettings {
cube_dim: partitioning.cube_dim(cube.plane_width),
cube_count: partitioning.cube_count(),
vectors: (),
}
.validate(hw)?;
let available = hw.shared_memory_budget();
if cube.shared_memory > available {
return Err(Refusal::SharedMemoryPastDevice {
bytes: cube.shared_memory,
most: available,
});
}
Ok(Self {
launch,
shared_memory: cube.shared_memory,
launcher: SettledLauncher::default(),
})
}
pub fn cubes(&self) -> Option<u64> {
match self.launch.cube_count {
CubeCount::Static(x, y, z) => Some(u64::from(x) * u64::from(y) * u64::from(z)),
CubeCount::Dynamic(_) => None,
}
}
pub fn planes(&self) -> CubePlanes {
CubePlanes {
count: self.launch.cube_dim.y as usize,
width: self.launch.cube_dim.x as usize,
}
}
}
impl From<&Grid> for KernelEstimate {
fn from(grid: &Grid) -> Self {
Self {
cubes: grid.cubes(),
cube: CubeFootprint {
units: grid.launch.units_per_cube(),
shared_memory: grid.shared_memory,
},
demand: None,
staging: None,
work: None,
}
}
}