torsh_ffi/python/tensor/
memory.rs1use crate::error::FfiResult;
2use once_cell::sync::Lazy;
3use parking_lot::Mutex;
4use std::collections::VecDeque;
5use std::sync::atomic::{AtomicUsize, Ordering};
6
7#[derive(Debug)]
9pub struct MemoryPool {
10 free_blocks: Mutex<std::collections::HashMap<usize, VecDeque<Vec<f32>>>>,
12 allocations: AtomicUsize,
14 deallocations: AtomicUsize,
15 pool_hits: AtomicUsize,
16 pool_misses: AtomicUsize,
17 max_pool_size: usize,
18}
19
20impl MemoryPool {
21 pub fn new(max_pool_size: usize) -> Self {
23 Self {
24 free_blocks: Mutex::new(std::collections::HashMap::new()),
25 allocations: AtomicUsize::new(0),
26 deallocations: AtomicUsize::new(0),
27 pool_hits: AtomicUsize::new(0),
28 pool_misses: AtomicUsize::new(0),
29 max_pool_size,
30 }
31 }
32
33 pub fn allocate(&self, size: usize) -> FfiResult<Vec<f32>> {
35 let mut free_blocks = self.free_blocks.lock();
36
37 if let Some(blocks) = free_blocks.get_mut(&size) {
38 if let Some(mut block) = blocks.pop_front() {
39 block.clear();
41 block.resize(size, 0.0);
42 self.pool_hits.fetch_add(1, Ordering::Relaxed);
43 self.allocations.fetch_add(1, Ordering::Relaxed);
44 return Ok(block);
45 }
46 }
47
48 self.pool_misses.fetch_add(1, Ordering::Relaxed);
50 self.allocations.fetch_add(1, Ordering::Relaxed);
51 Ok(vec![0.0; size])
52 }
53
54 pub fn deallocate(&self, mut data: Vec<f32>) -> FfiResult<()> {
56 let size = data.capacity();
57
58 if size > 0 && size <= self.max_pool_size {
60 let mut free_blocks = self.free_blocks.lock();
61
62 let blocks = free_blocks.entry(size).or_insert_with(VecDeque::new);
63
64 if blocks.len() < 10 {
66 data.clear();
67 blocks.push_back(data);
68 }
69 }
70
71 self.deallocations.fetch_add(1, Ordering::Relaxed);
72 Ok(())
73 }
74
75 pub fn stats(&self) -> FfiResult<MemoryPoolStats> {
77 Ok(MemoryPoolStats {
78 allocations: self.allocations.load(Ordering::Relaxed),
79 deallocations: self.deallocations.load(Ordering::Relaxed),
80 pool_hits: self.pool_hits.load(Ordering::Relaxed),
81 pool_misses: self.pool_misses.load(Ordering::Relaxed),
82 active_blocks: self.free_blocks.lock().values().map(|v| v.len()).sum(),
83 })
84 }
85
86 pub fn clear(&self) -> FfiResult<()> {
88 self.free_blocks.lock().clear();
89 Ok(())
90 }
91}
92
93#[derive(Debug, Clone)]
95pub struct MemoryPoolStats {
96 pub allocations: usize,
97 pub deallocations: usize,
98 pub pool_hits: usize,
99 pub pool_misses: usize,
100 pub active_blocks: usize,
101}
102
103pub static MEMORY_POOL: Lazy<MemoryPool> = Lazy::new(|| {
105 MemoryPool::new(1024 * 1024) });