use std::sync::{LazyLock, Mutex};
use cubecl::prelude::CubeDim;
use cubecl::zspace::Tiling;
use hashbrown::{Equivalent, HashMap};
use super::base::{ArgData, Derived};
use crate::{
Axis, BoundaryPolicy, Delivery, Geometry, Packing, Partitioning, Projection, Refusal, Space,
};
#[derive(PartialEq, Eq, Hash)]
pub(crate) struct Derivation {
geometry: Geometry,
axes: Vec<Axis>,
batches: Vec<Axis>,
projection: Option<Projection>,
width: usize,
boundary: Option<BoundaryPolicy>,
packing: Packing,
delivery: Delivery,
in_stride_order: bool,
stored: Tiling,
partitioning: Partitioning,
space: Space,
cube_dim: CubeDim,
}
#[derive(Hash)]
pub(crate) struct DerivationView<'a> {
geometry: &'a Geometry,
axes: &'a [Axis],
batches: &'a [Axis],
projection: &'a Option<Projection>,
width: usize,
boundary: Option<BoundaryPolicy>,
packing: Packing,
delivery: Delivery,
in_stride_order: bool,
stored: Tiling,
partitioning: &'a Partitioning,
space: &'a Space,
cube_dim: CubeDim,
}
const KEPT: usize = 4096;
static KEPT_DERIVATIONS: LazyLock<Mutex<HashMap<Derivation, Result<Derived, Refusal>>>> =
LazyLock::new(|| Mutex::new(HashMap::new()));
impl Derivation {
pub(crate) fn view<'a>(
data: &'a ArgData<'a>,
packing: Packing,
stored: Tiling,
) -> DerivationView<'a> {
DerivationView {
geometry: &data.geometry,
axes: data.axes,
batches: data.batches,
projection: &data.projection,
width: data.width,
boundary: data.boundary,
packing,
delivery: data.delivery,
in_stride_order: data.in_stride_order,
stored,
partitioning: data.launch.partitioning(),
space: data.launch.space(),
cube_dim: data.launch.cube_dim(),
}
}
}
impl DerivationView<'_> {
pub(crate) fn derived(
self,
derive: impl FnOnce() -> Result<Derived, Refusal>,
) -> Result<Derived, Refusal> {
if let Some(kept) = KEPT_DERIVATIONS.lock().unwrap().get(&self) {
return kept.clone();
}
let derived = derive();
let mut kept = KEPT_DERIVATIONS.lock().unwrap();
if kept.len() >= KEPT {
kept.clear();
}
kept.insert(self.owned(), derived.clone());
derived
}
fn owned(self) -> Derivation {
Derivation {
geometry: self.geometry.clone(),
axes: self.axes.to_vec(),
batches: self.batches.to_vec(),
projection: self.projection.clone(),
width: self.width,
boundary: self.boundary,
packing: self.packing,
delivery: self.delivery,
in_stride_order: self.in_stride_order,
stored: self.stored,
partitioning: self.partitioning.clone(),
space: self.space.clone(),
cube_dim: self.cube_dim,
}
}
}
impl Equivalent<Derivation> for DerivationView<'_> {
fn equivalent(&self, kept: &Derivation) -> bool {
*self.geometry == kept.geometry
&& self.axes == kept.axes
&& self.batches == kept.batches
&& *self.projection == kept.projection
&& self.width == kept.width
&& self.boundary == kept.boundary
&& self.packing == kept.packing
&& self.delivery == kept.delivery
&& self.in_stride_order == kept.in_stride_order
&& self.stored == kept.stored
&& *self.partitioning == kept.partitioning
&& *self.space == kept.space
&& self.cube_dim == kept.cube_dim
}
}