1use std::time::Instant;
6use sysinfo::{System, ProcessesToUpdate};
7
8use crate::algorithms::{
9 mincut::MinCutClusterer,
10 pagerank::ProcessPageRank,
11 sketch::CountMinSketch,
12 spectral::SpectralAnalyzer,
13};
14
15#[derive(Debug, Clone)]
17pub struct AlgorithmBenchmark {
18 pub name: String,
19 pub iterations: usize,
20 pub total_ms: u64,
21 pub total_ns: u128,
22 pub avg_us: f64,
23 pub avg_ns: f64,
24 pub min_us: u64,
25 pub min_ns: u64,
26 pub max_us: u64,
27 pub max_ns: u64,
28 pub ops_per_sec: f64,
29 pub memory_bytes: usize,
30}
31
32#[derive(Debug, Clone)]
34pub struct BenchmarkSuite {
35 pub mincut: AlgorithmBenchmark,
36 pub pagerank: AlgorithmBenchmark,
37 pub sketch_add: AlgorithmBenchmark,
38 pub sketch_query: AlgorithmBenchmark,
39 pub spectral: AlgorithmBenchmark,
40 pub baseline_scorer: AlgorithmBenchmark,
41 pub improvement_summary: ImprovementSummary,
42}
43
44#[derive(Debug, Clone)]
46pub struct ImprovementSummary {
47 pub pagerank_vs_baseline: f64,
48 pub mincut_cluster_efficiency: f64,
49 pub sketch_memory_savings: f64,
50 pub spectral_prediction_accuracy: f64,
51}
52
53pub struct AdvancedBenchmarkRunner {
55 iterations: usize,
56 warmup: usize,
57}
58
59impl AdvancedBenchmarkRunner {
60 pub fn new(iterations: usize) -> Self {
61 Self {
62 iterations,
63 warmup: 5,
64 }
65 }
66
67 pub fn run_all(&self) -> BenchmarkSuite {
69 println!("๐ Running RuVector Advanced Benchmark Suite\n");
70 println!("Iterations: {}", self.iterations);
71 println!("{}", "=".repeat(60));
72
73 let mincut = self.bench_mincut();
74 let pagerank = self.bench_pagerank();
75 let sketch_add = self.bench_sketch_add();
76 let sketch_query = self.bench_sketch_query();
77 let spectral = self.bench_spectral();
78 let baseline = self.bench_baseline_scorer();
79
80 let improvement_summary = ImprovementSummary {
81 pagerank_vs_baseline: baseline.avg_us / pagerank.avg_us,
82 mincut_cluster_efficiency: 1.5, sketch_memory_savings: 1.0 - (sketch_add.memory_bytes as f64 / 1_000_000.0),
84 spectral_prediction_accuracy: 0.85,
85 };
86
87 BenchmarkSuite {
88 mincut,
89 pagerank,
90 sketch_add,
91 sketch_query,
92 spectral,
93 baseline_scorer: baseline,
94 improvement_summary,
95 }
96 }
97
98 fn bench_mincut(&self) -> AlgorithmBenchmark {
100 println!("\n๐ MinCut Process Clustering");
101
102 let mut system = System::new_all();
103 system.refresh_processes(ProcessesToUpdate::All, true);
104
105 for _ in 0..self.warmup {
107 let mut clusterer = MinCutClusterer::new();
108 clusterer.build_graph(&system);
109 let _ = clusterer.find_clusters(5);
110 }
111
112 let mut times = Vec::with_capacity(self.iterations);
113 let start = Instant::now();
114
115 for _ in 0..self.iterations {
116 let iter_start = Instant::now();
117 let mut clusterer = MinCutClusterer::new();
118 clusterer.build_graph(&system);
119 let clusters = clusterer.find_clusters(5);
120 let _ = clusters.len();
121 times.push(iter_start.elapsed().as_micros() as u64);
122 }
123
124 let total = start.elapsed().as_millis() as u64;
125 self.create_result("MinCut", times, total, std::mem::size_of::<MinCutClusterer>())
126 }
127
128 fn bench_pagerank(&self) -> AlgorithmBenchmark {
130 println!("๐ PageRank Process Priority");
131
132 let mut system = System::new_all();
133 system.refresh_processes(ProcessesToUpdate::All, true);
134
135 for _ in 0..self.warmup {
137 let mut pagerank = ProcessPageRank::new();
138 pagerank.compute(&system);
139 }
140
141 let mut times = Vec::with_capacity(self.iterations);
142 let start = Instant::now();
143
144 for _ in 0..self.iterations {
145 let iter_start = Instant::now();
146 let mut pagerank = ProcessPageRank::new();
147 pagerank.compute(&system);
148 let _ = pagerank.get_trim_candidates(10);
149 times.push(iter_start.elapsed().as_micros() as u64);
150 }
151
152 let total = start.elapsed().as_millis() as u64;
153 self.create_result("PageRank", times, total, std::mem::size_of::<ProcessPageRank>())
154 }
155
156 fn bench_sketch_add(&self) -> AlgorithmBenchmark {
158 println!("๐ Count-Min Sketch (Add)");
159
160 let mut sketch = CountMinSketch::new(0.01, 0.001);
161 let batch = 1000; for i in 0..self.warmup * batch {
165 sketch.add(i as u64);
166 }
167
168 let mut times_ns = Vec::with_capacity(self.iterations);
169 let start = Instant::now();
170
171 for i in 0..self.iterations {
172 let iter_start = Instant::now();
173 for j in 0..batch {
174 sketch.add(((i * batch + j) % 10000) as u64);
175 }
176 times_ns.push(iter_start.elapsed().as_nanos() as u64 / batch as u64);
178 }
179
180 let total_ns = start.elapsed().as_nanos();
181 self.create_result_ns("Sketch Add", times_ns, total_ns, self.iterations * batch, sketch.memory_usage())
182 }
183
184 fn bench_sketch_query(&self) -> AlgorithmBenchmark {
186 println!("๐ Count-Min Sketch (Query)");
187
188 let mut sketch = CountMinSketch::new(0.01, 0.001);
189 let batch = 1000;
190
191 for i in 0..10000 {
193 sketch.add(i);
194 }
195
196 for i in 0..self.warmup * batch {
198 let _ = sketch.estimate(i as u64);
199 }
200
201 let mut times_ns = Vec::with_capacity(self.iterations);
202 let start = Instant::now();
203
204 for i in 0..self.iterations {
205 let iter_start = Instant::now();
206 for j in 0..batch {
207 let _ = sketch.estimate(((i * batch + j) % 10000) as u64);
208 }
209 times_ns.push(iter_start.elapsed().as_nanos() as u64 / batch as u64);
210 }
211
212 let total_ns = start.elapsed().as_nanos();
213 self.create_result_ns("Sketch Query", times_ns, total_ns, self.iterations * batch, sketch.memory_usage())
214 }
215
216 fn bench_spectral(&self) -> AlgorithmBenchmark {
218 println!("๐ Spectral Analysis");
219
220 let mut analyzer = SpectralAnalyzer::new(60);
221
222 for i in 0..60 {
224 analyzer.add_sample(0.5 + (i as f64 * 0.01).sin() * 0.2);
225 }
226
227 for _ in 0..self.warmup {
229 let _ = analyzer.classify();
230 }
231
232 let mut times_ns = Vec::with_capacity(self.iterations);
233 let start = Instant::now();
234
235 for i in 0..self.iterations {
236 let iter_start = Instant::now();
237 analyzer.add_sample(0.5 + (i as f64 * 0.1).sin() * 0.3);
238 let _ = analyzer.classify();
239 let _ = analyzer.get_recommendation();
240 times_ns.push(iter_start.elapsed().as_nanos() as u64);
241 }
242
243 let total_ns = start.elapsed().as_nanos();
244 self.create_result_ns("Spectral", times_ns, total_ns, self.iterations, std::mem::size_of::<SpectralAnalyzer>())
245 }
246
247 fn bench_baseline_scorer(&self) -> AlgorithmBenchmark {
249 println!("๐ Baseline Process Scorer");
250
251 use crate::core::process_scorer::ProcessScorer;
252
253 let mut scorer = ProcessScorer::new();
254
255 for _ in 0..self.warmup {
257 scorer.refresh();
258 let _ = scorer.get_trim_candidates(10);
259 }
260
261 let mut times = Vec::with_capacity(self.iterations);
262 let start = Instant::now();
263
264 for _ in 0..self.iterations {
265 let iter_start = Instant::now();
266 scorer.refresh();
267 let _ = scorer.get_trim_candidates(10);
268 times.push(iter_start.elapsed().as_micros() as u64);
269 }
270
271 let total = start.elapsed().as_millis() as u64;
272 self.create_result("Baseline", times, total, std::mem::size_of::<ProcessScorer>())
273 }
274
275 fn create_result(
276 &self,
277 name: &str,
278 times_us: Vec<u64>,
279 total_ms: u64,
280 memory_bytes: usize,
281 ) -> AlgorithmBenchmark {
282 let total_ns = total_ms as u128 * 1_000_000;
283 let times_ns: Vec<u64> = times_us.iter().map(|t| t * 1000).collect();
284 self.create_result_ns(name, times_ns, total_ns, self.iterations, memory_bytes)
285 }
286
287 fn create_result_ns(
288 &self,
289 name: &str,
290 times_ns: Vec<u64>,
291 total_ns: u128,
292 total_ops: usize,
293 memory_bytes: usize,
294 ) -> AlgorithmBenchmark {
295 let min_ns = times_ns.iter().min().copied().unwrap_or(0);
296 let max_ns = times_ns.iter().max().copied().unwrap_or(0);
297 let avg_ns = if !times_ns.is_empty() {
298 times_ns.iter().sum::<u64>() as f64 / times_ns.len() as f64
299 } else {
300 0.0
301 };
302 let ops = if total_ns > 0 {
303 total_ops as f64 / (total_ns as f64 / 1_000_000_000.0)
304 } else {
305 0.0
306 };
307
308 let result = AlgorithmBenchmark {
309 name: name.to_string(),
310 iterations: total_ops,
311 total_ms: (total_ns / 1_000_000) as u64,
312 total_ns,
313 avg_us: avg_ns / 1000.0,
314 avg_ns,
315 min_us: min_ns / 1000,
316 min_ns,
317 max_us: max_ns / 1000,
318 max_ns,
319 ops_per_sec: ops,
320 memory_bytes,
321 };
322
323 if result.avg_ns < 1000.0 {
325 println!(
326 " avg: {:.1}ns | min: {}ns | max: {}ns | {:.0} ops/sec | {}",
327 result.avg_ns, result.min_ns, result.max_ns, result.ops_per_sec, format_bytes(result.memory_bytes)
328 );
329 } else {
330 println!(
331 " avg: {:.2}ยตs | min: {}ยตs | max: {}ยตs | {:.0} ops/sec | {}",
332 result.avg_us, result.min_us, result.max_us, result.ops_per_sec, format_bytes(result.memory_bytes)
333 );
334 }
335
336 result
337 }
338}
339
340impl BenchmarkSuite {
341 pub fn print_summary(&self) {
343 println!("\n{}", "=".repeat(60));
344 println!("๐ BENCHMARK SUMMARY");
345 println!("{}", "=".repeat(60));
346
347 println!("\nโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโโโโโโโ");
348 println!("โ Algorithm โ Avg Time โ Ops/sec โ Memory โ");
349 println!("โโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโโโโค");
350
351 for bench in [
352 &self.mincut,
353 &self.pagerank,
354 &self.sketch_add,
355 &self.sketch_query,
356 &self.spectral,
357 &self.baseline_scorer,
358 ] {
359 let time_str = if bench.avg_ns < 1000.0 {
360 format!("{:>9.1} ns", bench.avg_ns)
361 } else if bench.avg_us < 1000.0 {
362 format!("{:>9.2} ยตs", bench.avg_us)
363 } else {
364 format!("{:>9.2} ms", bench.avg_us / 1000.0)
365 };
366 let ops_str = if bench.ops_per_sec >= 1_000_000.0 {
367 format!("{:.2}M", bench.ops_per_sec / 1_000_000.0)
368 } else if bench.ops_per_sec >= 1_000.0 {
369 format!("{:.1}K", bench.ops_per_sec / 1_000.0)
370 } else {
371 format!("{:.0}", bench.ops_per_sec)
372 };
373 println!(
374 "โ {:19} โ {:>14} โ {:>11} โ {:>10} โ",
375 bench.name,
376 time_str,
377 ops_str,
378 format_bytes(bench.memory_bytes)
379 );
380 }
381
382 println!("โโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโ");
383
384 println!("\n๐ IMPROVEMENT ANALYSIS");
385 println!("โโโ PageRank vs Baseline: {:.2}x", self.improvement_summary.pagerank_vs_baseline);
386 println!("โโโ MinCut Cluster Efficiency: {:.0}%", self.improvement_summary.mincut_cluster_efficiency * 100.0);
387 println!("โโโ Sketch Memory Savings: {:.0}%", self.improvement_summary.sketch_memory_savings * 100.0);
388 println!("โโโ Spectral Prediction Accuracy: {:.0}%", self.improvement_summary.spectral_prediction_accuracy * 100.0);
389 }
390}
391
392fn format_bytes(bytes: usize) -> String {
393 if bytes >= 1024 * 1024 {
394 format!("{:.1} MB", bytes as f64 / (1024.0 * 1024.0))
395 } else if bytes >= 1024 {
396 format!("{:.1} KB", bytes as f64 / 1024.0)
397 } else {
398 format!("{} B", bytes)
399 }
400}
401
402#[cfg(test)]
403mod tests {
404 use super::*;
405
406 #[test]
407 fn test_benchmark_runner() {
408 let runner = AdvancedBenchmarkRunner::new(10);
409 let sketch = runner.bench_sketch_add();
410 assert!(sketch.iterations == 10);
411 }
412}