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