1use crate ::prelude :: *;
7use std ::time ::Instant;
8
9#[ derive(Debug, Clone) ]
11pub struct AllocationResult
12{
13 pub name: String,
15 pub estimated_allocations: usize,
17 pub timing_result: BenchmarkResult,
19 pub allocation_rate: f64,
21}
22
23impl AllocationResult
24{
25 #[ must_use ]
27 pub fn compare_allocations(&self, other: &AllocationResult) -> AllocationComparison
28 {
29 AllocationComparison
30 {
31 baseline: self.clone(),
32 current: other.clone(),
33 allocation_improvement: if other.allocation_rate > 0.0
34 {
35 (self.allocation_rate - other.allocation_rate) / other.allocation_rate * 100.0
36 }
37 else
38 {
39 0.0
40 },
41 }
42 }
43}
44
45#[ derive(Debug, Clone) ]
47pub struct AllocationComparison
48{
49 pub baseline: AllocationResult,
51 pub current: AllocationResult,
53 pub allocation_improvement: f64,
55}
56
57impl AllocationComparison
58{
59 #[ must_use ]
61 pub fn to_markdown( &self ) -> String
62 {
63 let mut output = String ::new();
64
65 output.push_str("## Memory Allocation Comparison\n\n");
66 output.push_str("| Approach | Allocations/Op | Ops/sec | Memory Efficiency |\n");
67 output.push_str("|----------|----------------|---------|------------------|\n");
68
69 output.push_str(&format!(
70 "| {} | {:.1} | {:.0} | Baseline |\n",
71 self.baseline.name,
72 self.baseline.allocation_rate,
73 self.baseline.timing_result.operations_per_second()
74 ));
75
76 let efficiency = if self.allocation_improvement > 0.0
77 {
78 format!("{:.1}% fewer allocs", self.allocation_improvement)
79 }
80 else
81 {
82 format!("{:.1}% more allocs", -self.allocation_improvement)
83 };
84
85 output.push_str(&format!(
86 "| {} | {:.1} | {:.0} | {} |\n",
87 self.current.name,
88 self.current.allocation_rate,
89 self.current.timing_result.operations_per_second(),
90 efficiency
91 ));
92
93 if self.allocation_improvement > 50.0
94 {
95 output.push_str("\n**๐ Significant memory optimization achieved!**\n");
96 }
97 else if self.allocation_improvement > 10.0
98 {
99 output.push_str("\n**๐ Good memory optimization**\n");
100 }
101 else if self.allocation_improvement < -20.0
102 {
103 output.push_str("\n**โ ๏ธ Memory usage increased significantly**\n");
104 }
105
106 output
107 }
108}
109
110pub fn bench_with_allocation_tracking< F >(
112 name: &str,
113 mut operation: F,
114 estimated_allocs_per_call: usize,
115) -> AllocationResult
116where
117 F: FnMut() + Send,
118{
119 println!("๐ง Memory allocation tracking: {name}");
120
121 let timing_result = bench_function(name, ||
123 {
124 operation();
125 });
126
127 let total_operations = timing_result.times.len();
129 let estimated_total_allocations = total_operations * estimated_allocs_per_call;
130 let allocation_rate = estimated_allocs_per_call as f64;
131
132 println!(" ๐ Est. allocations: {estimated_total_allocations} ({allocation_rate:.1}/op)");
133
134 AllocationResult
135 {
136 name: name.to_string(),
137 estimated_allocations: estimated_total_allocations,
138 timing_result,
139 allocation_rate,
140 }
141}
142
143pub fn bench_string_operations< F1, F2 >(
145 baseline_name: &str,
146 optimized_name: &str,
147 baseline_fn: F1,
148 optimized_fn: F2,
149 test_data: &[ &[ &str]],
150) -> AllocationComparison
151where
152 F1: Fn(&[ &str]) -> String + Send + Sync,
153 F2: Fn(&[ &str]) -> String + Send + Sync,
154{
155 println!("๐งต String operations comparison");
156
157 let baseline_result = bench_with_allocation_tracking(
159 baseline_name,
160 ||
161 {
162 for slices in test_data
163 {
164 let _result = baseline_fn(slices);
165 std ::hint ::black_box(_result);
166 }
167 },
168 test_data.len() * 2, );
170
171 let optimized_result = bench_with_allocation_tracking(
173 optimized_name,
174 ||
175 {
176 for slices in test_data
177 {
178 let _result = optimized_fn(slices);
179 std ::hint ::black_box(_result);
180 }
181 },
182 test_data.len() / 10, );
184
185 optimized_result.compare_allocations(&baseline_result)
186}
187
188#[ derive(Debug, Clone) ]
190pub struct MemoryProfile
191{
192 pub operation_name: String,
194 pub peak_estimated_usage_mb: f64,
196 pub average_usage_mb: f64,
198 pub allocation_hotspots: Vec< String >,
200}
201
202impl MemoryProfile
203{
204 pub fn analyze< F >(name: &str, operation: F, iterations: usize) -> Self
206 where
207 F: Fn() + Send,
208 {
209 println!("๐ Memory profiling: {name}");
210
211 let start_time = Instant ::now();
212
213 for _ in 0..iterations
215 {
216 operation();
217 }
218
219 let duration = start_time.elapsed();
220
221 let ops_per_sec = iterations as f64 / duration.as_secs_f64();
223 let estimated_memory_per_op = if ops_per_sec > 100_000.0
224 {
225 0.001 }
227 else if ops_per_sec > 10000.0
228 {
229 0.01 }
231 else
232 {
233 0.1 };
235
236 let peak_usage = estimated_memory_per_op * iterations as f64;
237 let average_usage = peak_usage * 0.6; let mut hotspots = Vec ::new();
240 if ops_per_sec < 1000.0
241 {
242 hotspots.push("Potential string allocation hotspot".to_string());
243 }
244 if peak_usage > 10.0
245 {
246 hotspots.push("High memory usage detected".to_string());
247 }
248
249 println!(" ๐ Est. peak memory: {peak_usage:.2} MB, avg: {average_usage:.2} MB");
250
251 Self
252 {
253 operation_name: name.to_string(),
254 peak_estimated_usage_mb: peak_usage,
255 average_usage_mb: average_usage,
256 allocation_hotspots: hotspots,
257 }
258 }
259
260 #[ must_use ]
262 pub fn to_markdown( &self ) -> String
263 {
264 let mut output = String ::new();
265
266 output.push_str(&format!("## {} Memory Profile\n\n", self.operation_name));
267 output.push_str(&format!("- **Peak Usage** : {:.2} MB\n", self.peak_estimated_usage_mb));
268 output.push_str(&format!("- **Average Usage** : {:.2} MB\n", self.average_usage_mb));
269
270 if !self.allocation_hotspots.is_empty()
271 {
272 output.push_str("\n**Potential Issues** : \n");
273 for hotspot in &self.allocation_hotspots
274 {
275 output.push_str(&format!("- โ ๏ธ {}\n", hotspot));
276 }
277 }
278 else
279 {
280 output.push_str("\nโ
**No memory issues detected**\n");
281 }
282
283 output
284 }
285}
286