use rumdl_lib::config::Config;
use rumdl_lib::parallel::{FileParallelProcessor, ParallelConfig, ParallelPerformanceComparison};
use rumdl_lib::performance::ContentGenerator;
use rumdl_lib::rules::all_rules;
use std::env;
use std::time::Instant;
fn main() {
env_logger::init();
println!("📁 RUMDL File-Level Parallel Benchmark");
println!("======================================\n");
let args: Vec<String> = env::args().collect();
let file_count: usize = args.get(1).and_then(|s| s.parse().ok()).unwrap_or(4);
let content_size = args.get(2).map(|s| s.as_str()).unwrap_or("medium");
let thread_count: Option<usize> = args.get(3).and_then(|s| s.parse().ok());
let config = Config::default();
let rules = all_rules(&config);
println!("📋 Benchmark Configuration:");
println!(" Rules to test: {}", rules.len());
println!(" File count: {file_count}");
println!(" Content size: {content_size}");
println!(" CPU cores: {}", num_cpus::get());
if let Some(threads) = thread_count {
println!(" Thread override: {threads}");
}
println!();
let test_files = generate_test_files(file_count, content_size);
let total_content_size: usize = test_files.iter().map(|(_, content)| content.len()).sum();
let total_lines: usize = test_files.iter().map(|(_, content)| content.lines().count()).sum();
println!("📄 Generated Test Files:");
println!(" Total files: {}", test_files.len());
println!(" Total content: {total_content_size} bytes ({total_lines} lines)");
println!(" Average file size: {} bytes", total_content_size / test_files.len());
println!();
let parallel_config = ParallelConfig {
enabled: true,
thread_count,
min_file_count: 0, };
let file_processor = FileParallelProcessor::new(parallel_config);
run_file_parallel_comparison(&test_files, &rules, &file_processor);
println!("✅ File-level parallel benchmark completed!");
}
fn generate_test_files(count: usize, size_type: &str) -> Vec<(String, String)> {
let mut files = Vec::new();
for i in 0..count {
let content = match size_type {
"small" => ContentGenerator::small_content(),
"medium" => ContentGenerator::medium_content(),
"large" => ContentGenerator::large_content(),
"huge" => ContentGenerator::huge_content(),
_ => ContentGenerator::medium_content(),
};
let filename = format!("test_file_{}.md", i + 1);
files.push((filename, content));
}
files
}
fn run_file_parallel_comparison(
files: &[(String, String)],
rules: &[Box<dyn rumdl_lib::rule::Rule>],
file_processor: &FileParallelProcessor,
) {
println!("🔄 Testing File-Level Parallel Processing:");
let _ = process_files_sequential(files, rules);
let _ = file_processor.process_files(files, rules);
let mut sequential_times = Vec::new();
let mut sequential_total_warnings = 0;
for _ in 0..3 {
let start = Instant::now();
let results = process_files_sequential(files, rules);
sequential_times.push(start.elapsed());
sequential_total_warnings = results
.iter()
.map(|(_, result)| result.as_ref().map(|w| w.len()).unwrap_or(0))
.sum();
}
let sequential_time = sequential_times.iter().sum::<std::time::Duration>() / sequential_times.len() as u32;
let mut parallel_times = Vec::new();
let mut parallel_total_warnings = 0;
for _ in 0..3 {
let start = Instant::now();
let results = file_processor.process_files(files, rules).unwrap();
parallel_times.push(start.elapsed());
parallel_total_warnings = results
.iter()
.map(|(_, result)| result.as_ref().map(|w| w.len()).unwrap_or(0))
.sum();
}
let parallel_time = parallel_times.iter().sum::<std::time::Duration>() / parallel_times.len() as u32;
if sequential_total_warnings != parallel_total_warnings {
println!(
"⚠️ WARNING: Different warning counts! Sequential: {sequential_total_warnings}, Parallel: {parallel_total_warnings}"
);
}
let comparison = ParallelPerformanceComparison::new(sequential_time, parallel_time);
println!(" Files processed: {}", files.len());
println!(
" Sequential time: {:.3}ms ({} total warnings)",
sequential_time.as_secs_f64() * 1000.0,
sequential_total_warnings
);
println!(
" Parallel time: {:.3}ms ({} total warnings)",
parallel_time.as_secs_f64() * 1000.0,
parallel_total_warnings
);
println!(" Speedup factor: {:.2}x", comparison.speedup_factor);
if comparison.speedup_factor > 1.0 {
let improvement = (comparison.speedup_factor - 1.0) * 100.0;
println!(" ✅ Performance improvement: {improvement:.1}%");
} else {
let degradation = (1.0 - comparison.speedup_factor) * 100.0;
println!(" ❌ Performance degradation: {degradation:.1}%");
if comparison.parallel_overhead > std::time::Duration::ZERO {
println!(
" Parallel overhead: {:.3}ms",
comparison.parallel_overhead.as_secs_f64() * 1000.0
);
}
}
let total_content_size: usize = files.iter().map(|(_, content)| content.len()).sum();
let sequential_throughput = total_content_size as f64 / sequential_time.as_secs_f64() / 1024.0 / 1024.0; let parallel_throughput = total_content_size as f64 / parallel_time.as_secs_f64() / 1024.0 / 1024.0;
println!();
println!("📊 Throughput Analysis:");
println!(" Sequential: {sequential_throughput:.2} MB/s");
println!(" Parallel: {parallel_throughput:.2} MB/s");
println!(
" Throughput improvement: {:.1}%",
(parallel_throughput / sequential_throughput - 1.0) * 100.0
);
}
fn process_files_sequential(
files: &[(String, String)],
rules: &[Box<dyn rumdl_lib::rule::Rule>],
) -> Vec<(String, rumdl_lib::rule::LintResult)> {
files
.iter()
.map(|(path, content)| {
let result = rumdl_lib::lint(content, rules, false, rumdl_lib::config::MarkdownFlavor::Standard, Some(std::path::PathBuf::from(path)), None);
(path.clone(), result)
})
.collect()
}