1use cubecl::prelude::*;
4use cubecl::bytes::Bytes;
5use cubecl::server::Handle;
6use dspk_core::compute::MAX_DEVICE_ELEMENTS;
7
8pub fn bytes<E: CubeElement>(len: usize) -> usize {
15 assert!(len <= MAX_DEVICE_ELEMENTS, "device buffer of {len} elements exceeds the 32-bit index limit ({MAX_DEVICE_ELEMENTS})");
16 len.max(1) * size_of::<E>()
17}
18
19pub fn empty<E: CubeElement>(client: &Client, len: usize) -> Handle {
21 client.empty(bytes::<E>(len))
22}
23
24pub fn upload<E: CubeElement>(client: &Client, data: &[E]) -> Handle {
29 bytes::<E>(data.len());
30 client.create(Bytes::from_elems(data.to_vec()))
33}
34
35pub fn write<E: CubeElement>(client: &Client, handle: &Handle, data: &[E]) {
40 bytes::<E>(data.len());
41 write_bytes(client, handle, Bytes::from_elems(data.to_vec()));
42}
43
44pub fn write_owned<E: CubeElement>(client: &Client, handle: &Handle, data: Vec<E>) {
47 bytes::<E>(data.len());
48 write_bytes(client, handle, Bytes::from_elems(data));
49}
50
51pub fn write_bytes(client: &Client, handle: &Handle, data: Bytes) {
58 let (len, used) = (data.len() as u64, handle.size_in_used());
59 assert!(len <= used, "writing {len} bytes into a device buffer of {used}");
60 client.write(&handle.clone().offset_end(used - len), data);
61}
62
63pub fn zeros<E: CubeElement + Scalar>(client: &Client, len: usize) -> Handle {
66 bytes::<E>(len);
67 cubecl::std::tensor::TensorHandle::zeros(client, [len.max(1)], E::elem_type_native()).handle
68}
69
70pub fn filled<F: crate::core::DspFloat>(client: &Client, len: usize, value: F) -> Handle {
72 let out = empty::<F>(client, len);
73 if len > 0 {
74 let geom = dspk_core::compute::LaunchGeometry::elementwise(client, len);
75 unsafe {
76 super::kernels::fill_kernel::launch::<F>(
77 client,
78 geom.cube_count,
79 geom.cube_dim,
80 BufferArg::from_raw_parts(out.clone(), len),
81 value,
82 len as u32,
83 );
84 }
85 }
86 out
87}
88
89pub fn fill<F: crate::core::DspFloat>(client: &Client, handle: &Handle, len: usize, value: F) {
92 if len == 0 {
93 return;
94 }
95 let geom = dspk_core::compute::LaunchGeometry::elementwise(client, len);
96 unsafe {
98 super::kernels::fill_kernel::launch::<F>(
99 client,
100 geom.cube_count,
101 geom.cube_dim,
102 BufferArg::from_raw_parts(handle.clone(), len),
103 value,
104 len as u32,
105 );
106 }
107}
108
109pub fn copy<F: crate::core::DspFloat>(client: &Client, src: &Handle, dst: &Handle, len: usize) {
111 if len == 0 {
112 return;
113 }
114 let (src, dst) = unsafe {
116 (
117 TensorBinding::from_raw_parts(src.clone(), cubecl::zspace::Strides::new(&[1]), cubecl::zspace::Shape::new([len])),
118 TensorBinding::from_raw_parts(dst.clone(), cubecl::zspace::Strides::new(&[1]), cubecl::zspace::Shape::new([len])),
119 )
120 };
121 cubecl::std::tensor::copy_into(client, src, dst, F::elem_type_native());
122}
123
124pub fn download<E: CubeElement>(client: &Client, handle: Handle) -> Vec<E> {
126 E::from_bytes(&client.read_one_unchecked(handle)).to_vec()
127}
128
129pub fn download_prefix<E: CubeElement>(client: &Client, handle: Handle, len: usize) -> Vec<E> {
132 let used = handle.size_in_used();
133 let want = (len * size_of::<E>()) as u64;
134 assert!(want <= used, "{len} elements exceed the buffer's {used} bytes");
135 let mut out = download::<E>(client, handle.offset_end(used - want));
136 out.truncate(len);
137 out
138}
139
140pub fn download_range<E: CubeElement>(client: &Client, handle: Handle, start: usize, len: usize) -> Vec<E> {
143 let used = handle.size_in_used();
144 let (from, want) = ((start * size_of::<E>()) as u64, (len * size_of::<E>()) as u64);
145 assert!(from + want <= used, "elements {start}..{} exceed the buffer's {used} bytes", start + len);
146 let mut out = download::<E>(client, handle.offset_start(from).offset_end(used - from - want));
147 out.truncate(len);
148 out
149}
150
151pub fn truncate<E: CubeElement>(handle: Handle, unused: usize) -> Handle {
153 handle.offset_end((unused * size_of::<E>()) as u64)
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 fn fills_every_element(client: &Client) {
161 let len = 1_000_003;
163 let v: Vec<f32> = download(client, filled::<f32>(client, len, f32::MAX));
164 assert_eq!(v.len(), len);
165 assert!(v.iter().all(|&x| x == f32::MAX), "{}", client.name());
166 }
167 runtime_test!(test_filled, fills_every_element);
168
169 fn short_write_into_larger_buffer(client: &Client) {
172 let handle = upload::<f32>(client, &[7.0; 100]);
173 write(client, &handle, &[1.0f32; 10]);
174 write_owned(client, &handle, vec![2.0f32; 3]);
175 let v: Vec<f32> = download(client, handle);
176 assert_eq!(&v[..3], &[2.0; 3], "{}", client.name());
177 assert_eq!(&v[3..10], &[1.0; 7], "{}", client.name());
178 assert!(v[10..].iter().all(|&x| x == 7.0), "{}", client.name());
179 }
180 runtime_test!(test_short_write, short_write_into_larger_buffer);
181}