cubecl_runtime/memory_management/memory_pool/
handle.rs1use crate::memory_management::MemoryHandle;
2use alloc::{sync::Arc, vec::Vec};
3use core::cell::Cell;
4
5#[derive(Debug)]
7pub struct ManagedMemoryHandle {
8 descriptor: Arc<ManagedMemoryDescriptor>,
9 handle_count: Arc<()>,
11}
12
13#[derive(Debug)]
15pub struct ManagedMemoryBinding {
16 descriptor: Arc<ManagedMemoryDescriptor>,
17}
18
19#[derive(Debug, Default)]
21pub struct SharedMemoryBindings {
22 pub bindings: Vec<ManagedMemoryBinding>,
24}
25
26impl Clone for ManagedMemoryHandle {
27 fn clone(&self) -> Self {
28 Self {
29 descriptor: self.descriptor.clone(),
30 handle_count: self.handle_count.clone(),
31 }
32 }
33}
34
35pub(crate) struct ManagedMemoryDescriptor {
47 pub(crate) id: ManagedMemoryId,
48 location: Cell<MemoryLocation>,
49}
50
51unsafe impl Send for ManagedMemoryDescriptor {}
56unsafe impl Sync for ManagedMemoryDescriptor {}
57
58impl core::fmt::Debug for ManagedMemoryDescriptor {
59 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60 f.debug_struct("ManagedMemoryDescriptor")
61 .field("id", &self.id)
62 .field("location", &self.location())
63 .finish()
64 }
65}
66
67#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
68pub struct ManagedMemoryId {
70 pub(crate) value: usize,
71}
72
73impl PartialEq for ManagedMemoryDescriptor {
74 fn eq(&self, other: &Self) -> bool {
75 self.id == other.id
76 }
77}
78
79impl Eq for ManagedMemoryDescriptor {}
80
81#[derive(Clone, Copy, Debug)]
82pub(crate) struct MemoryLocation {
84 pub pool: u8,
86 pub page: u16,
88 pub slice: u32,
90 pub init: u8,
92}
93
94impl ManagedMemoryDescriptor {
95 pub(crate) fn update_location(&self, location: MemoryLocation) {
97 self.location.set(location);
98 }
99
100 pub(crate) fn update_slice(&self, slice: u32) {
102 self.location.update(|mut loc| {
103 loc.slice = slice;
104 loc
105 });
106 }
107
108 pub fn update_page(&self, page: u16) {
110 self.location.update(|mut loc| {
111 loc.page = page;
112 loc
113 });
114 }
115
116 pub(crate) fn location(&self) -> MemoryLocation {
118 self.location.get()
119 }
120
121 pub(crate) fn slice(&self) -> usize {
122 self.location.get().slice as usize
123 }
124
125 pub(crate) fn page(&self) -> usize {
126 self.location.get().page as usize
127 }
128}
129
130impl MemoryLocation {
131 pub(crate) fn new(pool: u8, page: u16, slice: u32) -> Self {
133 Self {
134 pool,
135 page,
136 slice,
137 init: 1,
138 }
139 }
140
141 pub(crate) fn uninit() -> Self {
143 Self {
144 pool: 0,
145 page: 0,
146 slice: 0,
147 init: 0,
148 }
149 }
150}
151
152impl ManagedMemoryHandle {
153 pub fn new() -> Self {
155 let value = Self::gen_id();
156
157 Self {
158 descriptor: Arc::new(ManagedMemoryDescriptor {
159 id: ManagedMemoryId { value },
160 location: Cell::new(MemoryLocation::uninit()),
161 }),
162 handle_count: Arc::new(()),
163 }
164 }
165
166 pub(crate) fn descriptor(&self) -> &ManagedMemoryDescriptor {
168 &self.descriptor
169 }
170
171 pub fn can_mut(&self) -> bool {
173 Arc::strong_count(&self.handle_count) <= 2
174 }
175
176 pub fn is_free(&self) -> bool {
178 Arc::strong_count(&self.descriptor) <= 1
179 }
180
181 pub fn binding(self) -> ManagedMemoryBinding {
183 ManagedMemoryBinding {
184 descriptor: self.descriptor.clone(),
185 }
186 }
187
188 fn gen_id() -> usize {
189 static COUNTER: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
190 let value = COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
191 if value == usize::MAX {
192 core::panic!("Memory ID overflowed");
193 }
194 value
195 }
196}
197
198impl ManagedMemoryBinding {
199 pub(crate) fn descriptor(&self) -> &ManagedMemoryDescriptor {
201 &self.descriptor
202 }
203}
204
205impl Default for ManagedMemoryHandle {
206 fn default() -> Self {
207 Self::new()
208 }
209}
210
211impl Clone for ManagedMemoryBinding {
212 fn clone(&self) -> Self {
213 Self {
214 descriptor: self.descriptor.clone(),
215 }
216 }
217}
218
219impl MemoryHandle<ManagedMemoryBinding> for ManagedMemoryHandle {
220 fn can_mut(&self) -> bool {
221 self.can_mut()
222 }
223
224 fn binding(self) -> ManagedMemoryBinding {
225 self.binding()
226 }
227}
228
229impl SharedMemoryBindings {
230 pub fn clear(&mut self) {
232 self.bindings.clear();
233 }
234
235 pub fn is_empty(&self) -> bool {
237 self.bindings.is_empty()
238 }
239
240 pub fn push(&mut self, binding: ManagedMemoryBinding) {
242 self.bindings.push(binding)
243 }
244}
245
246impl cubecl_common::pool::Reclaim for SharedMemoryBindings {
247 fn reclaim(&mut self) {
248 self.clear();
249 }
250}
251
252pub fn optimal_align(shape: usize, elem_size: usize, buffer_align: usize) -> usize {
256 if shape == 1 {
257 elem_size
258 } else {
259 (shape * elem_size)
260 .next_power_of_two()
261 .clamp(16, buffer_align)
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 #[test]
270 fn test_memory_id_mutability() {
271 let handle1 = ManagedMemoryHandle::new();
272 handle1.descriptor().update_slice(4);
273 assert_eq!(handle1.descriptor().slice(), 4);
274
275 let handle2 = ManagedMemoryHandle::new();
276 handle2
277 .clone()
278 .descriptor()
279 .update_location(handle1.descriptor().location());
280 assert_eq!(handle2.descriptor().slice(), 4);
281 }
282
283 #[test]
284 fn test_location_visible_through_shared_arc() {
285 let handle = ManagedMemoryHandle::new();
286 let handle2 = handle.clone();
287
288 let location = MemoryLocation::new(1, 2, 3);
289 handle.descriptor().update_location(location);
290
291 assert_eq!(handle2.descriptor().location().pool, 1);
292 assert_eq!(handle2.descriptor().location().page, 2);
293 assert_eq!(handle2.descriptor().location().slice, 3);
294 assert_eq!(handle2.descriptor().location().init, 1);
295
296 handle.descriptor().update_slice(42);
297 assert_eq!(handle2.descriptor().slice(), 42);
298 }
299}