1use crate::backend::BackendDevice;
2use crate::cpu_backend::CpuDevice;
3use crate::{CpuStorage, DType, Result, Shape, Storage, WithDType};
4
5#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8pub enum DeviceLocation {
9 Cpu,
10 Cuda {
11 gpu_id: usize,
12 },
13 Metal {
14 gpu_id: usize,
15 },
16 #[cfg(feature = "rocm")]
17 Rocm {
18 gpu_id: usize,
19 },
20 #[cfg(feature = "vulkan")]
21 Vulkan {
22 gpu_id: usize,
23 },
24 #[cfg(feature = "wgpu")]
25 Wgpu {
26 gpu_id: usize,
27 },
28}
29
30#[derive(Debug, Clone)]
32pub enum Device {
33 Cpu,
34 Cuda(crate::CudaDevice),
35 Metal(crate::MetalDevice),
36 #[cfg(feature = "rocm")]
37 Rocm(crate::RocmDevice),
38 #[cfg(feature = "vulkan")]
39 Vulkan(crate::VulkanDevice),
40 #[cfg(feature = "wgpu")]
41 Wgpu(crate::WgpuDevice),
42}
43
44pub trait NdArray {
45 fn shape(&self) -> Result<Shape>;
46
47 fn to_cpu_storage(&self) -> CpuStorage;
48}
49
50impl<S: WithDType> NdArray for S {
51 fn shape(&self) -> Result<Shape> {
52 Ok(Shape::from(()))
53 }
54
55 fn to_cpu_storage(&self) -> CpuStorage {
56 S::to_cpu_storage(&[*self])
57 }
58}
59
60impl<S: WithDType, const N: usize> NdArray for &[S; N] {
61 fn shape(&self) -> Result<Shape> {
62 Ok(Shape::from(self.len()))
63 }
64
65 fn to_cpu_storage(&self) -> CpuStorage {
66 S::to_cpu_storage(self.as_slice())
67 }
68}
69
70impl<S: WithDType> NdArray for &[S] {
71 fn shape(&self) -> Result<Shape> {
72 Ok(Shape::from(self.len()))
73 }
74
75 fn to_cpu_storage(&self) -> CpuStorage {
76 S::to_cpu_storage(self)
77 }
78}
79
80impl<S: WithDType, const N: usize, const M: usize> NdArray for &[[S; N]; M] {
81 fn shape(&self) -> Result<Shape> {
82 Ok(Shape::from((M, N)))
83 }
84
85 fn to_cpu_storage(&self) -> CpuStorage {
86 S::to_cpu_storage_owned(self.concat())
87 }
88}
89
90impl<S: WithDType, const N1: usize, const N2: usize, const N3: usize> NdArray
91 for &[[[S; N3]; N2]; N1]
92{
93 fn shape(&self) -> Result<Shape> {
94 Ok(Shape::from((N1, N2, N3)))
95 }
96
97 fn to_cpu_storage(&self) -> CpuStorage {
98 let mut vec = Vec::with_capacity(N1 * N2 * N3);
99 for i1 in 0..N1 {
100 for i2 in 0..N2 {
101 vec.extend(self[i1][i2])
102 }
103 }
104 S::to_cpu_storage_owned(vec)
105 }
106}
107
108impl<S: WithDType, const N1: usize, const N2: usize, const N3: usize, const N4: usize> NdArray
109 for &[[[[S; N4]; N3]; N2]; N1]
110{
111 fn shape(&self) -> Result<Shape> {
112 Ok(Shape::from((N1, N2, N3, N4)))
113 }
114
115 fn to_cpu_storage(&self) -> CpuStorage {
116 let mut vec = Vec::with_capacity(N1 * N2 * N3 * N4);
117 for i1 in 0..N1 {
118 for i2 in 0..N2 {
119 for i3 in 0..N3 {
120 vec.extend(self[i1][i2][i3])
121 }
122 }
123 }
124 S::to_cpu_storage_owned(vec)
125 }
126}
127
128impl<S: WithDType> NdArray for Vec<S> {
129 fn shape(&self) -> Result<Shape> {
130 Ok(Shape::from(self.len()))
131 }
132
133 fn to_cpu_storage(&self) -> CpuStorage {
134 S::to_cpu_storage(self.as_slice())
135 }
136}
137
138impl<S: WithDType> NdArray for Vec<&[S]> {
139 fn shape(&self) -> Result<Shape> {
140 if self.is_empty() {
141 crate::bail!("empty array")
142 }
143 let n = self.len();
144 let m = self[0].len();
145 for v in self.iter() {
146 if v.len() != m {
147 crate::bail!("two elements have different len {m} {}", v.len())
148 }
149 }
150 Ok(Shape::from((n, m)))
151 }
152
153 fn to_cpu_storage(&self) -> CpuStorage {
154 let data = self.iter().copied().flatten().copied().collect::<Vec<_>>();
155 S::to_cpu_storage_owned(data)
156 }
157}
158
159impl<S: WithDType> NdArray for Vec<Vec<S>> {
160 fn shape(&self) -> Result<Shape> {
161 if self.is_empty() {
162 crate::bail!("empty array")
163 }
164 let n = self.len();
165 let m = self[0].len();
166 for v in self.iter() {
167 if v.len() != m {
168 crate::bail!("two elements have different len {m} {}", v.len())
169 }
170 }
171 Ok(Shape::from((n, m)))
172 }
173
174 fn to_cpu_storage(&self) -> CpuStorage {
175 let len: usize = self.iter().map(|v| v.len()).sum();
176 let mut dst = Vec::with_capacity(len);
177 for v in self.iter() {
178 dst.extend(v.iter().copied());
179 }
180 S::to_cpu_storage_owned(dst)
181 }
182}
183
184impl<S: WithDType> NdArray for Vec<Vec<Vec<S>>> {
185 fn shape(&self) -> Result<Shape> {
186 if self.is_empty() {
187 crate::bail!("empty array")
188 }
189 let shape0 = self[0].shape()?;
190 let n = self.len();
191 for v in self.iter() {
192 let shape = v.shape()?;
193 if shape != shape0 {
194 crate::bail!("two elements have different shapes {shape:?} {shape0:?}")
195 }
196 }
197 Ok(Shape::from([[n].as_slice(), shape0.dims()].concat()))
198 }
199
200 fn to_cpu_storage(&self) -> CpuStorage {
201 if self.is_empty() {
202 return S::to_cpu_storage_owned(vec![]);
203 }
204 let len: usize = self
205 .iter()
206 .map(|v| v.iter().map(|v| v.len()).sum::<usize>())
207 .sum();
208 let mut dst = Vec::with_capacity(len);
209 for v1 in self.iter() {
210 for v2 in v1.iter() {
211 dst.extend(v2.iter().copied());
212 }
213 }
214 S::to_cpu_storage_owned(dst)
215 }
216}
217
218impl<S: WithDType> NdArray for Vec<Vec<Vec<Vec<S>>>> {
219 fn shape(&self) -> Result<Shape> {
220 if self.is_empty() {
221 crate::bail!("empty array")
222 }
223 let shape0 = self[0].shape()?;
224 let n = self.len();
225 for v in self.iter() {
226 let shape = v.shape()?;
227 if shape != shape0 {
228 crate::bail!("two elements have different shapes {shape:?} {shape0:?}")
229 }
230 }
231 Ok(Shape::from([[n].as_slice(), shape0.dims()].concat()))
232 }
233
234 fn to_cpu_storage(&self) -> CpuStorage {
235 let len: usize = self
236 .iter()
237 .map(|v| {
238 v.iter()
239 .map(|v| v.iter().map(|v| v.len()).sum::<usize>())
240 .sum::<usize>()
241 })
242 .sum();
243 let mut dst = Vec::with_capacity(len);
244 for v1 in self.iter() {
245 for v2 in v1.iter() {
246 for v3 in v2.iter() {
247 dst.extend(v3.iter().copied());
248 }
249 }
250 }
251 S::to_cpu_storage_owned(dst)
252 }
253}
254
255impl Device {
256 pub fn new_cuda(ordinal: usize) -> Result<Self> {
257 Ok(Self::Cuda(crate::CudaDevice::new(ordinal)?))
258 }
259
260 #[cfg(feature = "rocm")]
261 pub fn new_rocm(ordinal: usize) -> Result<Self> {
262 Ok(Self::Rocm(crate::RocmDevice::new(ordinal)?))
263 }
264 #[cfg(feature = "vulkan")]
265 pub fn new_vulkan(ordinal: usize) -> Result<Self> {
266 Ok(Self::Vulkan(crate::VulkanDevice::new(ordinal)?))
267 }
268 #[cfg(feature = "wgpu")]
269 pub fn new_wgpu(ordinal: usize) -> Result<Self> {
270 Ok(Self::Wgpu(crate::WgpuDevice::new(ordinal)?))
271 }
272
273 pub fn as_cuda_device(&self) -> Result<&crate::CudaDevice> {
274 match self {
275 Self::Cuda(d) => Ok(d),
276 Self::Cpu => crate::bail!("expected a cuda device, got cpu"),
277 Self::Metal(_) => crate::bail!("expected a cuda device, got Metal"),
278 #[cfg(feature = "rocm")]
279 Self::Rocm(_) => crate::bail!("expected a cuda device, got rocm"),
280 #[cfg(feature = "vulkan")]
281 Self::Vulkan(_) => crate::bail!("expected a cuda device, got vulkan"),
282 #[cfg(feature = "wgpu")]
283 Self::Wgpu(_) => crate::bail!("expected a cuda device, got wgpu"),
284 }
285 }
286
287 pub fn as_metal_device(&self) -> Result<&crate::MetalDevice> {
288 match self {
289 Self::Cuda(_) => crate::bail!("expected a metal device, got cuda"),
290 Self::Cpu => crate::bail!("expected a metal device, got cpu"),
291 Self::Metal(d) => Ok(d),
292 #[cfg(feature = "rocm")]
293 Self::Rocm(_) => crate::bail!("expected a metal device, got rocm"),
294 #[cfg(feature = "vulkan")]
295 Self::Vulkan(_) => crate::bail!("expected a metal device, got vulkan"),
296 #[cfg(feature = "wgpu")]
297 Self::Wgpu(_) => crate::bail!("expected a metal device, got wgpu"),
298 }
299 }
300
301 #[cfg(feature = "rocm")]
302 pub fn as_rocm_device(&self) -> Result<&crate::RocmDevice> {
303 match self {
304 Self::Cuda(_) => crate::bail!("expected a rocm device, got cuda"),
305 Self::Cpu => crate::bail!("expected a rocm device, got cpu"),
306 Self::Metal(_) => crate::bail!("expected a rocm device, got Metal"),
307 Self::Rocm(d) => Ok(d),
308 }
309 }
310 #[cfg(feature = "vulkan")]
311 pub fn as_vulkan_device(&self) -> Result<&crate::VulkanDevice> {
312 match self {
313 Self::Cuda(_) => crate::bail!("expected a vulkan device, got cuda"),
314 Self::Cpu => crate::bail!("expected a vulkan device, got cpu"),
315 Self::Metal(_) => crate::bail!("expected a vulkan device, got Metal"),
316 Self::Vulkan(d) => Ok(d),
317 #[cfg(feature = "wgpu")]
318 Self::Wgpu(_) => crate::bail!("expected a vulkan device, got wgpu"),
319 }
320 }
321 #[cfg(feature = "wgpu")]
322 pub fn as_wgpu_device(&self) -> Result<&crate::WgpuDevice> {
323 match self {
324 Self::Cuda(_) => crate::bail!("expected a wgpu device, got cuda"),
325 Self::Cpu => crate::bail!("expected a wgpu device, got cpu"),
326 Self::Metal(_) => crate::bail!("expected a wgpu device, got Metal"),
327 #[cfg(feature = "vulkan")]
328 Self::Vulkan(_) => crate::bail!("expected a wgpu device, got vulkan"),
329 Self::Wgpu(d) => Ok(d),
330 }
331 }
332
333 pub fn new_cuda_with_stream(ordinal: usize) -> Result<Self> {
334 Ok(Self::Cuda(crate::CudaDevice::new_with_stream(ordinal)?))
335 }
336
337 pub fn new_metal(ordinal: usize) -> Result<Self> {
338 Ok(Self::Metal(crate::MetalDevice::new(ordinal)?))
339 }
340
341 pub fn set_seed(&self, seed: u64) -> Result<()> {
342 match self {
343 Self::Cpu => CpuDevice.set_seed(seed),
344 Self::Cuda(c) => c.set_seed(seed),
345 Self::Metal(m) => m.set_seed(seed),
346 #[cfg(feature = "rocm")]
347 Self::Rocm(r) => r.set_seed(seed),
348 #[cfg(feature = "vulkan")]
349 Self::Vulkan(r) => r.set_seed(seed),
350 #[cfg(feature = "wgpu")]
351 Self::Wgpu(r) => r.set_seed(seed),
352 }
353 }
354
355 pub fn get_current_seed(&self) -> Result<u64> {
356 match self {
357 Self::Cpu => CpuDevice.get_current_seed(),
358 Self::Cuda(c) => c.get_current_seed(),
359 Self::Metal(m) => m.get_current_seed(),
360 #[cfg(feature = "rocm")]
361 Self::Rocm(r) => r.get_current_seed(),
362 #[cfg(feature = "vulkan")]
363 Self::Vulkan(r) => r.get_current_seed(),
364 #[cfg(feature = "wgpu")]
365 Self::Wgpu(r) => r.get_current_seed(),
366 }
367 }
368
369 pub fn same_device(&self, rhs: &Self) -> bool {
370 match (self, rhs) {
371 (Self::Cpu, Self::Cpu) => true,
372 (Self::Cuda(lhs), Self::Cuda(rhs)) => lhs.same_device(rhs),
373 (Self::Metal(lhs), Self::Metal(rhs)) => lhs.same_device(rhs),
374 #[cfg(feature = "rocm")]
375 (Self::Rocm(lhs), Self::Rocm(rhs)) => lhs.same_device(rhs),
376 #[cfg(feature = "vulkan")]
377 (Self::Vulkan(lhs), Self::Vulkan(rhs)) => lhs.same_device(rhs),
378 #[cfg(feature = "wgpu")]
379 (Self::Wgpu(lhs), Self::Wgpu(rhs)) => lhs.same_device(rhs),
380 _ => false,
381 }
382 }
383
384 pub fn location(&self) -> DeviceLocation {
385 match self {
386 Self::Cpu => DeviceLocation::Cpu,
387 Self::Cuda(device) => device.location(),
388 Device::Metal(device) => device.location(),
389 #[cfg(feature = "rocm")]
390 Self::Rocm(device) => device.location(),
391 #[cfg(feature = "vulkan")]
392 Self::Vulkan(device) => device.location(),
393 #[cfg(feature = "wgpu")]
394 Self::Wgpu(device) => device.location(),
395 }
396 }
397
398 pub fn is_cpu(&self) -> bool {
399 matches!(self, Self::Cpu)
400 }
401
402 pub fn is_cuda(&self) -> bool {
403 matches!(self, Self::Cuda(_))
404 }
405
406 pub fn is_metal(&self) -> bool {
407 matches!(self, Self::Metal(_))
408 }
409
410 pub fn is_rocm(&self) -> bool {
411 #[cfg(feature = "rocm")]
412 {
413 matches!(self, Self::Rocm(_))
414 }
415 #[cfg(not(feature = "rocm"))]
416 {
417 false
418 }
419 }
420
421 pub fn is_vulkan(&self) -> bool {
422 #[cfg(feature = "vulkan")]
423 {
424 matches!(self, Self::Vulkan(_))
425 }
426 #[cfg(not(feature = "vulkan"))]
427 {
428 false
429 }
430 }
431
432 pub fn is_wgpu(&self) -> bool {
433 #[cfg(feature = "wgpu")]
434 {
435 matches!(self, Self::Wgpu(_))
436 }
437 #[cfg(not(feature = "wgpu"))]
438 {
439 false
440 }
441 }
442
443 pub fn supports_bf16(&self) -> bool {
444 match self {
445 Self::Cuda(_) | Self::Metal(_) => true,
446 Self::Cpu => false,
447 #[cfg(feature = "rocm")]
448 Self::Rocm(_) => true,
449 #[cfg(feature = "vulkan")]
452 Self::Vulkan(_) => false,
453 #[cfg(feature = "wgpu")]
455 Self::Wgpu(_) => false,
456 }
457 }
458
459 pub fn bf16_default_to_f32(&self) -> DType {
461 if self.supports_bf16() {
462 DType::BF16
463 } else {
464 DType::F32
465 }
466 }
467
468 pub fn cuda_if_available(ordinal: usize) -> Result<Self> {
469 if crate::utils::cuda_is_available() {
470 Self::new_cuda(ordinal)
471 } else {
472 Ok(Self::Cpu)
473 }
474 }
475
476 pub fn metal_if_available(ordinal: usize) -> Result<Self> {
477 if crate::utils::metal_is_available() {
478 Self::new_metal(ordinal)
479 } else {
480 Ok(Self::Cpu)
481 }
482 }
483
484 pub(crate) fn rand_uniform_f64(
485 &self,
486 lo: f64,
487 up: f64,
488 shape: &Shape,
489 dtype: DType,
490 ) -> Result<Storage> {
491 match self {
492 Device::Cpu => {
493 let storage = CpuDevice.rand_uniform(shape, dtype, lo, up)?;
494 Ok(Storage::Cpu(storage))
495 }
496 Device::Cuda(device) => {
497 if dtype == DType::F16 || dtype == DType::BF16 {
499 let storage = device.rand_uniform(shape, DType::F32, lo, up)?;
500 Storage::Cuda(storage).to_dtype(&crate::Layout::contiguous(shape), dtype)
501 } else {
502 let storage = device.rand_uniform(shape, dtype, lo, up)?;
503 Ok(Storage::Cuda(storage))
504 }
505 }
506 Device::Metal(device) => {
507 let storage = device.rand_uniform(shape, dtype, lo, up)?;
508 Ok(Storage::Metal(storage))
509 }
510 #[cfg(feature = "rocm")]
511 Device::Rocm(device) => {
512 let storage = device.rand_uniform(shape, dtype, lo, up)?;
513 Ok(Storage::Rocm(storage))
514 }
515 #[cfg(feature = "vulkan")]
516 Device::Vulkan(device) => {
517 let storage = device.rand_uniform(shape, dtype, lo, up)?;
518 Ok(Storage::Vulkan(storage))
519 }
520 #[cfg(feature = "wgpu")]
521 Device::Wgpu(device) => {
522 let storage = device.rand_uniform(shape, dtype, lo, up)?;
523 Ok(Storage::Wgpu(storage))
524 }
525 }
526 }
527
528 pub(crate) fn rand_uniform<T: crate::FloatDType>(
529 &self,
530 lo: T,
531 up: T,
532 shape: &Shape,
533 ) -> Result<Storage> {
534 self.rand_uniform_f64(lo.to_f64(), up.to_f64(), shape, T::DTYPE)
535 }
536
537 pub(crate) fn rand_normal_f64(
538 &self,
539 mean: f64,
540 std: f64,
541 shape: &Shape,
542 dtype: DType,
543 ) -> Result<Storage> {
544 match self {
545 Device::Cpu => {
546 let storage = CpuDevice.rand_normal(shape, dtype, mean, std)?;
547 Ok(Storage::Cpu(storage))
548 }
549 Device::Cuda(device) => {
550 if dtype == DType::F16 || dtype == DType::BF16 {
552 let storage = device.rand_normal(shape, DType::F32, mean, std)?;
553 Storage::Cuda(storage).to_dtype(&crate::Layout::contiguous(shape), dtype)
554 } else {
555 let storage = device.rand_normal(shape, dtype, mean, std)?;
556 Ok(Storage::Cuda(storage))
557 }
558 }
559 Device::Metal(device) => {
560 let storage = device.rand_normal(shape, dtype, mean, std)?;
561 Ok(Storage::Metal(storage))
562 }
563 #[cfg(feature = "rocm")]
564 Device::Rocm(device) => {
565 let storage = device.rand_normal(shape, dtype, mean, std)?;
566 Ok(Storage::Rocm(storage))
567 }
568 #[cfg(feature = "vulkan")]
569 Device::Vulkan(device) => {
570 let storage = device.rand_normal(shape, dtype, mean, std)?;
571 Ok(Storage::Vulkan(storage))
572 }
573 #[cfg(feature = "wgpu")]
574 Device::Wgpu(device) => {
575 let storage = device.rand_normal(shape, dtype, mean, std)?;
576 Ok(Storage::Wgpu(storage))
577 }
578 }
579 }
580
581 pub(crate) fn rand_normal<T: crate::FloatDType>(
582 &self,
583 mean: T,
584 std: T,
585 shape: &Shape,
586 ) -> Result<Storage> {
587 self.rand_normal_f64(mean.to_f64(), std.to_f64(), shape, T::DTYPE)
588 }
589
590 pub(crate) fn zeros(&self, shape: &Shape, dtype: DType) -> Result<Storage> {
591 match self {
592 Device::Cpu => {
593 let storage = CpuDevice.zeros_impl(shape, dtype)?;
594 Ok(Storage::Cpu(storage))
595 }
596 Device::Cuda(device) => {
597 let storage = device.zeros_impl(shape, dtype)?;
598 Ok(Storage::Cuda(storage))
599 }
600 Device::Metal(device) => {
601 let storage = device.zeros_impl(shape, dtype)?;
602 Ok(Storage::Metal(storage))
603 }
604 #[cfg(feature = "rocm")]
605 Device::Rocm(device) => {
606 let storage = device.zeros_impl(shape, dtype)?;
607 Ok(Storage::Rocm(storage))
608 }
609 #[cfg(feature = "vulkan")]
610 Device::Vulkan(device) => {
611 let storage = device.zeros_impl(shape, dtype)?;
612 Ok(Storage::Vulkan(storage))
613 }
614 #[cfg(feature = "wgpu")]
615 Device::Wgpu(device) => {
616 let storage = device.zeros_impl(shape, dtype)?;
617 Ok(Storage::Wgpu(storage))
618 }
619 }
620 }
621
622 pub(crate) unsafe fn alloc_uninit(&self, shape: &Shape, dtype: DType) -> Result<Storage> {
623 match self {
624 Device::Cpu => {
625 let storage = CpuDevice.alloc_uninit(shape, dtype)?;
626 Ok(Storage::Cpu(storage))
627 }
628 Device::Cuda(device) => {
629 let storage = device.alloc_uninit(shape, dtype)?;
630 Ok(Storage::Cuda(storage))
631 }
632 Device::Metal(device) => {
633 let storage = device.alloc_uninit(shape, dtype)?;
634 Ok(Storage::Metal(storage))
635 }
636 #[cfg(feature = "rocm")]
637 Device::Rocm(device) => {
638 let storage = device.alloc_uninit(shape, dtype)?;
639 Ok(Storage::Rocm(storage))
640 }
641 #[cfg(feature = "vulkan")]
642 Device::Vulkan(device) => {
643 let storage = device.alloc_uninit(shape, dtype)?;
644 Ok(Storage::Vulkan(storage))
645 }
646 #[cfg(feature = "wgpu")]
647 Device::Wgpu(device) => {
648 let storage = device.alloc_uninit(shape, dtype)?;
649 Ok(Storage::Wgpu(storage))
650 }
651 }
652 }
653
654 pub(crate) fn storage_from_slice<D: WithDType>(&self, data: &[D]) -> Result<Storage> {
655 match self {
656 Device::Cpu => Ok(Storage::Cpu(data.to_cpu_storage())),
657 Device::Cuda(device) => {
658 let storage = device.storage_from_slice(data)?;
659 Ok(Storage::Cuda(storage))
660 }
661 Device::Metal(device) => {
662 let storage = device.storage_from_slice(data)?;
663 Ok(Storage::Metal(storage))
664 }
665 #[cfg(feature = "rocm")]
666 Device::Rocm(device) => {
667 let storage = device.storage_from_slice(data)?;
668 Ok(Storage::Rocm(storage))
669 }
670 #[cfg(feature = "vulkan")]
671 Device::Vulkan(device) => {
672 let storage = device.storage_from_slice(data)?;
673 Ok(Storage::Vulkan(storage))
674 }
675 #[cfg(feature = "wgpu")]
676 Device::Wgpu(device) => {
677 let storage = device.storage_from_slice(data)?;
678 Ok(Storage::Wgpu(storage))
679 }
680 }
681 }
682
683 pub(crate) fn storage<A: NdArray>(&self, array: A) -> Result<Storage> {
684 match self {
685 Device::Cpu => Ok(Storage::Cpu(array.to_cpu_storage())),
686 Device::Cuda(device) => {
687 let storage = array.to_cpu_storage();
688 let storage = device.storage_from_cpu_storage_owned(storage)?;
689 Ok(Storage::Cuda(storage))
690 }
691 Device::Metal(device) => {
692 let storage = array.to_cpu_storage();
693 let storage = device.storage_from_cpu_storage_owned(storage)?;
694 Ok(Storage::Metal(storage))
695 }
696 #[cfg(feature = "rocm")]
697 Device::Rocm(device) => {
698 let storage = array.to_cpu_storage();
699 let storage = device.storage_from_cpu_storage_owned(storage)?;
700 Ok(Storage::Rocm(storage))
701 }
702 #[cfg(feature = "vulkan")]
703 Device::Vulkan(device) => {
704 let storage = array.to_cpu_storage();
705 let storage = device.storage_from_cpu_storage_owned(storage)?;
706 Ok(Storage::Vulkan(storage))
707 }
708 #[cfg(feature = "wgpu")]
709 Device::Wgpu(device) => {
710 let storage = array.to_cpu_storage();
711 let storage = device.storage_from_cpu_storage_owned(storage)?;
712 Ok(Storage::Wgpu(storage))
713 }
714 }
715 }
716
717 pub(crate) fn storage_owned<S: WithDType>(&self, data: Vec<S>) -> Result<Storage> {
718 match self {
719 Device::Cpu => Ok(Storage::Cpu(S::to_cpu_storage_owned(data))),
720 Device::Cuda(device) => {
721 let storage = S::to_cpu_storage_owned(data);
722 let storage = device.storage_from_cpu_storage_owned(storage)?;
723 Ok(Storage::Cuda(storage))
724 }
725 Device::Metal(device) => {
726 let storage = S::to_cpu_storage_owned(data);
727 let storage = device.storage_from_cpu_storage_owned(storage)?;
728 Ok(Storage::Metal(storage))
729 }
730 #[cfg(feature = "rocm")]
731 Device::Rocm(device) => {
732 let storage = S::to_cpu_storage_owned(data);
733 let storage = device.storage_from_cpu_storage_owned(storage)?;
734 Ok(Storage::Rocm(storage))
735 }
736 #[cfg(feature = "vulkan")]
737 Device::Vulkan(device) => {
738 let storage = S::to_cpu_storage_owned(data);
739 let storage = device.storage_from_cpu_storage_owned(storage)?;
740 Ok(Storage::Vulkan(storage))
741 }
742 #[cfg(feature = "wgpu")]
743 Device::Wgpu(device) => {
744 let storage = S::to_cpu_storage_owned(data);
745 let storage = device.storage_from_cpu_storage_owned(storage)?;
746 Ok(Storage::Wgpu(storage))
747 }
748 }
749 }
750
751 pub fn synchronize(&self) -> Result<()> {
752 match self {
753 Self::Cpu => Ok(()),
754 Self::Cuda(d) => d.synchronize(),
755 Self::Metal(d) => d.synchronize(),
756 #[cfg(feature = "rocm")]
757 Self::Rocm(d) => d.synchronize(),
758 #[cfg(feature = "vulkan")]
759 Self::Vulkan(d) => d.synchronize(),
760 #[cfg(feature = "wgpu")]
761 Self::Wgpu(d) => d.synchronize(),
762 }
763 }
764}