use std::marker::PhantomData;
use crate::components::global::memory::GlobalIterator;
use crate::components::global::read::{AsyncLoadingJob, LoadingValidation};
use crate::components::global::{CopyMechanism, GlobalConfig};
use crate::components::stage::TilingLayout;
use crate::components::stage::{self, StridedStage};
use crate::components::{MatmulIdent, MatrixPrecision};
use cubecl_core as cubecl;
use cubecl_core::prelude::barrier::BarrierLevel;
use cubecl_core::prelude::*;
use cubecl_std::{
CubeOption, CubeOptionExpand,
tensor::{View, layout::Coords2d},
};
#[cube]
pub trait AsyncFullLoadingStrategy: 'static + Send + Sync + Clone + LoadingValidation {
type TilingLayout: TilingLayout;
type Job<IP: MatrixPrecision>: AsyncLoadingJob<IP, Self::TilingLayout>;
fn new_job<IP: MatrixPrecision, G: GlobalConfig>(
#[comptime] ident: MatmulIdent,
#[comptime] config: G,
) -> Self::Job<IP>;
fn barrier_level() -> BarrierLevel;
}
#[derive(CubeType)]
pub struct AsyncFullStageGlobalReader<
IP: MatrixPrecision,
CM: CopyMechanism,
S: stage::StageConfig,
L: AsyncFullLoadingStrategy,
G: GlobalConfig,
> {
tensor_reader: GlobalIterator<Line<IP::Global>>,
stage_memory: StridedStage<IP::Stage, L::TilingLayout>,
loading_job: CubeOption<L::Job<IP>>,
#[cube(comptime)]
ident: MatmulIdent,
#[cube(comptime)]
_phantom: PhantomData<(S, L, CM, G)>,
}
#[cube]
impl<
IP: MatrixPrecision,
CM: CopyMechanism,
S: stage::StageConfig,
L: AsyncFullLoadingStrategy,
G: GlobalConfig,
> AsyncFullStageGlobalReader<IP, CM, S, L, G>
{
pub fn new(
view: View<Line<IP::Global>, Coords2d>,
k_step: u32,
#[comptime] ident: MatmulIdent,
#[comptime] config: G,
) -> Self {
let mut stage_memory = StridedStage::new(
comptime!(ident.into_stage()),
config.stage_memory_config(ident),
);
let (shape_row, shape_col) = view.shape();
let tensor_reader = GlobalIterator::new(view, k_step, ident.view_direction(), true);
let loading_job = match config.precompute_job() {
true => CubeOption::new_Some(L::new_job::<IP, G>(ident, config)),
false => CubeOption::new_None(),
};
match ident {
MatmulIdent::Lhs =>
{
#[allow(clippy::collapsible_if)]
if config.check_row_bounds(ident) {
if shape_row < config.tiling_scheme().elements_in_stage_m() {
stage_memory.clear_all::<G>(ident, config);
}
}
}
MatmulIdent::Rhs =>
{
#[allow(clippy::collapsible_if)]
if config.check_col_bounds(ident) {
if shape_col < config.tiling_scheme().elements_in_stage_n() {
stage_memory.clear_all::<G>(ident, config);
}
}
}
MatmulIdent::Out => comptime!(unreachable!()),
}
AsyncFullStageGlobalReader::<IP, CM, S, L, G> {
tensor_reader,
stage_memory,
loading_job,
ident,
_phantom: PhantomData,
}
}
pub fn load_stage(&mut self, mechanism: &CM, #[comptime] config: G) {
let mut loading_job = match self.loading_job {
CubeOption::Some(loading_job) => loading_job,
CubeOption::None => L::new_job::<IP, G>(self.ident, config),
};
let len = L::Job::task_count(&loading_job);
for task_id in 0..len {
L::Job::<IP>::execute_task::<CM, G>(
&mut loading_job,
task_id,
&self.tensor_reader,
&mut self.stage_memory,
mechanism,
config,
);
}
}
pub fn clear_stage(&mut self, #[comptime] config: G) {
self.stage_memory.clear_all::<G>(self.ident, config)
}
pub fn stage(&self) -> StridedStage<IP::Stage, L::TilingLayout> {
self.stage_memory
}
pub fn advance_view(&mut self) {
self.tensor_reader.advance();
}
}