Skip to main content

rudnn/convolution/kernels/forward/
launch.rs

1use ruda_kernel::dsl as kernel_dsl;
2use crate::convolution::components::{ConvolutionProblem, Dimensionality};
3use crate::convolution::routines::Routine;
4use crate::convolution::{components::ConvSetupError, kernels::forward::selector::launch_kernel_concrete};
5use crate::convolution::{
6    components::ConvolutionOperation, components::global::args::RuntimeArgs,
7    forward::args::ConcreteArgs, launch::ConvolutionArgs,
8};
9use ruda_kernel::dsl::Runtime;
10use ruda_kernel::dsl::client::ComputeClient;
11use ruda_kernel::dsl::prelude::*;
12use rublas::kernel_ir::definition::{AvailableVectorSizes, MatmulElems};
13use rublas::kernel_ir::routines::BlueprintStrategy;
14use ruda_kernel::tiling::{InputBinding, MatrixLayout};
15
16/// Forward-convolution dispatch helper.
17///
18/// Called by `rudnn::convolution::launch_ref` after the routine and
19/// blueprint-strategy have been resolved. Not meant for direct external use.
20#[allow(clippy::result_large_err, clippy::too_many_arguments)]
21pub(crate) fn launch_internal<R: Runtime, const N_SPATIAL: usize, Rt: Routine>(
22    client: &ComputeClient<R>,
23    input: InputBinding<R>,
24    weight: InputBinding<R>,
25    bias: Option<InputBinding<R>>,
26    out: TensorBinding<R>,
27    args: ConvolutionArgs<N_SPATIAL>,
28    blueprint_strategy: &BlueprintStrategy<RuntimeArgs, Rt::MatmulRoutine>,
29    dtypes: MatmulElems,
30) -> Result<(), ConvSetupError>
31where
32    Rt::Args: ConcreteArgs<Rt::MatmulRoutine>,
33{
34    let ConvolutionArgs {
35        stride,
36        padding,
37        dilation,
38    } = args;
39
40    let dimensionality = match N_SPATIAL {
41        1 => Dimensionality::Dim1,
42        2 => Dimensionality::Dim2,
43        3 => Dimensionality::Dim3,
44        other => unimplemented!("Unsupported dimensionality {other}"),
45    };
46
47    launch_with_routine::<R, Rt>(
48        client,
49        input,
50        weight,
51        bias,
52        out,
53        (&stride, &padding, &dilation),
54        dimensionality,
55        blueprint_strategy,
56        dtypes,
57    )
58}
59
60#[allow(clippy::too_many_arguments)]
61fn launch_with_routine<R: Runtime, Rt: Routine>(
62    client: &ComputeClient<R>,
63    input: InputBinding<R>,
64    weight: InputBinding<R>,
65    bias: Option<InputBinding<R>>,
66    out: TensorBinding<R>,
67    (stride, padding, dilation): (&[usize], &[usize], &[usize]),
68    dimensionality: Dimensionality,
69    blueprint_strategy: &BlueprintStrategy<RuntimeArgs, Rt::MatmulRoutine>,
70    dtypes: MatmulElems,
71) -> Result<(), ConvSetupError>
72where
73    Rt::Args: ConcreteArgs<Rt::MatmulRoutine>,
74{
75    let rank = input.data().shape.len();
76    let dim_c = rank - 1;
77
78    let n = input.data().shape[0];
79    let c = input.data().shape[dim_c];
80
81    let out_c = weight.data().shape[0];
82
83    let in_shape = &input.data().shape[1..dim_c];
84    let kernel_shape = &weight.data().shape[1..dim_c];
85    let out_shape = &out.shape[1..dim_c];
86
87    let op = ConvolutionOperation::Forward;
88
89    let input_data = Rt::correct_layout(client, input.clone().into_data(), dtypes.lhs_global, op)?;
90    let weight_data =
91        Rt::correct_layout(client, weight.clone().into_data(), dtypes.rhs_global, op)?;
92
93    let mut input = input.clone();
94    let mut weight = weight.clone();
95
96    *input.data_mut() = input_data;
97    *weight.data_mut() = weight_data;
98
99    let address_type = input
100        .required_address_type()
101        .max(weight.required_address_type())
102        .max(
103            bias.clone()
104                .map(|bias| bias.required_address_type())
105                .unwrap_or_default(),
106        )
107        .max(out.required_address_type(dtypes.acc_global.size()));
108
109    let problem = ConvolutionProblem {
110        m: n * out_shape.iter().product::<usize>(),
111        n: out_c,
112        k: c * kernel_shape.iter().product::<usize>(),
113        lhs_strides: input.data().strides.clone(),
114        rhs_strides: weight.data().strides.clone(),
115        lhs_layout: MatrixLayout::RowMajor,
116        rhs_layout: MatrixLayout::ColMajor,
117        kernel_size: kernel_shape.iter().map(|it| *it as u32).collect(),
118        stride: stride.iter().map(|it| *it as u32).collect(),
119        padding: padding.iter().map(|it| *it as i32).collect(),
120        dilation: dilation.iter().map(|it| *it as u32).collect(),
121
122        batches: n,
123        in_shape: in_shape.into(),
124        out_shape: out_shape.into(),
125        channels: c,
126        out_channels: out_c,
127
128        padded_channels: c,
129        operation: op,
130
131        dimensionality,
132        global_dtypes: dtypes.as_global_elems(),
133        address_type,
134    };
135
136    launch_kernel::<R, Rt>(
137        client,
138        input,
139        weight,
140        bias,
141        out,
142        problem,
143        blueprint_strategy,
144        dtypes,
145    )
146}
147
148#[allow(clippy::result_large_err, clippy::too_many_arguments)]
149pub fn launch_kernel<R: Runtime, Rt: Routine>(
150    client: &ComputeClient<R>,
151    input: InputBinding<R>,
152    weight: InputBinding<R>,
153    bias: Option<InputBinding<R>>,
154    out: TensorBinding<R>,
155    problem: ConvolutionProblem,
156    blueprint_strategy: &BlueprintStrategy<RuntimeArgs, Rt::MatmulRoutine>,
157    dtypes: MatmulElems,
158) -> Result<(), ConvSetupError>
159where
160    Rt::Args: ConcreteArgs<Rt::MatmulRoutine>,
161{
162    // Shape/strides are treated as k-major, with the last dim always being the contiguous one.
163    // So for the sake of selecting a vector size, the shape/strides are always row-major.
164    let vector_sizes = AvailableVectorSizes::from_type_sizes(
165        client,
166        input.data_elem_size(),
167        weight.data_elem_size(),
168        dtypes.acc_global.size(),
169    )
170    .filter_lhs_with_tensor(
171        &input.data().strides,
172        &input.data().shape,
173        MatrixLayout::RowMajor,
174    )
175    .filter_rhs_with_tensor(
176        &weight.data().strides,
177        &weight.data().shape,
178        MatrixLayout::RowMajor,
179    )
180    .filter_out_with_tensor(&out.strides, &out.shape);
181
182    let mut vector_sizes = Rt::filter_vector_sizes(vector_sizes).pick_max()?;
183
184    // The large vector size resulting from dequantizing ends up slower due to restrictions on
185    // algorithms. Use this as a quick and dirty fix.
186    if input.scale().is_some() {
187        vector_sizes.lhs = 1;
188    }
189    if weight.scale().is_some() {
190        vector_sizes.rhs = 1;
191    }
192
193    launch_kernel_concrete::<R, Rt::Args, Rt::MatmulRoutine>(
194        client,
195        input,
196        weight,
197        bias,
198        out,
199        problem,
200        vector_sizes,
201        blueprint_strategy,
202        &dtypes,
203    )
204}