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;
31
32pub use cubecl_ir as ir;
34
35pub mod codegen;
36pub mod compute;
37pub mod prelude;
38
39mod pod;
40
41pub use codegen::*;
42pub use pod::*;
43
44pub use cubecl_macros::*;
45pub use cubecl_runtime::benchmark;
46pub use cubecl_runtime::client;
47pub use cubecl_runtime::compiler::{CompilationError, Compiler};
48pub use cubecl_runtime::kernel::{CubeKernel, PrecompiledSource, define_kernel};
49pub use cubecl_runtime::memory_management::MemoryUsage;
50pub use cubecl_runtime::memory_management::{
51 AuxiliaryMemoryReport, MemoryPoolKind, MemoryPoolReport, MemoryPoolsReport, MemoryReport,
52 MemoryScope, StreamMemoryReport,
53};
54pub use cubecl_runtime::server;
55pub use cubecl_runtime::throughput;
56pub use cubecl_runtime::tune;
57
58use frontend::LaunchArg;
59
60pub use cubecl_common::*;
61
62pub use prelude::CubeCount;
63pub use prelude::{CubeDim, ExecutionMode};
64
65pub use num_traits;
66
67mod id;
68pub use id::*;
69
70#[doc(hidden)]
72pub mod __private {
73 pub use alloc::sync::Arc;
74 pub use alloc::{format, vec};
75 pub use cubecl_runtime::runtime::Runtime;
76 pub use paste::paste;
77}
78
79pub use prelude::{Assign, IntoRuntime};
80
81pub fn calculate_cube_count_elemwise(
84 client: &Client,
85 num_elems: usize,
86 cube_dim: CubeDim,
87) -> CubeCount {
88 if num_elems == 0 {
89 return CubeCount::Static(0, 0, 0);
90 }
91 let num_cubes = num_elems.div_ceil(cube_dim.num_elems() as usize);
92 CubeCountSelection::new(client, num_cubes as u32).cube_count()
93}
94
95pub fn tensor_vectorization_factor(
96 factors: &[VectorSize],
97 shape: &Shape,
98 strides: &Strides,
99 dim: usize,
100) -> VectorSize {
101 tensor_vector_size_parallel(factors.iter().cloned(), shape, strides, dim)
102}
103pub fn tensor_vectorization(
104 factors: &[VectorSize],
105 shape: &Shape,
106 strides: &Strides,
107 dim: usize,
108) -> VectorSize {
109 tensor_vector_size_parallel(factors.iter().cloned(), shape, strides, dim)
110}
111
112#[derive(Debug, Clone)]
113pub enum VectorizationError {
114 AxisOutOfBounds,
115 StrideMismatch,
116 NoValidVectorization,
117}
118
119pub fn tensor_vector_size_parallel(
132 optimized_vector_sizes: impl Iterator<Item = VectorSize>,
133 shape: &Shape,
134 strides: &Strides,
135 axis: usize,
136) -> VectorSize {
137 try_tensor_vector_size_parallel(optimized_vector_sizes, shape, strides, axis).unwrap_or(1)
138}
139
140pub fn try_tensor_vector_size_parallel(
142 supported_vector_sizes: impl Iterator<Item = VectorSize>,
143 shape: &Shape,
144 strides: &Strides,
145 axis: usize,
146) -> Result<VectorSize, VectorizationError> {
147 let stride = strides
148 .get(axis)
149 .ok_or(VectorizationError::AxisOutOfBounds)?;
150 if *stride != 1 {
151 return Err(VectorizationError::StrideMismatch);
152 }
153
154 let axis_shape = shape.get(axis).ok_or(VectorizationError::AxisOutOfBounds)?;
155
156 let next_stride = strides
163 .iter()
164 .enumerate()
165 .filter_map(|(i, &s)| (i != axis && s != 0).then_some(s))
166 .min()
167 .unwrap_or(0);
168
169 supported_vector_sizes
170 .filter(|&vector_size| axis_shape % vector_size == 0 && next_stride % vector_size == 0)
171 .max()
172 .ok_or(VectorizationError::NoValidVectorization)
173}
174
175pub fn tensor_vector_size_perpendicular(
186 supported_vector_sizes: impl Iterator<Item = VectorSize>,
187 shape: &[usize],
188 strides: &[usize],
189 axis: usize,
190) -> VectorSize {
191 try_tensor_vector_sizes_perpendicular(supported_vector_sizes, shape, strides, axis).unwrap_or(1)
192}
193
194pub fn try_tensor_vector_sizes_perpendicular(
196 supported_vector_sizes: impl Iterator<Item = VectorSize>,
197 shape: &[usize],
198 strides: &[usize],
199 axis: usize,
200) -> Result<VectorSize, VectorizationError> {
201 let axis_stride = strides
202 .get(axis)
203 .ok_or(VectorizationError::AxisOutOfBounds)?;
204
205 let prod_shape_axes_smaller_strides = strides
206 .iter()
207 .zip(shape.iter())
208 .filter(|(stride, _)| **stride < *axis_stride)
209 .map(|(_, shape)| shape)
210 .product::<usize>();
211
212 if *axis_stride != prod_shape_axes_smaller_strides {
213 return Err(VectorizationError::StrideMismatch);
214 }
215
216 supported_vector_sizes
217 .filter(|&vector_size| *axis_stride % vector_size == 0)
218 .max()
219 .ok_or(VectorizationError::NoValidVectorization)
220}
221
222pub type RuntimeArg<T> = <T as LaunchArg>::RuntimeArg;
224pub type ExpandType<T> = <T as crate::prelude::CubeType>::ExpandType;
225
226#[cfg(feature = "export_tests")]
227pub mod runtime_tests;
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 fn try_parallel(
235 sizes: &[VectorSize],
236 shape: &[usize],
237 strides: &[usize],
238 axis: usize,
239 ) -> Result<VectorSize, VectorizationError> {
240 try_tensor_vector_size_parallel(
241 sizes.iter().copied(),
242 &Shape::from(shape.iter().copied()),
243 &Strides::new(strides),
244 axis,
245 )
246 }
247
248 #[test]
249 fn parallel_contiguous_picks_max_vector_size() {
250 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[36, 4, 1], 2).unwrap();
253 assert_eq!(v, 4);
254 }
255
256 #[test]
257 fn parallel_unfold_step_one_rejects_vectorization() {
258 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[12, 1, 1], 2).unwrap();
264 assert_eq!(v, 1);
265 }
266
267 #[test]
268 fn parallel_unfold_step_two_allows_vectorization() {
269 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[12, 2, 1], 2).unwrap();
273 assert_eq!(v, 2);
274 }
275
276 #[test]
277 fn parallel_broadcast_dim_ignored() {
278 let v = try_parallel(&[1, 2, 4], &[1, 9, 4], &[0, 4, 1], 2).unwrap();
281 assert_eq!(v, 4);
282 }
283
284 #[test]
285 fn parallel_axis_stride_not_one_is_error() {
286 let err = try_parallel(&[1, 2, 4], &[1, 9, 4], &[36, 1, 4], 2).unwrap_err();
287 assert!(matches!(err, VectorizationError::StrideMismatch));
288 }
289}