1use crate::{
2 AcceleratedTileKind, ReadingStrategy, algorithm::simple::*,
3 components::global::args::RuntimeArgs,
4};
5use crate::{
6 ConvolutionArgs, Strategy, components::ConvolutionOperation, forward::args::ConcreteArgs,
7};
8use crate::{
9 algorithm::Algorithm,
10 components::{ConvolutionProblem, Dimensionality},
11};
12use crate::{components::ConvSetupError, kernels::forward::selector::launch_kernel_concrete};
13use cubecl::{Runtime, client::ComputeClient, prelude::*, std::tensor::TensorHandle};
14use cubek_matmul::{
15 components::tile::{cmma::CmmaMatmul, io::Strided, mma::MmaMatmul},
16 definition::{AvailableLineSizes, MatmulElems, MatrixLayout},
17};
18use cubek_matmul::{definition, launch::MatmulInputHandleRef};
19use cubek_matmul::{launch::MatmulInputHandle, routines::BlueprintStrategy};
20use derive_new::new;
21
22macro_rules! with_tile_kind {
23 ($kind: expr, $T: ident, $launch: expr) => {
24 match $kind {
25 AcceleratedTileKind::Cmma => {
26 type $T = CmmaMatmul<Option<Strided>>;
27 ($launch)()
28 }
29 AcceleratedTileKind::Mma => {
30 type $T = MmaMatmul<Strided, Strided, Option<Strided>>;
31 ($launch)()
32 }
33 }
34 };
35}
36
37#[allow(clippy::result_large_err, clippy::too_many_arguments)]
38pub fn launch<R: Runtime, const N_SPATIAL: usize>(
39 strategy: &Strategy,
40 client: &ComputeClient<R>,
41 input: MatmulInputHandle<R>,
42 weight: MatmulInputHandle<R>,
43 bias: Option<MatmulInputHandle<R>>,
44 out: TensorHandle<R>,
45 args: ConvolutionArgs<N_SPATIAL>,
46 dtypes: MatmulElems,
47) -> Result<(), ConvSetupError> {
48 launch_ref(
49 strategy,
50 client,
51 &input.as_ref(),
52 &weight.as_ref(),
53 &bias.as_ref().map(|it| it.as_ref()),
54 &out.as_ref(),
55 args,
56 dtypes,
57 )
58}
59
60#[allow(clippy::result_large_err, clippy::too_many_arguments)]
69pub fn launch_ref<R: Runtime, const N_SPATIAL: usize>(
70 strategy: &Strategy,
71 client: &ComputeClient<R>,
72 input: &MatmulInputHandleRef<'_, R>,
73 weight: &MatmulInputHandleRef<'_, R>,
74 bias: &Option<MatmulInputHandleRef<'_, R>>,
75 out: &TensorHandleRef<'_, R>,
76 args: ConvolutionArgs<N_SPATIAL>,
77 dtypes: MatmulElems,
78) -> Result<(), ConvSetupError> {
79 let conv = Convolution::new(client, input, weight, bias, out, args, dtypes);
80
81 match strategy {
82 Strategy::Simple {
83 read_strategy,
84 tile_kind,
85 } => with_tile_kind!(tile_kind, Accelerated, || match read_strategy {
86 ReadingStrategy::Cyclic => conv.launch::<SimpleSyncCyclicConv<Accelerated>>(),
87 ReadingStrategy::Strided => conv.launch::<SimpleSyncStridedConv<Accelerated>>(),
88 ReadingStrategy::Tilewise => conv.launch::<SimpleSyncTilewiseConv<Accelerated>>(),
89 ReadingStrategy::AsyncCyclic => conv.launch::<SimpleAsyncCyclicConv<Accelerated>>(),
90 ReadingStrategy::AsyncStrided => conv.launch::<SimpleAsyncStridedConv<Accelerated>>(),
91 ReadingStrategy::Tma => conv.launch::<SimpleAsyncTmaConv<Accelerated>>(),
92 }),
93 }
94}
95
96#[derive(new)]
97struct Convolution<'a, R: Runtime, const N_SPATIAL: usize> {
98 client: &'a ComputeClient<R>,
99 input: &'a MatmulInputHandleRef<'a, R>,
100 weight: &'a MatmulInputHandleRef<'a, R>,
101 bias: &'a Option<MatmulInputHandleRef<'a, R>>,
102 out: &'a TensorHandleRef<'a, R>,
103 args: ConvolutionArgs<N_SPATIAL>,
104 dtypes: MatmulElems,
105}
106
107impl<'a, R: Runtime, const N_SPATIAL: usize> Convolution<'a, R, N_SPATIAL> {
108 fn launch<Alg: Algorithm>(self) -> Result<(), ConvSetupError>
109 where
110 Alg::Args: ConcreteArgs<Alg::Routine>,
111 {
112 let ConvolutionArgs {
113 stride,
114 padding,
115 dilation,
116 } = self.args;
117
118 let dimensionality = match N_SPATIAL {
119 1 => Dimensionality::Dim1,
120 2 => Dimensionality::Dim2,
121 3 => Dimensionality::Dim3,
122 other => unimplemented!("Unsupported dimensionality {other}"),
123 };
124
125 launch_with_algorithm::<R, Alg>(
126 self.client,
127 self.input,
128 self.weight,
129 self.bias,
130 self.out,
131 (&stride, &padding, &dilation),
132 dimensionality,
133 &BlueprintStrategy::Inferred(Default::default()),
134 self.dtypes,
135 )
136 }
137}
138
139#[allow(clippy::too_many_arguments)]
140fn launch_with_algorithm<R: Runtime, Alg: Algorithm>(
141 client: &ComputeClient<R>,
142 input: &MatmulInputHandleRef<'_, R>,
143 weight: &MatmulInputHandleRef<'_, R>,
144 bias: &Option<MatmulInputHandleRef<'_, R>>,
145 out: &TensorHandleRef<'_, R>,
146 (stride, padding, dilation): (&[usize], &[usize], &[usize]),
147 dimensionality: Dimensionality,
148 blueprint_strategy: &BlueprintStrategy<RuntimeArgs, Alg::Routine>,
149 dtypes: MatmulElems,
150) -> Result<(), ConvSetupError>
151where
152 Alg::Args: ConcreteArgs<Alg::Routine>,
153{
154 let rank = input.data().shape.len();
155 let dim_c = rank - 1;
156
157 let n = input.data().shape[0];
158 let c = input.data().shape[dim_c];
159
160 let out_c = weight.data().shape[0];
161
162 let in_shape = &input.data().shape[1..dim_c];
163 let kernel_shape = &weight.data().shape[1..dim_c];
164 let out_shape = &out.shape[1..dim_c];
165
166 let op = ConvolutionOperation::Forward;
167
168 let input_data = Alg::into_tensor_handle(client, input.data(), dtypes.lhs_global, op)?;
169 let weight_data = Alg::into_tensor_handle(client, weight.data(), dtypes.rhs_global, op)?;
170
171 let mut input = *input;
172 let mut weight = *weight;
173
174 *input.data_mut() = input_data.as_ref();
175 *weight.data_mut() = weight_data.as_ref();
176
177 let address_type = input
178 .required_address_type()
179 .max(weight.required_address_type())
180 .max(
181 bias.map(|bias| bias.required_address_type())
182 .unwrap_or_default(),
183 )
184 .max(out.required_address_type());
185
186 let problem = ConvolutionProblem {
187 m: n * out_shape.iter().product::<usize>(),
188 n: out_c,
189 k: c * kernel_shape.iter().product::<usize>(),
190 lhs_strides: input.data().strides.into(),
191 rhs_strides: weight.data().strides.into(),
192 lhs_layout: definition::MatrixLayout::RowMajor,
193 rhs_layout: definition::MatrixLayout::ColMajor,
194 kernel_size: kernel_shape.iter().map(|it| *it as u32).collect(),
195 stride: stride.iter().map(|it| *it as u32).collect(),
196 padding: padding.iter().map(|it| *it as i32).collect(),
197 dilation: dilation.iter().map(|it| *it as u32).collect(),
198
199 batches: n,
200 in_shape: in_shape.into(),
201 out_shape: out_shape.into(),
202 channels: c,
203 out_channels: out_c,
204
205 padded_channels: c,
206 operation: op,
207
208 dimensionality,
209 global_dtypes: dtypes.as_global_elems(),
210 address_type,
211 };
212
213 launch_kernel::<R, Alg>(
214 client,
215 &input,
216 &weight,
217 bias,
218 out,
219 problem,
220 blueprint_strategy,
221 dtypes,
222 )
223}
224
225#[allow(clippy::result_large_err, clippy::too_many_arguments)]
226pub fn launch_kernel<R: Runtime, Alg: Algorithm>(
227 client: &ComputeClient<R>,
228 input: &MatmulInputHandleRef<'_, R>,
229 weight: &MatmulInputHandleRef<'_, R>,
230 bias: &Option<MatmulInputHandleRef<'_, R>>,
231 out: &TensorHandleRef<'_, R>,
232 problem: ConvolutionProblem,
233 blueprint_strategy: &BlueprintStrategy<RuntimeArgs, Alg::Routine>,
234 dtypes: MatmulElems,
235) -> Result<(), ConvSetupError>
236where
237 Alg::Args: ConcreteArgs<Alg::Routine>,
238{
239 let line_sizes = AvailableLineSizes::from_type_sizes(
242 client,
243 input.data().elem_size,
244 weight.data().elem_size,
245 out.elem_size,
246 )
247 .filter_lhs_with_tensor(
248 input.data().strides,
249 input.data().shape,
250 MatrixLayout::RowMajor,
251 )
252 .filter_rhs_with_tensor(
253 weight.data().strides,
254 weight.data().shape,
255 MatrixLayout::RowMajor,
256 )
257 .filter_out_with_tensor(out.strides, out.shape);
258
259 let mut line_sizes = Alg::filter_line_sizes(line_sizes).pick_max()?;
260
261 if input.scale().is_some() {
264 line_sizes.lhs = 1;
265 }
266 if weight.scale().is_some() {
267 line_sizes.rhs = 1;
268 }
269
270 launch_kernel_concrete::<R, Alg::Args, Alg::Routine>(
271 client,
272 input,
273 weight,
274 bias,
275 out,
276 problem,
277 line_sizes,
278 blueprint_strategy,
279 &dtypes,
280 )
281}