hft_benchmarks/
allocation.rs1use jemallocator::Jemalloc;
4use crate::BenchmarkResults;
5
6#[global_allocator]
7static GLOBAL: Jemalloc = Jemalloc;
8
9const DEFAULT_ITERATIONS: usize = 10_000;
10const ALLOCATION_SIZES: [usize; 6] = [64, 128, 256, 512, 1024, 4096];
11
12pub fn benchmark_allocations() {
13 benchmark_allocations_with_iterations(DEFAULT_ITERATIONS)
14}
15
16pub fn benchmark_allocations_with_iterations(iterations: usize) {
17 println!("Benchmarking memory allocations ({iterations} iterations per size)...");
18
19 for &size in &ALLOCATION_SIZES {
20 let mut results = BenchmarkResults::new(format!("allocation_{size}B"));
21
22 for _ in 0..iterations {
23 let (_, elapsed) = crate::timing::time_function(|| vec![0u8; size]);
24 results.record(elapsed);
25 }
26
27 println!("{}", results.analyze().summary());
28 }
29}
30
31pub struct SimpleObjectPool<T> {
32 objects: Vec<Box<T>>,
33}
34
35impl<T> Default for SimpleObjectPool<T> {
36 fn default() -> Self {
37 Self::new()
38 }
39}
40
41impl<T> SimpleObjectPool<T> {
42 pub fn new() -> Self {
43 Self {
44 objects: Vec::with_capacity(1000),
45 }
46 }
47
48 pub fn get(&mut self) -> Box<T>
49 where
50 T: Default,
51 {
52 self.objects.pop().unwrap_or_else(|| Box::new(T::default()))
53 }
54
55 pub fn put(&mut self, obj: Box<T>) {
56 if self.objects.len() < 1000 {
57 self.objects.push(obj);
58 }
59 }
60}
61
62pub fn benchmark_object_pools() {
64 benchmark_object_pools_with_iterations(DEFAULT_ITERATIONS)
65}
66
67pub fn benchmark_object_pools_with_iterations(iterations: usize) {
69 println!("Benchmarking object pools vs direct allocation...");
70
71 let mut pool = SimpleObjectPool::<u64>::new();
72 let mut pool_results = BenchmarkResults::new("pool_allocation".to_string());
73 let mut direct_results = BenchmarkResults::new("direct_allocation".to_string());
74
75 for _ in 0..iterations {
76 let (obj, elapsed) = crate::timing::time_function(|| pool.get());
77 pool.put(obj);
78 pool_results.record(elapsed);
79
80 let (_, elapsed) = crate::timing::time_function(|| Box::new(0u64));
81 direct_results.record(elapsed);
82 }
83
84 println!("Pool allocation: {}", pool_results.analyze().summary());
85 println!("Direct allocation: {}", direct_results.analyze().summary());
86}
87
88pub fn benchmark_aligned_allocations() {
90 benchmark_aligned_allocations_with_iterations(DEFAULT_ITERATIONS / 2)
91}
92
93pub fn benchmark_aligned_allocations_with_iterations(iterations: usize) {
95 println!("Benchmarking aligned vs unaligned allocations...");
96
97 let mut aligned_results = BenchmarkResults::new("aligned_allocation".to_string());
98 let mut unaligned_results = BenchmarkResults::new("unaligned_allocation".to_string());
99
100 let aligned_layout = std::alloc::Layout::from_size_align(1024, 64).unwrap();
101 let unaligned_layout = std::alloc::Layout::from_size_align(1024, 8).unwrap();
102
103 for _ in 0..iterations {
104 let (_, elapsed) = crate::timing::time_function(|| unsafe {
105 let ptr = std::alloc::alloc(aligned_layout);
106 if !ptr.is_null() {
107 std::alloc::dealloc(ptr, aligned_layout);
108 }
109 });
110 aligned_results.record(elapsed);
111
112 let (_, elapsed) = crate::timing::time_function(|| unsafe {
113 let ptr = std::alloc::alloc(unaligned_layout);
114 if !ptr.is_null() {
115 std::alloc::dealloc(ptr, unaligned_layout);
116 }
117 });
118 unaligned_results.record(elapsed);
119 }
120
121 println!("Aligned allocation: {}", aligned_results.analyze().summary());
122 println!("Unaligned allocation: {}", unaligned_results.analyze().summary());
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_object_pool() {
131 let mut pool = SimpleObjectPool::<u64>::new();
132
133 let obj1 = pool.get();
134 let obj2 = pool.get();
135
136 pool.put(obj1);
137 pool.put(obj2);
138
139 let obj3 = pool.get();
141 let obj4 = pool.get();
142
143 drop(obj3);
144 drop(obj4);
145 }
146
147 #[test]
148 fn test_allocation_benchmarks() {
149 crate::quick_calibrate_tsc_frequency();
150
151 benchmark_object_pools_with_iterations(10);
154 benchmark_allocations_with_iterations(10);
155 benchmark_aligned_allocations_with_iterations(10);
156 }
157
158 #[test]
159 fn test_object_pool_reuse() {
160 let mut pool = SimpleObjectPool::<u64>::new();
161
162 let obj1 = pool.get();
164 assert_eq!(*obj1, 0); pool.put(obj1);
168
169 assert_eq!(pool.objects.len(), 1);
171
172 let obj2 = pool.get();
174 assert_eq!(*obj2, 0);
175
176 assert_eq!(pool.objects.len(), 0);
178 }
179
180 #[test]
181 fn test_pool_capacity_limit() {
182 let mut pool = SimpleObjectPool::<u64>::new();
183
184 for _ in 0..1100 {
186 pool.put(Box::new(42));
187 }
188
189 assert!(pool.objects.len() <= 1000);
191 }
192}