1use std::marker::PhantomData;
2
3use crate::{
4 components::global::multi_stage::JobExecutor,
5 components::global::multi_stage::LoadMaxRoundPlaneCount,
6 components::global::read::LoadingJob,
7 components::global::read::LoadingValidation,
8 components::global::read::StageBuffer,
9 components::global::read::SyncStrategy,
10 components::global::read::TaskCounter,
11 components::global::{multi_stage::JobIterator, read::FullLoaderStage},
12 components::{global::memory::GlobalIterator, stage::LoadStageFamily},
13 {args::RuntimeConfig, components::global::GlobalReaderConfig},
14};
15use cubecl::{
16 prelude::*,
17 std::tensor::{View, layout::Coords2d},
18};
19use cubek_std::tile::TilingLayout;
20
21pub type SyncBarrier<S> = <S as SyncStrategy>::Barrier;
22
23#[cube]
24pub trait FullLoadingStrategy<RC: RuntimeConfig>:
26 'static + Send + Sync + Clone + LoadingValidation + LoadMaxRoundPlaneCount
27{
28 type TilingLayout: TilingLayout;
30 type SyncStrategy: SyncStrategy;
32 type Stage: LoadStageFamily;
33
34 type Job<EG: Numeric, NG: Size, ES: Numeric, NS: Size>: LoadingJob<EG, NG, ES, NS, Self::TilingLayout, Self::SyncStrategy, Stage = Self::Stage>;
36
37 const SHOULD_CLEAR: bool = false;
38
39 fn new_job<EG: Numeric, NG: Size, ES: Numeric, NS: Size>(
41 config: RC,
42 #[comptime] config: GlobalReaderConfig,
43 ) -> Self::Job<EG, NG, ES, NS>;
44}
45
46#[derive(Clone, CubeType)]
47#[expand(derive(Clone))]
48pub struct FullStageGlobalReader<
53 'a,
54 EG: Numeric,
55 NG: Size,
56 ES: Numeric,
57 NS: Size,
58 RC: RuntimeConfig,
59 L: FullLoadingStrategy<RC>,
60> {
61 global_iter: GlobalIterator<'a, Vector<EG, NG>>,
62 runtime_config: RC,
63 stage: FullLoaderStage<RC, L, ES, NS>,
64 loading_job: ComptimeOption<L::Job<EG, NG, ES, NS>>,
65 #[cube(comptime)]
66 _phantom: PhantomData<L>,
67}
68
69#[cube]
70impl<
71 'a,
72 EG: Numeric,
73 NG: Size,
74 ES: Numeric,
75 NS: Size,
76 RC: RuntimeConfig,
77 L: FullLoadingStrategy<RC>,
78> FullStageGlobalReader<'a, EG, NG, ES, NS, RC, L>
79{
80 pub fn new(
82 view: View<'a, Vector<EG, NG>, Coords2d>,
83 runtime_config: RC,
84 k_step: u32,
85 #[comptime] config: GlobalReaderConfig,
86 ) -> Self {
87 let stage = L::Stage::create(128usize, config.smem_config);
90
91 let global_iter =
92 GlobalIterator::new(view, k_step, config.gmem_config.view_direction, false);
93
94 let loading_job = match config.precompute_job {
95 true => ComptimeOption::new_Some(L::new_job::<EG, NG, ES, NS>(
96 runtime_config.clone(),
97 config,
98 )),
99 false => ComptimeOption::new_None(),
100 };
101
102 FullStageGlobalReader::<'a, EG, NG, ES, NS, RC, L> {
103 global_iter,
104 runtime_config,
105 stage,
106 loading_job,
107 _phantom: PhantomData::<L>,
108 }
109 }
110
111 pub fn stage(&self) -> FullLoaderStage<RC, L, ES, NS> {
113 L::Stage::with_buffer_index(&self.stage, 0)
114 }
115
116 pub fn free_stage(self) {
118 L::Stage::free(&self.stage);
119 }
120
121 pub fn advance_view(&mut self) {
123 self.global_iter.advance();
124 }
125
126 pub fn load_stage(
128 &mut self,
129 barrier: &SyncBarrier<L::SyncStrategy>,
130 #[comptime] config: GlobalReaderConfig,
131 ) {
132 let mut loading_job = self
133 .loading_job
134 .clone()
135 .unwrap_or_else(|| L::new_job::<EG, NG, ES, NS>(self.runtime_config.clone(), config));
136
137 let len = L::Job::task_count(&loading_job);
138
139 #[unroll]
140 for task_id in 0..len {
141 L::Job::<EG, NG, ES, NS>::execute_task(
142 &mut loading_job,
143 task_id,
144 &self.global_iter,
145 &mut self.stage,
146 barrier,
147 config,
148 );
149 }
150 }
151}
152
153#[cube]
154impl<EG: Numeric, NG: Size, ES: Numeric, NS: Size, RC: RuntimeConfig, L: FullLoadingStrategy<RC>>
155 JobExecutor<L::SyncStrategy> for FullStageGlobalReader<'_, EG, NG, ES, NS, RC, L>
156{
157 type JobIterator = FullStageJobIterator<EG, NG, ES, NS, RC, L>;
158
159 fn create_job_iterator(
160 this: &Self,
161 #[comptime] _stage_buffer: StageBuffer,
162 #[comptime] config: GlobalReaderConfig,
163 ) -> Self::JobIterator {
164 let job = this
165 .loading_job
166 .clone()
167 .unwrap_or_else(|| L::new_job::<EG, NG, ES, NS>(this.runtime_config.clone(), config));
168
169 let num_tasks = L::Job::task_count(&job);
170
171 FullStageJobIterator::<EG, NG, ES, NS, RC, L> {
172 job,
173 num_tasks,
174 current: ComptimeCell::new(TaskCounter { counter: 0u32 }),
175 }
176 }
177
178 fn execute_task(
179 this: &mut Self,
180 job_iterator: &mut FullStageJobIterator<EG, NG, ES, NS, RC, L>,
181 barrier: &SyncBarrier<L::SyncStrategy>,
182 #[comptime] config: GlobalReaderConfig,
183 ) {
184 let task_id = job_iterator.current.read().counter.comptime();
185
186 L::Job::<EG, NG, ES, NS>::execute_task(
187 &mut job_iterator.job,
188 task_id,
189 &this.global_iter,
190 &mut this.stage,
191 barrier,
192 config,
193 );
194
195 job_iterator.current.store(TaskCounter {
196 counter: task_id + 1,
197 });
198 }
199
200 fn execute_all_remaining_tasks(
201 this: &mut Self,
202 job_iterator: &mut Self::JobIterator,
203 barrier: &SyncBarrier<L::SyncStrategy>,
204 #[comptime] config: GlobalReaderConfig,
205 ) {
206 let task_counter = job_iterator.current.read().counter;
207
208 #[unroll]
209 for task_id in task_counter..job_iterator.num_tasks {
210 L::Job::<EG, NG, ES, NS>::execute_task(
211 &mut job_iterator.job,
212 task_id,
213 &this.global_iter,
214 &mut this.stage,
215 barrier,
216 config,
217 );
218 }
219
220 job_iterator.current.store(TaskCounter {
221 counter: job_iterator.num_tasks,
222 });
223 }
224
225 fn execute_whole_job(
226 this: &mut Self,
227 barrier: &SyncBarrier<L::SyncStrategy>,
228 #[comptime] stage_buffer: StageBuffer,
229 #[comptime] config: GlobalReaderConfig,
230 ) {
231 let mut iter = Self::create_job_iterator(&*this, stage_buffer, config);
232 Self::execute_all_remaining_tasks(this, &mut iter, barrier, config);
233 }
234}
235
236#[derive(CubeType)]
237pub struct FullStageJobIterator<
239 EG: Numeric,
240 NG: Size,
241 ES: Numeric,
242 NS: Size,
243 RC: RuntimeConfig,
244 L: FullLoadingStrategy<RC>,
245> {
246 job: L::Job<EG, NG, ES, NS>,
247 #[cube(comptime)]
248 pub num_tasks: u32,
249 pub current: ComptimeCell<TaskCounter>,
250}
251
252#[cube]
253impl<EG: Numeric, NG: Size, ES: Numeric, NS: Size, RC: RuntimeConfig, L: FullLoadingStrategy<RC>>
254 JobIterator for FullStageJobIterator<EG, NG, ES, NS, RC, L>
255{
256 fn current(this: &Self) -> comptime_type!(u32) {
257 this.current.read().counter
258 }
259
260 fn num_tasks(this: &Self) -> comptime_type!(u32) {
261 this.num_tasks
262 }
263}