atlas_core/tensor.rs
1// SPDX-License-Identifier: AGPL-3.0-only
2
3use crate::dtype::DType;
4
5/// A zero-copy reference to a GPU tensor, typically from PyTorch via data_ptr().
6///
7/// Atlas never allocates or copies tensor data — it receives raw CUDA device
8/// pointers from Python and wraps them for kernel launches.
9#[derive(Debug, Clone)]
10pub struct TensorRef {
11 /// Raw CUDA device pointer (from torch.Tensor.data_ptr())
12 pub ptr: u64,
13
14 /// Shape dimensions (e.g., [batch, seq_len, hidden_size])
15 pub shape: Vec<usize>,
16
17 /// Strides in elements (not bytes)
18 pub strides: Vec<usize>,
19
20 /// Element data type
21 pub dtype: DType,
22}
23
24impl TensorRef {
25 /// Create a new tensor reference from a raw pointer and shape.
26 /// Assumes contiguous (row-major) layout.
27 pub fn new(ptr: u64, shape: Vec<usize>, dtype: DType) -> Self {
28 let strides = Self::contiguous_strides(&shape);
29 Self {
30 ptr,
31 shape,
32 strides,
33 dtype,
34 }
35 }
36
37 /// Total number of elements.
38 pub fn numel(&self) -> usize {
39 self.shape.iter().product()
40 }
41
42 /// Total size in bytes.
43 pub fn size_bytes(&self) -> usize {
44 let bits = self.numel() * self.dtype.element_size_bits();
45 bits.div_ceil(8) // round up for sub-byte types
46 }
47
48 /// Number of dimensions.
49 pub fn ndim(&self) -> usize {
50 self.shape.len()
51 }
52
53 /// Compute contiguous (C-order / row-major) strides from shape.
54 fn contiguous_strides(shape: &[usize]) -> Vec<usize> {
55 let mut strides = vec![1usize; shape.len()];
56 for i in (0..shape.len().saturating_sub(1)).rev() {
57 strides[i] = strides[i + 1] * shape[i + 1];
58 }
59 strides
60 }
61
62 /// Raw pointer cast to a typed device pointer (for kernel launches).
63 pub fn as_device_ptr<T>(&self) -> *const T {
64 self.ptr as *const T
65 }
66
67 /// Mutable raw pointer cast.
68 pub fn as_device_ptr_mut<T>(&self) -> *mut T {
69 self.ptr as *mut T
70 }
71}