1#![no_std]
2
3#[cfg(feature = "std")]
4extern crate std;
5
6extern crate alloc;
7
8#[macro_use]
9extern crate derive_new;
10
11pub use cubecl_zspace as zspace;
12use cubecl_zspace::Shape;
13use cubecl_zspace::Strides;
14
15pub mod frontend;
17pub mod io;
19
20pub mod post_processing;
21
22pub use cubecl_environment as environment;
24pub use cubecl_environment::future;
25
26use cubecl_ir::VectorSize;
27use cubecl_runtime::client::Client;
28pub use cubecl_runtime::memory_management::MemoryConfiguration;
29use cubecl_runtime::server::CubeCountSelection;
30pub use frontend::cmma;
31pub use frontend::wgmma;
32
33pub use cubecl_ir as ir;
35
36pub mod codegen;
37pub mod compute;
38pub mod prelude;
39
40mod pod;
41
42pub use codegen::*;
43pub use pod::*;
44
45pub use cubecl_macros::*;
46pub use cubecl_runtime::benchmark;
47pub use cubecl_runtime::client;
48pub use cubecl_runtime::compiler::{CompilationError, Compiler};
49pub use cubecl_runtime::kernel::{CubeKernel, PrecompiledSource, define_kernel};
50pub use cubecl_runtime::memory_management::MemoryUsage;
51pub use cubecl_runtime::memory_management::{
52 AuxiliaryMemoryReport, MemoryPoolKind, MemoryPoolReport, MemoryPoolsReport, MemoryReport,
53 MemoryScope, StreamMemoryReport,
54};
55pub use cubecl_runtime::server;
56pub use cubecl_runtime::throughput;
57pub use cubecl_runtime::tune;
58
59use frontend::LaunchArg;
60
61pub use cubecl_common::*;
62
63pub use prelude::CubeCount;
64pub use prelude::{CubeDim, ExecutionMode};
65
66pub use num_traits;
67
68mod id;
69pub use id::*;
70
71#[doc(hidden)]
73pub mod __private {
74 pub use alloc::sync::Arc;
75 pub use alloc::{format, vec};
76 pub use cubecl_runtime::runtime::Runtime;
77 pub use paste::paste;
78}
79
80pub use prelude::{Assign, IntoRuntime};
81
82pub fn calculate_cube_count_elemwise(
85 client: &Client,
86 num_elems: usize,
87 cube_dim: CubeDim,
88) -> CubeCount {
89 if num_elems == 0 {
90 return CubeCount::Static(0, 0, 0);
91 }
92 let num_cubes = num_elems.div_ceil(cube_dim.num_elems() as usize);
93 CubeCountSelection::new(client, num_cubes as u32).cube_count()
94}
95
96pub fn tensor_vectorization_factor(
97 factors: &[VectorSize],
98 shape: &Shape,
99 strides: &Strides,
100 dim: usize,
101) -> VectorSize {
102 tensor_vector_size_parallel(factors.iter().cloned(), shape, strides, dim)
103}
104pub fn tensor_vectorization(
105 factors: &[VectorSize],
106 shape: &Shape,
107 strides: &Strides,
108 dim: usize,
109) -> VectorSize {
110 tensor_vector_size_parallel(factors.iter().cloned(), shape, strides, dim)
111}
112
113#[derive(Debug, Clone)]
114pub enum VectorizationError {
115 AxisOutOfBounds,
116 StrideMismatch,
117 NoValidVectorization,
118}
119
120pub fn tensor_vector_size_parallel(
133 optimized_vector_sizes: impl Iterator<Item = VectorSize>,
134 shape: &Shape,
135 strides: &Strides,
136 axis: usize,
137) -> VectorSize {
138 try_tensor_vector_size_parallel(optimized_vector_sizes, shape, strides, axis).unwrap_or(1)
139}
140
141pub fn try_tensor_vector_size_parallel(
143 supported_vector_sizes: impl Iterator<Item = VectorSize>,
144 shape: &Shape,
145 strides: &Strides,
146 axis: usize,
147) -> Result<VectorSize, VectorizationError> {
148 let stride = strides
149 .get(axis)
150 .ok_or(VectorizationError::AxisOutOfBounds)?;
151 if *stride != 1 {
152 return Err(VectorizationError::StrideMismatch);
153 }
154
155 let axis_shape = shape.get(axis).ok_or(VectorizationError::AxisOutOfBounds)?;
156
157 supported_vector_sizes
161 .filter(|&vector_size| {
162 axis_shape % vector_size == 0
163 && strides
164 .iter()
165 .enumerate()
166 .all(|(i, stride)| i == axis || stride % vector_size == 0)
167 })
168 .max()
169 .ok_or(VectorizationError::NoValidVectorization)
170}
171
172pub fn tensor_vector_size_perpendicular(
183 supported_vector_sizes: impl Iterator<Item = VectorSize>,
184 shape: &[usize],
185 strides: &[usize],
186 axis: usize,
187) -> VectorSize {
188 try_tensor_vector_sizes_perpendicular(supported_vector_sizes, shape, strides, axis).unwrap_or(1)
189}
190
191pub fn try_tensor_vector_sizes_perpendicular(
193 supported_vector_sizes: impl Iterator<Item = VectorSize>,
194 shape: &[usize],
195 strides: &[usize],
196 axis: usize,
197) -> Result<VectorSize, VectorizationError> {
198 let axis_stride = strides
199 .get(axis)
200 .ok_or(VectorizationError::AxisOutOfBounds)?;
201
202 let prod_shape_axes_smaller_strides = strides
203 .iter()
204 .zip(shape.iter())
205 .filter(|(stride, _)| **stride < *axis_stride)
206 .map(|(_, shape)| shape)
207 .product::<usize>();
208
209 if *axis_stride != prod_shape_axes_smaller_strides {
210 return Err(VectorizationError::StrideMismatch);
211 }
212
213 supported_vector_sizes
214 .filter(|&vector_size| *axis_stride % vector_size == 0)
215 .max()
216 .ok_or(VectorizationError::NoValidVectorization)
217}
218
219pub type RuntimeArg<T> = <T as LaunchArg>::RuntimeArg;
221pub type ExpandType<T> = <T as crate::prelude::CubeType>::ExpandType;
222
223#[cfg(feature = "export_tests")]
224pub mod runtime_tests;
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230
231 fn try_parallel(
232 sizes: &[VectorSize],
233 shape: &[usize],
234 strides: &[usize],
235 axis: usize,
236 ) -> Result<VectorSize, VectorizationError> {
237 try_tensor_vector_size_parallel(
238 sizes.iter().copied(),
239 &Shape::from(shape.iter().copied()),
240 &Strides::new(strides),
241 axis,
242 )
243 }
244
245 #[test]
246 fn parallel_contiguous_picks_max_vector_size() {
247 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[36, 4, 1], 2).unwrap();
250 assert_eq!(v, 4);
251 }
252
253 #[test]
254 fn parallel_unfold_step_one_rejects_vectorization() {
255 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[12, 1, 1], 2).unwrap();
261 assert_eq!(v, 1);
262 }
263
264 #[test]
265 fn parallel_unfold_step_two_allows_vectorization() {
266 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[12, 2, 1], 2).unwrap();
270 assert_eq!(v, 2);
271 }
272
273 #[test]
274 fn parallel_unfold_with_odd_outer_stride_rejects_vectorization() {
275 let v = try_parallel(&[1, 2, 4], &[2, 2, 2], &[5, 2, 1], 2).unwrap();
277 assert_eq!(v, 1);
278 assert!(matches!(
279 try_parallel(&[2, 4], &[2, 2, 2], &[5, 2, 1], 2),
280 Err(VectorizationError::NoValidVectorization)
281 ));
282 }
283
284 #[test]
285 fn parallel_unfold_outer_stride_limits_vector_width() {
286 let v = try_parallel(&[1, 2, 4], &[2, 2, 4], &[10, 4, 1], 2).unwrap();
288 assert_eq!(v, 2);
289 }
290
291 #[test]
292 fn parallel_broadcast_dim_ignored() {
293 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[0, 4, 1], 2).unwrap();
296 assert_eq!(v, 4);
297 }
298
299 #[test]
300 fn parallel_axis_stride_not_one_is_error() {
301 let err = try_parallel(&[1, 2, 4], &[1, 9, 4], &[36, 1, 4], 2).unwrap_err();
302 assert!(matches!(err, VectorizationError::StrideMismatch));
303 }
304}