alloc_test/alloc/
measure.rs1use std::{
2 mem,
3 sync::atomic::{AtomicBool, Ordering},
4};
5
6use derive_more::Display;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Default, Clone, Display, Serialize, Deserialize)]
10#[display(fmt = r#"Currently allocated (B): {current}
11Maximum allocated (B): {peak}
12Total amount of claimed memory (B): {total_size}
13Total number of allocations: (N): {total_num}
14Reallocations (N): {reallocs}
15"#)]
16pub struct MemoryStats {
17 pub current: usize,
18 pub peak: usize,
19 pub total_size: usize,
20 pub total_num: usize,
21 pub reallocs: usize,
22}
23
24static mut TRACE_ALLOCS: AtomicBool = AtomicBool::new(false);
25
26static mut ALLOC_STATS: MemoryStats = MemoryStats {
27 current: 0,
28 peak: 0,
29 total_size: 0,
30 total_num: 0,
31 reallocs: 0,
32};
33
34#[allow(static_mut_refs)]
56pub fn trace_allocs<F: FnOnce() -> O, O>(f: F) -> (O, MemoryStats) {
57 unsafe {
58 while TRACE_ALLOCS
59 .compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire)
60 .is_err()
61 {}
62 let o = f();
63 let stats = mem::take(&mut ALLOC_STATS);
64 TRACE_ALLOCS.store(false, Ordering::Release);
65 (o, stats)
66 }
67}
68
69pub struct MemoryTracingHooks;
70
71#[allow(static_mut_refs)]
72unsafe impl super::allocator::AllocHooks for MemoryTracingHooks {
73 fn on_alloc(&self, _pointer: *mut u8, size: usize, _align: usize) {
74 unsafe {
75 if TRACE_ALLOCS.load(Ordering::Acquire) {
76 ALLOC_STATS.current += size;
78 ALLOC_STATS.total_size += size;
79 ALLOC_STATS.total_num += 1;
80 if ALLOC_STATS.current > ALLOC_STATS.peak {
81 ALLOC_STATS.peak = ALLOC_STATS.current;
82 }
83 }
84 }
85 }
86
87 fn on_dealloc(&self, _pointer: *mut u8, size: usize, _align: usize) {
88 unsafe {
89 if TRACE_ALLOCS.load(Ordering::Acquire) {
90 ALLOC_STATS.current = ALLOC_STATS.current.saturating_sub(size);
91 }
92 }
93 }
94
95 fn on_alloc_zeroed(&self, pointer: *mut u8, size: usize, align: usize) {
96 self.on_alloc(pointer, size, align);
97 }
98
99 fn on_realloc(
100 &self,
101 old_pointer: *mut u8,
102 new_pointer: *mut u8,
103 old_size: usize,
104 new_size: usize,
105 align: usize,
106 ) {
107 unsafe {
108 if TRACE_ALLOCS.load(Ordering::Acquire) {
109 ALLOC_STATS.reallocs += 1;
111 }
112 }
113 self.on_dealloc(old_pointer, old_size, align);
114 self.on_alloc(new_pointer, new_size, align);
115 }
116}