ferrotensor_backend/
pool.rs1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3use wgpu::{Buffer, BufferDescriptor, BufferUsages, Device};
4
5pub const DEFAULT_MAX_POOLED_BYTES: u64 = 512 * 1024 * 1024;
7
8pub struct BufferPool {
15 buffers: Mutex<PoolState>,
16 usage: BufferUsages,
17}
18
19#[derive(Default)]
20struct PoolState {
21 free: HashMap<u64, Vec<Arc<Buffer>>>,
22 pooled_bytes: u64,
23 max_pooled_bytes: u64,
24}
25
26impl std::fmt::Debug for BufferPool {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 let state = self.buffers.lock().unwrap();
29 let counts: HashMap<u64, usize> = state
30 .free
31 .iter()
32 .map(|(sz, list)| (*sz, list.len()))
33 .collect();
34 f.debug_struct("BufferPool")
35 .field("usage", &self.usage)
36 .field("buffer_counts", &counts)
37 .field("pooled_bytes", &state.pooled_bytes)
38 .finish()
39 }
40}
41
42impl BufferPool {
43 pub fn new(usage: BufferUsages) -> Self {
45 Self {
46 buffers: Mutex::new(PoolState {
47 max_pooled_bytes: DEFAULT_MAX_POOLED_BYTES,
48 ..PoolState::default()
49 }),
50 usage,
51 }
52 }
53
54 pub fn set_max_pooled_bytes(&self, max: u64) {
57 let mut state = self.buffers.lock().unwrap();
58 state.max_pooled_bytes = max;
59 if state.pooled_bytes > max {
60 state.free.clear();
61 state.pooled_bytes = 0;
62 }
63 }
64
65 pub fn pooled_bytes(&self) -> u64 {
67 self.buffers.lock().unwrap().pooled_bytes
68 }
69
70 pub fn get(&self, device: &Device, size: u64) -> Arc<Buffer> {
72 let mut state = self.buffers.lock().unwrap();
73 if let Some(buffer) = state.free.get_mut(&size).and_then(Vec::pop) {
74 state.pooled_bytes -= size;
75 return buffer;
76 }
77
78 Arc::new(device.create_buffer(&BufferDescriptor {
80 label: Some("Pooled Buffer"),
81 size,
82 usage: self.usage,
83 mapped_at_creation: false,
84 }))
85 }
86
87 pub fn return_buffer(&self, size: u64, buffer: Arc<Buffer>) {
89 let mut state = self.buffers.lock().unwrap();
90 if state.pooled_bytes + size > state.max_pooled_bytes {
91 return;
93 }
94 state.pooled_bytes += size;
95 state.free.entry(size).or_default().push(buffer);
96 }
97
98 pub fn clear(&self) {
100 let mut state = self.buffers.lock().unwrap();
101 state.free.clear();
102 state.pooled_bytes = 0;
103 }
104}