torsh_ffi/python/tensor/
storage.rs1use crate::error::{FfiError, FfiResult};
2use crate::python::tensor::memory::MEMORY_POOL;
3use parking_lot::Mutex;
4use std::sync::atomic::{AtomicUsize, Ordering};
5use std::sync::Arc;
6use torsh_core::DType;
7
8#[derive(Debug, Clone)]
10pub struct TensorStorage {
11 data: Arc<Mutex<Vec<f32>>>,
12 shape: Vec<usize>,
13 dtype: DType,
14 is_external: bool,
16 grad: Arc<Mutex<Option<Vec<f32>>>>,
18 version: Arc<AtomicUsize>,
21}
22
23impl TensorStorage {
24 pub fn new(data: Vec<f32>, shape: Vec<usize>, dtype: DType) -> Self {
26 Self {
27 data: Arc::new(Mutex::new(data)),
28 shape,
29 dtype,
30 is_external: false,
31 grad: Arc::new(Mutex::new(None)),
32 version: Arc::new(AtomicUsize::new(0)),
33 }
34 }
35
36 pub fn new_pooled(shape: Vec<usize>, dtype: DType) -> FfiResult<Self> {
38 let size = shape.iter().product();
39 let data = MEMORY_POOL.allocate(size)?;
40
41 Ok(Self {
42 data: Arc::new(Mutex::new(data)),
43 shape,
44 dtype,
45 is_external: false,
46 grad: Arc::new(Mutex::new(None)),
47 version: Arc::new(AtomicUsize::new(0)),
48 })
49 }
50
51 pub fn from_external(data: Vec<f32>, shape: Vec<usize>, dtype: DType) -> Self {
53 Self {
54 data: Arc::new(Mutex::new(data)),
55 shape,
56 dtype,
57 is_external: true,
58 grad: Arc::new(Mutex::new(None)),
59 version: Arc::new(AtomicUsize::new(0)),
60 }
61 }
62
63 pub fn data(&self) -> parking_lot::MutexGuard<'_, Vec<f32>> {
65 self.data.lock()
66 }
67
68 pub fn data_mut(&self) -> parking_lot::MutexGuard<'_, Vec<f32>> {
70 self.data.lock()
71 }
72
73 pub fn shape(&self) -> &[usize] {
75 &self.shape
76 }
77
78 pub fn dtype(&self) -> DType {
80 self.dtype
81 }
82
83 pub fn view(&self, new_shape: Vec<usize>) -> FfiResult<Self> {
85 let total_elements: usize = new_shape.iter().product();
86 let current_elements: usize = self.shape.iter().product();
87
88 if total_elements != current_elements {
89 return Err(FfiError::ShapeMismatch {
90 expected: vec![current_elements],
91 actual: vec![total_elements],
92 });
93 }
94
95 Ok(Self {
96 data: Arc::clone(&self.data),
97 shape: new_shape,
98 dtype: self.dtype,
99 is_external: self.is_external,
100 grad: Arc::clone(&self.grad),
101 version: Arc::clone(&self.version),
102 })
103 }
104
105 pub fn ref_count(&self) -> usize {
107 Arc::strong_count(&self.data)
108 }
109
110 pub fn is_external(&self) -> bool {
112 self.is_external
113 }
114
115 pub fn grad(&self) -> parking_lot::MutexGuard<'_, Option<Vec<f32>>> {
117 self.grad.lock()
118 }
119
120 pub fn set_grad(&self, grad_data: Option<Vec<f32>>) {
122 *self.grad.lock() = grad_data;
123 }
124
125 pub fn clear_grad(&self) {
127 *self.grad.lock() = None;
128 }
129
130 pub fn version(&self) -> usize {
133 self.version.load(Ordering::Relaxed)
134 }
135
136 pub fn increment_version(&self) {
139 self.version.fetch_add(1, Ordering::Relaxed);
140 }
141}
142
143impl Drop for TensorStorage {
144 fn drop(&mut self) {
145 if !self.is_external && Arc::strong_count(&self.data) == 1 {
147 if let Ok(data) = Arc::try_unwrap(std::mem::replace(
148 &mut self.data,
149 Arc::new(Mutex::new(Vec::new())),
150 )) {
151 let data_vec = data.into_inner();
153 let _ = MEMORY_POOL.deallocate(data_vec);
155 }
156 }
157 }
158}