1#![deny(missing_docs)]
13
14pub mod actions;
15pub mod arena;
16pub mod nixl;
17#[cfg(target_os = "linux")]
18pub mod numa;
19
20pub mod offset;
22
23pub mod pool;
25
26pub mod prelude;
28
29mod device;
30mod disk;
31mod external;
32mod pinned;
33mod system;
34mod tensor;
35
36#[cfg(test)]
37mod tests;
38
39pub use arena::{ArenaAllocator, ArenaBuffer, ArenaError};
40pub use device::DeviceStorage;
41pub use disk::DiskStorage;
42pub use external::ExternalDeviceMemory;
43#[cfg(target_os = "linux")]
44pub use numa::{NumaNode, is_numa_disabled, is_numa_enabled};
45pub use offset::OffsetBuffer;
46pub use pinned::PinnedStorage;
47pub use pool::{CudaMemPool, CudaMemPoolBuilder};
48pub use system::SystemStorage;
49pub use tensor::{TensorDescriptor, TensorDescriptorExt};
50
51use serde::{Deserialize, Serialize};
52use std::any::Any;
53use std::fmt;
54use std::sync::Arc;
55use thiserror::Error;
56
57pub type Result<T> = std::result::Result<T, StorageError>;
59
60pub trait MemoryDescriptor: Send + Sync + fmt::Debug {
65 fn addr(&self) -> usize;
67
68 fn size(&self) -> usize;
70
71 fn storage_kind(&self) -> StorageKind;
73
74 fn as_any(&self) -> &dyn Any;
76
77 fn nixl_descriptor(&self) -> Option<nixl::NixlDescriptor>;
79}
80
81#[derive(Debug, Error)]
83#[allow(missing_docs)]
84pub enum StorageError {
85 #[error("allocation failed: {0}")]
86 AllocationFailed(String),
87
88 #[error("registration failed: {0}")]
89 RegistrationFailed(String),
90
91 #[error("operation failed: {0}")]
92 OperationFailed(String),
93
94 #[error("unsupported operation: {0}")]
95 Unsupported(String),
96
97 #[error("I/O error: {0}")]
98 Io(#[from] std::io::Error),
99
100 #[error("CUDA error: {0}")]
102 Cuda(#[from] cudarc::driver::DriverError),
103
104 #[error("NIXL error: {0}")]
105 Nixl(#[from] nixl_sys::NixlError),
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
110pub enum StorageKind {
111 System,
113
114 Pinned,
117
118 Device(u32),
121
122 Disk(u64),
124}
125
126impl StorageKind {
127 pub fn cuda_device_index(&self) -> Option<u32> {
129 match self {
130 StorageKind::Device(idx) => Some(*idx),
131 _ => None,
132 }
133 }
134
135 pub fn is_cuda(&self) -> bool {
137 matches!(self, StorageKind::Device(_))
138 }
139
140 pub fn is_system(&self) -> bool {
142 matches!(self, StorageKind::System)
143 }
144
145 pub fn is_pinned(&self) -> bool {
147 matches!(self, StorageKind::Pinned)
148 }
149
150 pub fn is_disk(&self) -> bool {
152 matches!(self, StorageKind::Disk(_))
153 }
154}
155
156#[derive(Clone)]
158pub struct Buffer(Arc<dyn MemoryDescriptor>);
159
160impl Buffer {
161 pub fn new<S: MemoryDescriptor + 'static>(memory: S) -> Self {
166 Buffer(Arc::new(memory))
167 }
168}
169
170impl MemoryDescriptor for Buffer {
171 fn addr(&self) -> usize {
172 self.0.addr()
173 }
174 fn size(&self) -> usize {
175 self.0.size()
176 }
177 fn storage_kind(&self) -> StorageKind {
178 self.0.storage_kind()
179 }
180 fn as_any(&self) -> &dyn Any {
181 self.0.as_any()
182 }
183 fn nixl_descriptor(&self) -> Option<nixl::NixlDescriptor> {
184 self.0.nixl_descriptor()
185 }
186}
187
188impl std::ops::Deref for Buffer {
189 type Target = dyn MemoryDescriptor;
190
191 fn deref(&self) -> &Self::Target {
192 self.0.as_ref()
193 }
194}
195
196impl std::fmt::Debug for Buffer {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 f.debug_struct("Buffer")
199 .field("addr", &self.addr())
200 .field("size", &self.size())
201 .field("kind", &self.storage_kind())
202 .finish()
203 }
204}
205
206pub fn create_buffer<S: MemoryDescriptor + 'static>(memory: S) -> Buffer {
208 Buffer(Arc::new(memory))
209}
210
211impl Buffer {
212 pub fn from_arc(arc: Arc<dyn MemoryDescriptor>) -> Self {
214 Buffer(arc)
215 }
216}
217
218impl From<Arc<dyn MemoryDescriptor>> for Buffer {
220 fn from(arc: Arc<dyn MemoryDescriptor>) -> Self {
221 Buffer::from_arc(arc)
222 }
223}
224
225impl From<Arc<dyn nixl::NixlMemory + Send + Sync>> for Buffer {
226 fn from(arc: Arc<dyn nixl::NixlMemory + Send + Sync>) -> Self {
227 Buffer::new(arc)
229 }
230}
231
232#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
234pub struct MemoryRegion {
235 pub addr: usize,
237
238 pub size: usize,
240}
241
242impl MemoryRegion {
243 pub fn new(addr: usize, size: usize) -> Self {
245 Self { addr, size }
246 }
247
248 #[inline]
250 pub fn addr(&self) -> usize {
251 self.addr
252 }
253
254 #[inline]
256 pub fn size(&self) -> usize {
257 self.size
258 }
259
260 #[cfg(feature = "unsafe-slices")]
268 pub unsafe fn as_slice(&self) -> Result<&[u8]> {
269 if self.size == 0 {
270 return Ok(&[]);
271 }
272 unsafe {
274 Ok(std::slice::from_raw_parts(
275 self.addr as *const u8,
276 self.size,
277 ))
278 }
279 }
280
281 #[cfg(feature = "unsafe-slices")]
289 pub unsafe fn as_slice_mut(&mut self) -> Result<&mut [u8]> {
290 if self.size == 0 {
291 return Ok(&mut []);
292 }
293 unsafe {
295 Ok(std::slice::from_raw_parts_mut(
296 self.addr as *mut u8,
297 self.size,
298 ))
299 }
300 }
301}
302
303pub use dynamo_truthy::{env_is_truthy, parse_bool, parse_bool_opt};