use super::StageBuffer;
use crate::components::global::CopyMechanism;
use crate::components::global::base::GlobalConfig;
use crate::components::global::memory::GlobalIterator;
use crate::components::global::multi_stage::double_buffering::DoubleBufferingGlobalConfig;
use crate::components::global::read::{AsyncLoadingJob, LoadingValidation};
use crate::components::stage::TilingLayout;
use crate::components::stage::{self, StridedStage};
use crate::components::{MatmulIdent, MatrixPrecision};
use core::marker::PhantomData;
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 AsyncPartialLoadingStrategy: 'static + Send + Sync + Clone + LoadingValidation {
type TilingLayout: TilingLayout;
type Job<IP: MatrixPrecision>: AsyncLoadingJob<IP, Self::TilingLayout>;
fn new_job<IP: MatrixPrecision, G: GlobalConfig>(
#[comptime] buffer_index: u32,
#[comptime] ident: MatmulIdent,
#[comptime] config: G,
) -> Self::Job<IP>;
fn barrier_level() -> BarrierLevel;
}
#[derive(CubeType)]
pub struct AsyncBufferGlobalReader<
IP: MatrixPrecision,
S: stage::StageConfig,
CM: CopyMechanism,
L: AsyncPartialLoadingStrategy,
> {
global_iter: GlobalIterator<Line<IP::Global>>,
stage: StridedStage<IP::Stage, L::TilingLayout>,
loading_job: CubeOption<(L::Job<IP>, L::Job<IP>)>,
#[cube(comptime)]
ident: MatmulIdent,
#[cube(comptime)]
_phantom: PhantomData<(S, CM)>,
}
#[cube]
impl<IP: MatrixPrecision, S: stage::StageConfig, CM: CopyMechanism, L: AsyncPartialLoadingStrategy>
AsyncBufferGlobalReader<IP, S, CM, L>
{
pub fn new(
tensor: View<Line<IP::Global>, Coords2d>,
k_step: u32,
#[comptime] ident: MatmulIdent,
#[comptime] config: DoubleBufferingGlobalConfig<S>,
) -> Self {
let stage = StridedStage::new(
comptime!(ident.into_stage()),
config.stage_memory_config(ident),
);
let global_iter = GlobalIterator::new(tensor, k_step, ident.view_direction(), true);
let loading_job = match config.precompute_job() {
true => CubeOption::new_Some((
L::new_job::<IP, DoubleBufferingGlobalConfig<S>>(0u32, ident, config),
L::new_job::<IP, DoubleBufferingGlobalConfig<S>>(1u32, ident, config),
)),
false => CubeOption::new_None(),
};
AsyncBufferGlobalReader::<IP, S, CM, L> {
global_iter,
stage,
loading_job,
ident,
_phantom: PhantomData::<(S, CM)>,
}
}
pub fn stage(
&mut self,
#[comptime] stage_buffer: StageBuffer,
) -> StridedStage<IP::Stage, L::TilingLayout> {
self.stage.with_buffer_index(stage_buffer.to_index())
}
pub fn advance_view(&mut self) {
self.global_iter.advance();
}
pub fn load_stage(
&mut self,
mechanism: &CM,
#[comptime] stage_buffer: StageBuffer,
#[comptime] config: DoubleBufferingGlobalConfig<S>,
) {
let mut loading_job = match self.loading_job {
CubeOption::Some(job) => match stage_buffer {
StageBuffer::A => job.0,
StageBuffer::B => job.1,
},
CubeOption::None => match stage_buffer {
StageBuffer::A => {
L::new_job::<IP, DoubleBufferingGlobalConfig<S>>(0u32, self.ident, config)
}
StageBuffer::B => {
L::new_job::<IP, DoubleBufferingGlobalConfig<S>>(1u32, self.ident, config)
}
},
};
let len = L::Job::task_count(&loading_job);
for task_id in 0..len {
L::Job::<IP>::execute_task::<CM, DoubleBufferingGlobalConfig<S>>(
&mut loading_job,
task_id,
&self.global_iter,
&mut self.stage,
mechanism,
config,
);
}
}
pub fn clear_stage(
&mut self,
#[comptime] stage_buffer: StageBuffer,
#[comptime] config: DoubleBufferingGlobalConfig<S>,
) {
self.stage
.clear_stage::<DoubleBufferingGlobalConfig<S>>(stage_buffer, self.ident, config)
}
}