cubecl_hip/compute/storage/
gpu.rs1use crate::compute::uninit_vec;
2use cubecl_common::backtrace::BackTrace;
3use cubecl_core::server::IoError;
4use cubecl_hip_sys::HIP_SUCCESS;
5use cubecl_runtime::storage::{ComputeStorage, StorageHandle, StorageId, StorageUtilization};
6use std::collections::HashMap;
7
8pub struct GpuStorage {
13 mem_alignment: usize,
14 memory: HashMap<StorageId, cubecl_hip_sys::hipDeviceptr_t>,
15 deallocations: Vec<StorageId>,
16 ptr_bindings: PtrBindings,
17}
18
19#[derive(new, Debug)]
21pub struct GpuResource {
22 pub ptr: cubecl_hip_sys::hipDeviceptr_t,
24 pub binding: cubecl_hip_sys::hipDeviceptr_t,
26 pub size: u64,
28}
29
30impl GpuStorage {
31 pub fn new(mem_alignment: usize) -> Self {
37 Self {
38 mem_alignment,
39 memory: HashMap::new(),
40 deallocations: Vec::new(),
41 ptr_bindings: PtrBindings::new(),
42 }
43 }
44
45 pub fn perform_deallocations(&mut self) {
49 for id in self.deallocations.drain(..) {
50 if let Some(ptr) = self.memory.remove(&id) {
51 unsafe {
52 cubecl_hip_sys::hipFree(ptr);
53 }
54 }
55 }
56 }
57}
58
59struct PtrBindings {
63 slots: Vec<u64>,
64 cursor: usize,
65}
66
67impl PtrBindings {
68 fn new() -> Self {
70 Self {
71 slots: uninit_vec(crate::device::AMD_MAX_BINDINGS as usize),
72 cursor: 0,
73 }
74 }
75
76 fn register(&mut self, ptr: u64) -> &u64 {
86 self.slots[self.cursor] = ptr;
87 let ptr_ref = self.slots.get(self.cursor).unwrap();
88
89 self.cursor += 1;
90
91 if self.cursor >= self.slots.len() {
93 self.cursor = 0;
94 }
95
96 ptr_ref
97 }
98}
99
100impl ComputeStorage for GpuStorage {
101 type Resource = GpuResource;
102
103 fn alignment(&self) -> usize {
104 self.mem_alignment
105 }
106
107 fn get(&mut self, handle: &StorageHandle) -> Self::Resource {
108 let ptr = (*self.memory.get(&handle.id).unwrap()) as u64;
109
110 let offset = handle.offset();
111 let size = handle.size();
112 let ptr = self.ptr_bindings.register(ptr + offset);
113
114 GpuResource::new(
115 *ptr as cubecl_hip_sys::hipDeviceptr_t,
116 std::ptr::from_ref(ptr) as *mut std::ffi::c_void,
117 size,
118 )
119 }
120
121 #[cfg_attr(
122 feature = "tracing",
123 tracing::instrument(level = "trace", skip(self, size))
124 )]
125 fn alloc(&mut self, size: u64) -> Result<StorageHandle, IoError> {
126 let id = StorageId::new();
127 unsafe {
128 let mut dptr: *mut ::std::os::raw::c_void = std::ptr::null_mut();
129 let status = cubecl_hip_sys::hipMalloc(&mut dptr, size as usize);
130
131 match status {
132 HIP_SUCCESS => {}
133 other => {
134 return Err(IoError::Unknown {
135 description: format!("HIP allocation error: {other}"),
136 backtrace: BackTrace::capture(),
137 });
138 }
139 }
140 self.memory.insert(id, dptr);
141 };
142 Ok(StorageHandle::new(
143 id,
144 StorageUtilization { offset: 0, size },
145 ))
146 }
147
148 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip(self)))]
149 fn dealloc(&mut self, id: StorageId) {
150 self.deallocations.push(id);
151 }
152}
153
154unsafe impl Send for GpuStorage {}
155unsafe impl Send for GpuResource {}
156
157impl core::fmt::Debug for GpuStorage {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 f.write_str("GpuStorage".to_string().as_str())
160 }
161}