use crate::components::{
InvalidConfigError, MatmulIdent, MatrixLayout, MatrixPrecision,
global::{
CopyMechanism, GlobalConfig,
memory::{GlobalIterator, load_window_in_stage},
read::AsyncFullLoadingStrategy,
},
stage::{StridedStage, StridedTilingLayout, TilingValidation},
};
use cubecl_core::prelude::*;
use cubecl_core::{self as cubecl, prelude::barrier::BarrierLevel};
use super::{AsyncLoadingJob, LoadingValidation};
#[derive(CubeType, Clone, Copy)]
pub struct AsyncFullMaximizeSliceLengthLoading {}
impl LoadingValidation for AsyncFullMaximizeSliceLengthLoading {
fn check<C: GlobalConfig>(config: &C, ident: MatmulIdent) -> Result<(), InvalidConfigError> {
StridedTilingLayout::check(config.global_memory_config(ident))?;
Ok(())
}
}
#[cube]
impl AsyncFullLoadingStrategy for AsyncFullMaximizeSliceLengthLoading {
type TilingLayout = StridedTilingLayout;
type Job<IP: MatrixPrecision> = AsynFullMaximizeSliceLengthJob;
fn new_job<IP: MatrixPrecision, G: GlobalConfig>(
#[comptime] ident: MatmulIdent,
#[comptime] config: G,
) -> AsynFullMaximizeSliceLengthJob {
let matrix_layout = config.matrix_layout(ident);
let num_slices = match matrix_layout {
MatrixLayout::RowMajor => config.tiling_scheme().elements_in_stage_row(ident),
MatrixLayout::ColMajor => config.tiling_scheme().elements_in_stage_col(ident),
};
let unit_count = config.plane_dim() * config.num_loading_planes(ident);
let num_tasks_per_unit = comptime!(div_ceil(num_slices, unit_count));
AsynFullMaximizeSliceLengthJob {
num_tasks_per_unit,
unit_count,
num_slices,
ident,
}
}
fn barrier_level() -> BarrierLevel {
BarrierLevel::cube_manual(0u32)
}
}
#[derive(CubeType, Clone, Copy)]
pub struct AsynFullMaximizeSliceLengthJob {
#[cube(comptime)]
num_tasks_per_unit: u32,
#[cube(comptime)]
unit_count: u32,
#[cube(comptime)]
num_slices: u32,
#[cube(comptime)]
ident: MatmulIdent,
}
#[cube]
impl<IP: MatrixPrecision> AsyncLoadingJob<IP, StridedTilingLayout>
for AsynFullMaximizeSliceLengthJob
{
fn execute_task<CM: CopyMechanism, G: GlobalConfig>(
this: &mut Self,
task_id: u32,
tensor_reader: &GlobalIterator<Line<IP::Global>>,
stage: &mut StridedStage<IP::Stage, StridedTilingLayout>,
mechanism: &CM,
#[comptime] config: G,
) {
let nth_slice = this.unit_count * task_id + UNIT_POS;
#[allow(clippy::collapsible_else_if)]
if comptime!(this.num_slices.is_multiple_of(this.unit_count)) {
load_nth_slice::<IP::Global, IP::Stage, CM, G>(
nth_slice,
tensor_reader,
stage,
mechanism,
this.ident,
config,
);
} else {
if nth_slice < this.num_slices {
load_nth_slice::<IP::Global, IP::Stage, CM, G>(
nth_slice,
tensor_reader,
stage,
mechanism,
this.ident,
config,
);
}
};
}
fn task_count(this: &Self) -> comptime_type!(u32) {
this.num_tasks_per_unit
}
}
#[cube]
fn load_nth_slice<EG: Numeric, ES: Numeric, CM: CopyMechanism, G: GlobalConfig>(
nth_slice: u32,
global_iter: &GlobalIterator<Line<EG>>,
stage: &mut StridedStage<ES, StridedTilingLayout>,
mechanism: &CM,
#[comptime] ident: MatmulIdent,
#[comptime] config: G,
) {
let window = load_window_in_stage(
&global_iter.view(),
nth_slice,
comptime!(config.global_memory_config(ident)),
);
let mut destination: SliceMut<Line<ES>> = StridedTilingLayout::nth_slice::<ES>(
stage,
nth_slice,
comptime!(config.stage_memory_config(ident)),
);
CM::memcpy_async(mechanism, &window.try_cast_unchecked(), &mut destination);
}