1pub use ruda_core::tensor as zspace;
2use ruda_core::tensor::Shape;
3use ruda_core::tensor::Strides;
4
5pub mod frontend;
7pub mod io;
9
10pub mod post_processing;
11
12pub use ruda_core::future;
14
15use ruda_core::ir::VectorSize;
16use ruda::runtime::client::ComputeClient;
17pub use ruda::runtime::memory_management::MemoryConfiguration;
18use ruda::runtime::server::RudaCountSelection;
19pub use frontend::cmma;
20
21pub use ruda_core::ir as ir;
23
24pub mod codegen;
25pub mod compute;
26pub mod prelude;
27
28mod pod;
29
30pub use codegen::*;
31pub use ruda::runtime::backend::*;
32pub use pod::*;
33
34pub use ruda_kernel_macros::{
35 AutotuneKey, RudaLaunch, RudaType, RudaTypeMut, comment, comptime,
36 comptime_type, ruda, derive_ruda_comptime, derive_expand, intrinsic, terminate,
37};
38
39pub use ruda::runtime::benchmark;
40pub use ruda::runtime::client;
41pub use ruda::runtime::compiler::{CompilationError, Compiler, RudaTask};
42pub use ruda::runtime::memory_management::MemoryUsage;
43pub use ruda::runtime::server;
44pub use ruda::runtime::tune;
45
46use frontend::LaunchArg;
47
48pub use ruda_core::*;
49
50pub use prelude::RudaCount;
51pub use prelude::{RudaDim, ExecutionMode};
52
53pub use num_traits;
54
55mod id;
56pub use id::*;
57
58#[doc(hidden)]
60pub mod __private {
61 pub use alloc::{format, vec};
62 pub use paste::paste;
63}
64
65pub use prelude::{Assign, IntoRuntime};
66
67pub fn calculate_ruda_count_elemwise<R: Runtime>(
70 client: &ComputeClient<R>,
71 num_elems: usize,
72 ruda_dim: RudaDim,
73) -> RudaCount {
74 if num_elems == 0 {
75 return RudaCount::Static(0, 0, 0);
76 }
77 let num_rudas = num_elems.div_ceil(ruda_dim.num_elems() as usize);
78 RudaCountSelection::new(client, num_rudas as u32).ruda_count()
79}
80
81pub fn tensor_vectorization_factor(
82 factors: &[VectorSize],
83 shape: &Shape,
84 strides: &Strides,
85 dim: usize,
86) -> VectorSize {
87 tensor_vector_size_parallel(factors.iter().cloned(), shape, strides, dim)
88}
89pub fn tensor_vectorization(
90 factors: &[VectorSize],
91 shape: &Shape,
92 strides: &Strides,
93 dim: usize,
94) -> VectorSize {
95 tensor_vector_size_parallel(factors.iter().cloned(), shape, strides, dim)
96}
97
98#[derive(Debug, Clone)]
99pub enum VectorizationError {
100 AxisOutOfBounds,
101 StrideMismatch,
102 NoValidVectorization,
103}
104
105pub fn tensor_vector_size_parallel(
118 optimized_vector_sizes: impl Iterator<Item = VectorSize>,
119 shape: &Shape,
120 strides: &Strides,
121 axis: usize,
122) -> VectorSize {
123 try_tensor_vector_size_parallel(optimized_vector_sizes, shape, strides, axis).unwrap_or(1)
124}
125
126pub fn try_tensor_vector_size_parallel(
128 supported_vector_sizes: impl Iterator<Item = VectorSize>,
129 shape: &Shape,
130 strides: &Strides,
131 axis: usize,
132) -> Result<VectorSize, VectorizationError> {
133 let stride = strides
134 .get(axis)
135 .ok_or(VectorizationError::AxisOutOfBounds)?;
136 if *stride != 1 {
137 return Err(VectorizationError::StrideMismatch);
138 }
139
140 let axis_shape = shape.get(axis).ok_or(VectorizationError::AxisOutOfBounds)?;
141
142 supported_vector_sizes
149 .filter(|&vector_size| {
150 vector_size != 0
151 && axis_shape % vector_size == 0
152 && strides
153 .iter()
154 .enumerate()
155 .all(|(i, &stride)| i == axis || stride % vector_size == 0)
156 })
157 .max()
158 .ok_or(VectorizationError::NoValidVectorization)
159}
160
161pub fn tensor_vector_size_perpendicular(
171 supported_vector_sizes: impl Iterator<Item = VectorSize>,
172 shape: &[usize],
173 strides: &[usize],
174 axis: usize,
175) -> VectorSize {
176 try_tensor_vector_sizes_perpendicular(supported_vector_sizes, shape, strides, axis).unwrap_or(1)
177}
178
179pub fn try_tensor_vector_sizes_perpendicular(
181 supported_vector_sizes: impl Iterator<Item = VectorSize>,
182 shape: &[usize],
183 strides: &[usize],
184 axis: usize,
185) -> Result<VectorSize, VectorizationError> {
186 let axis_stride = *strides
187 .get(axis)
188 .ok_or(VectorizationError::AxisOutOfBounds)?;
189 shape.get(axis).ok_or(VectorizationError::AxisOutOfBounds)?;
190 if shape.len() != strides.len() || axis_stride == 0 {
191 return Err(VectorizationError::StrideMismatch);
192 }
193
194 let mut inner_axes = strides
195 .iter()
196 .zip(shape.iter())
197 .filter_map(|(&stride, &size)| {
198 (stride < axis_stride && size != 1).then_some((stride, size))
199 })
200 .collect::<alloc::vec::Vec<_>>();
201 inner_axes.sort_unstable_by_key(|&(stride, _)| stride);
202
203 let mut span = 1usize;
204 for (stride, size) in inner_axes {
205 if stride != span {
206 return Err(VectorizationError::StrideMismatch);
207 }
208 span = span.checked_mul(size).ok_or(VectorizationError::StrideMismatch)?;
209 }
210 if axis_stride != span {
211 return Err(VectorizationError::StrideMismatch);
212 }
213
214 supported_vector_sizes
215 .filter(|&vector_size| {
216 vector_size != 0
217 && axis_stride % vector_size == 0
218 && strides.iter().all(|&stride| stride < axis_stride || stride % vector_size == 0)
219 })
220 .max()
221 .ok_or(VectorizationError::NoValidVectorization)
222}
223
224pub type RuntimeArg<T, R> = <T as LaunchArg>::RuntimeArg<R>;
226pub type ExpandType<T> = <T as crate::dsl::prelude::RudaType>::ExpandType;
227
228#[cfg(feature = "frontend-tests")]
229pub mod runtime_tests;
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 fn try_parallel(
237 sizes: &[VectorSize],
238 shape: &[usize],
239 strides: &[usize],
240 axis: usize,
241 ) -> Result<VectorSize, VectorizationError> {
242 try_tensor_vector_size_parallel(
243 sizes.iter().copied(),
244 &Shape::from(shape.iter().copied()),
245 &Strides::new(strides),
246 axis,
247 )
248 }
249
250 #[test]
251 fn parallel_contiguous_picks_max_vector_size() {
252 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[36, 4, 1], 2).unwrap();
255 assert_eq!(v, 4);
256 }
257
258 #[test]
259 fn parallel_unfold_step_one_rejects_vectorization() {
260 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[12, 1, 1], 2).unwrap();
266 assert_eq!(v, 1);
267 }
268
269 #[test]
270 fn parallel_unfold_step_two_allows_vectorization() {
271 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[12, 2, 1], 2).unwrap();
275 assert_eq!(v, 2);
276 }
277
278 #[test]
279 fn parallel_broadcast_dim_ignored() {
280 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[0, 4, 1], 2).unwrap();
283 assert_eq!(v, 4);
284 }
285
286 #[test]
287 fn parallel_axis_stride_not_one_is_error() {
288 let err = try_parallel(&[1, 2, 4], &[1, 9, 4], &[36, 1, 4], 2).unwrap_err();
289 assert!(matches!(err, VectorizationError::StrideMismatch));
290 }
291}
292
293pub use crate::{unexpanded, expand_error, expand_assert, size, define, debug_print, debug_print_expand, define_scalar, define_size};
294
295#[cfg(feature = "frontend-tests")]
296pub use crate::{testgen_all_reduce, testgen_assign, testgen_atomic_untyped, testgen_atomic_int, testgen_atomic_float, testgen_barrier, testgen_binary, testgen_binary_untyped, testgen_branch, testgen_cluster, testgen_cmma, testgen_comparison, testgen_const_match, testgen_constants, testgen_debug, testgen_different_rank, testgen_enums, testgen_file, testgen_index, testgen_launch, testgen_launch_untyped, testgen_metadata, testgen_minifloat, testgen_all, testgen_float, testgen_int, testgen_uint, testgen_untyped, as_bytes, as_type, testgen_numeric, testgen_plane, testgen_properties, testgen_saturating_uint, testgen_saturating_int, testgen_sequence, testgen_slice, testgen_stream, testgen_sync_plane, testgen_tensor_indexing, testgen_tensormap, testgen_to_client, testgen_topology, testgen_unary, testgen_unary_int, testgen_unroll, testgen_vector};
297
298pub mod lowering;