use webpage_quality_analyzer::{analyze, Analyzer};
#[path = "common/macros.rs"]
mod macros;
use std::collections::HashMap;
use std::time::{Duration, Instant};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
print_section!("⚡", "Performance Optimization Examples");
println!("🏁 Example 1: Performance Benchmarking");
println!("--------------------------------------");
run_performance_benchmarks().await?;
println!();
println!("📦 Example 2: Batch Processing");
println!("------------------------------");
run_batch_processing_demo().await?;
println!();
println!("💾 Example 3: Memory Optimization");
println!("---------------------------------");
run_memory_optimization_demo().await?;
println!();
println!("⚙️ Example 4: Configuration Tuning");
println!("-----------------------------------");
run_configuration_optimization().await?;
println!();
println!("💡 Example 5: Real-world Optimization");
println!("-------------------------------------");
demonstrate_optimization_strategies().await?;
println!();
println!("🎉 Performance optimization examples completed!");
println!();
println!("🚀 Key Performance Takeaways:");
println!(" • Reuse analyzer instances for better performance");
println!(" • Disable unused features (NLP, link checking) for speed");
println!(" • Use minimal reporting for high-throughput scenarios");
println!(" • Optimize configuration for your specific use case");
println!(" • Consider memory usage in long-running applications");
Ok(())
}
async fn run_performance_benchmarks() -> Result<(), Box<dyn std::error::Error>> {
println!("📊 Benchmarking different configuration approaches:");
println!();
let test_html = r#"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Performance Test Article</title>
<meta name="description" content="Testing performance with different analyzer configurations.">
</head>
<body>
<article>
<h1>Performance Testing Article</h1>
<h2>Introduction</h2>
<p>This article is designed to test the performance characteristics of different
analyzer configurations. It contains sufficient content to trigger all major
analysis components.</p>
<h2>Content Analysis</h2>
<p>The content analysis component examines text quality, readability, and structure.
This section provides enough text to ensure meaningful readability calculations and
content quality assessments.</p>
<h3>Subsection Example</h3>
<p>Subsections help demonstrate heading structure analysis and organization scoring.
Proper heading hierarchy is important for both SEO and accessibility.</p>
<h2>Media and Links</h2>
<p>This section contains various media elements and links to test different
analysis components:</p>
<ul>
<li><a href="https://example.com/page1">External link one</a></li>
<li><a href="https://example.com/page2">External link two</a></li>
<li><a href="/internal-page">Internal link</a></li>
</ul>
<img src="test-image.jpg" alt="Test image for media analysis">
<h2>Conclusion</h2>
<p>This comprehensive test content ensures that all analysis components have
sufficient data to work with, providing realistic performance measurements.</p>
</article>
</body>
</html>
"#;
let test_cases = vec![
("Minimal Config", create_minimal_analyzer().await?),
("Standard Config", create_standard_analyzer().await?),
("Full Features", create_full_featured_analyzer().await?),
("NLP Enabled", create_nlp_analyzer().await?),
("Link Checking", create_linkcheck_analyzer().await?),
];
let mut results = HashMap::new();
let iterations = 5;
for (name, analyzer) in test_cases {
println!(" Testing {}: ", name);
let mut times = Vec::new();
for i in 0..iterations {
let start = Instant::now();
match analyzer
.run("https://performance-test.example.com", Some(test_html))
.await
{
Ok(report) => {
let duration = start.elapsed();
times.push(duration);
if i == 0 {
print!("Score: {:.1} | ", report.score);
}
}
Err(e) => {
println!("❌ Failed: {}", e);
continue;
}
}
}
if !times.is_empty() {
let avg_time = times.iter().sum::<Duration>() / times.len() as u32;
let min_time = times.iter().min().unwrap();
let max_time = times.iter().max().unwrap();
println!(
"Avg: {:.2?} (min: {:.2?}, max: {:.2?})",
avg_time, min_time, max_time
);
results.insert(name, avg_time);
}
}
if let Some(baseline) = results.get("Minimal Config") {
println!();
println!(" 📈 Performance Impact (vs Minimal Config):");
let mut sorted_results: Vec<_> = results.iter().collect();
sorted_results.sort_by_key(|(_, time)| *time);
for (name, time) in sorted_results {
if name != &"Minimal Config" {
let overhead = time.as_millis() as f64 / baseline.as_millis() as f64;
println!(" {}: {:.1}x slower ({:.2?})", name, overhead, time);
} else {
println!(" {} (baseline): {:.2?}", name, time);
}
}
}
Ok(())
}
async fn run_batch_processing_demo() -> Result<(), Box<dyn std::error::Error>> {
println!("🔄 Batch processing optimization strategies:");
println!();
let urls = (1..=20)
.map(|i| format!("https://example{}.com", i))
.collect::<Vec<_>>();
let html_template = |id: usize| {
format!(
r#"
<html>
<head><title>Page {}</title></head>
<body>
<h1>Article {}</h1>
<p>This is article number {} with some content for testing batch processing performance.</p>
<h2>Section</h2>
<p>Additional content to make the analysis more realistic and comprehensive.</p>
</body>
</html>
"#,
id, id, id
)
};
println!(" 📝 Strategy 1: Sequential Processing");
let sequential_analyzer: Analyzer = Analyzer::builder()
.with_profile_name("blog")?
.add_report(false) .build()?;
let start = Instant::now();
let mut sequential_results = Vec::new();
for (i, url) in urls.iter().enumerate() {
let html = html_template(i + 1);
if let Ok(report) = sequential_analyzer.run(url, Some(&html)).await {
sequential_results.push(report.score);
}
}
let sequential_time = start.elapsed();
println!(
" ✅ Processed {} pages in {:.2?}",
sequential_results.len(),
sequential_time
);
println!(
" Average score: {:.1}",
sequential_results.iter().sum::<f32>() / sequential_results.len() as f32
);
println!();
println!(" ⚡ Strategy 2: Optimized Configuration");
let optimized_analyzer: Analyzer = Analyzer::builder()
.with_profile_name("blog")?
.enable_linkcheck(false) .enable_nlp(false) .add_report(false) .build()?;
let start = Instant::now();
let mut optimized_results = Vec::new();
for (i, url) in urls.iter().enumerate() {
let html = html_template(i + 1);
if let Ok(report) = optimized_analyzer.run(url, Some(&html)).await {
optimized_results.push(report.score);
}
}
let optimized_time = start.elapsed();
println!(
" ✅ Processed {} pages in {:.2?}",
optimized_results.len(),
optimized_time
);
println!(
" Speed improvement: {:.1}x faster",
sequential_time.as_millis() as f64 / optimized_time.as_millis() as f64
);
println!();
println!(" 🚀 Strategy 3: Batch with Concurrent-like Processing");
let concurrent_analyzer: Analyzer = Analyzer::builder()
.with_profile_name("blog")?
.add_report(false)
.build()?;
let start = Instant::now();
let mut concurrent_results = Vec::new();
let batch_size = 5;
for batch in urls.chunks(batch_size) {
for (i, url) in batch.iter().enumerate() {
let html = html_template(i + 1);
if let Ok(report) = concurrent_analyzer.run(url, Some(&html)).await {
concurrent_results.push(report.score);
}
}
tokio::time::sleep(std::time::Duration::from_millis(1)).await;
}
let concurrent_time = start.elapsed();
println!(
" ✅ Processed {} pages in {:.2?}",
concurrent_results.len(),
concurrent_time
);
println!();
println!(" 💡 Batch Processing Recommendations:");
println!(" • Reuse analyzer instances instead of creating new ones");
println!(" • Disable unused features (NLP, link checking) for speed");
println!(" • Use add_report(false) for minimal memory footprint");
println!(" • Process in batches to manage memory usage");
println!(" • Consider async/await patterns for I/O bound operations");
Ok(())
}
async fn run_memory_optimization_demo() -> Result<(), Box<dyn std::error::Error>> {
println!("💾 Memory usage optimization strategies:");
println!();
let large_html = create_large_html_content();
println!(" 📊 Memory Usage Comparison:");
let memory_heavy_analyzer: Analyzer = Analyzer::builder()
.with_profile_name("content_article")?
.enable_nlp(true)
.enable_linkcheck(true)
.add_report(true) .build()?;
let start = Instant::now();
match memory_heavy_analyzer
.run("https://memory-test.example.com", Some(&large_html))
.await
{
Ok(report) => {
let processing_time = start.elapsed();
println!(" Heavy Config: {:.2?} processing time", processing_time);
println!(" Report size: ~{} KB", estimate_report_size(&report));
println!(
" Metadata fields: {}",
count_metadata_fields(&report.metadata)
);
println!(
" Document elements: {}",
count_document_elements(&report.processed_document)
);
}
Err(e) => println!(" ❌ Heavy config failed: {}", e),
}
let memory_light_analyzer: Analyzer = Analyzer::builder()
.with_profile_name("blog")?
.enable_nlp(false)
.enable_linkcheck(false)
.add_report(false) .build()?;
let start = Instant::now();
match memory_light_analyzer
.run("https://memory-test.example.com", Some(&large_html))
.await
{
Ok(report) => {
let processing_time = start.elapsed();
println!(" Light Config: {:.2?} processing time", processing_time);
println!(" Report size: ~{} KB", estimate_report_size(&report));
println!(
" Minimal metadata: {}",
report.metadata.title.len() > 0
);
println!(
" Minimal document: {}",
report.processed_document.cleaned_text.len()
);
}
Err(e) => println!(" ❌ Light config failed: {}", e),
}
println!();
println!(" 🔧 Memory Optimization Techniques:");
println!(" 1. Use add_report(false) to exclude detailed document data");
println!(" 2. Disable NLP processing if not needed");
println!(" 3. Disable link checking for faster processing");
println!(" 4. Choose appropriate profiles for your use case");
println!(" 5. Process large documents in smaller chunks if possible");
println!(" 6. Clear or reuse variables in long-running applications");
Ok(())
}
async fn run_configuration_optimization() -> Result<(), Box<dyn std::error::Error>> {
println!("⚙️ Configuration optimization for different use cases:");
println!();
let test_html = r#"
<html>
<head><title>Config Test</title></head>
<body><h1>Test</h1><p>Configuration optimization test content.</p></body>
</html>
"#;
let use_cases = vec![
("SEO Audit", create_seo_optimized_analyzer().await?),
("Content Review", create_content_optimized_analyzer().await?),
("Quick Check", create_speed_optimized_analyzer().await?),
("Comprehensive", create_comprehensive_analyzer().await?),
];
for (use_case, analyzer) in use_cases {
let start = Instant::now();
match analyzer
.run("https://config-test.example.com", Some(test_html))
.await
{
Ok(report) => {
let duration = start.elapsed();
println!(
" 📋 {}: {:.1}/100 in {:.2?}",
use_case, report.score, duration
);
match use_case {
"SEO Audit" => {
let seo = &report.metrics.html_analysis.seo;
println!(
" SEO Focus: Title: {} chars, Meta: {}, OG: {}",
seo.title_len,
seo.meta_desc_len.is_some(),
seo.og_tags
);
}
"Content Review" => {
let content = &report.metrics.html_analysis.content;
println!(
" Content Focus: {} words, {:.1} min read, {:.1}% density",
content.word_count,
content.reading_time_minutes,
content.content_density * 100.0
);
}
"Quick Check" => {
println!(" Speed Focus: Fast analysis with essential metrics only");
}
"Comprehensive" => {
println!(
" Complete Analysis: All features enabled, detailed reporting"
);
}
_ => {}
}
}
Err(e) => println!(" ❌ {} failed: {}", use_case, e),
}
}
println!();
println!(" 🎯 Configuration Guidelines:");
println!(" • SEO Audit: Focus on metadata, structure, and technical aspects");
println!(" • Content Review: Enable NLP, emphasize readability and quality");
println!(" • Quick Check: Disable expensive features, minimal reporting");
println!(" • Comprehensive: All features enabled for complete analysis");
Ok(())
}
async fn demonstrate_optimization_strategies() -> Result<(), Box<dyn std::error::Error>> {
println!("💡 Real-world optimization strategies:");
println!();
println!(" 🔄 Strategy 1: Analyzer Instance Reuse");
let reusable_analyzer: Analyzer = Analyzer::builder().with_profile_name("blog")?.build()?;
let urls = vec![
"https://blog1.example.com",
"https://blog2.example.com",
"https://blog3.example.com",
];
let start = Instant::now();
for url in &urls {
let html = format!("<html><head><title>Blog</title></head><body><h1>Post</h1><p>Content for {}.</p></body></html>", url);
let _ = reusable_analyzer.run(url, Some(&html)).await;
}
let reuse_time = start.elapsed();
println!(
" ✅ Processed {} URLs with reused analyzer: {:.2?}",
urls.len(),
reuse_time
);
println!();
println!(" ⚡ Strategy 2: Feature Selection Based on Needs");
let feature_configs = vec![
("Basic", false, false),
("With NLP", true, false),
("With Links", false, true),
("Full Featured", true, true),
];
for (name, nlp, links) in feature_configs {
let analyzer: Analyzer = Analyzer::builder()
.with_profile_name("content_article")?
.enable_nlp(nlp)
.enable_linkcheck(links)
.build()?;
let start = Instant::now();
let html = "<html><head><title>Feature Test</title></head><body><h1>Test</h1><p>Testing feature selection.</p><a href='#'>Link</a></body></html>";
if let Ok(_) = analyzer
.run("https://feature-test.example.com", Some(html))
.await
{
let duration = start.elapsed();
println!(" {} config: {:.2?}", name, duration);
}
}
println!();
println!(" 🎯 Strategy 3: Profile Selection Optimization");
let content_types = vec![
("News Article", "news", "<html><head><title>Breaking News</title></head><body><h1>News</h1><p>Current events.</p></body></html>"),
("Blog Post", "blog", "<html><head><title>My Blog</title></head><body><h1>Blog</h1><p>Personal thoughts.</p></body></html>"),
("Product Page", "product", "<html><head><title>Amazing Product</title></head><body><h1>Product</h1><p>Buy now!</p></body></html>"),
];
for (content_type, _profile, html) in content_types {
let start = Instant::now();
if let Ok(report) = analyze("https://example.com", Some(html)).await {
let duration = start.elapsed();
println!(
" {}: {:.1}/100 in {:.2?}",
content_type, report.score, duration
);
}
}
println!();
println!(" 📈 Performance Best Practices:");
println!(" 1. 🔄 Reuse analyzer instances - avoid recreating");
println!(" 2. ⚡ Disable unused features for better performance");
println!(" 3. 🎯 Choose the right profile for your content type");
println!(" 4. 💾 Use minimal reporting for high-throughput scenarios");
println!(" 5. 📦 Process in batches to manage memory usage");
println!(" 6. 🔍 Profile your specific use case and optimize accordingly");
Ok(())
}
async fn create_minimal_analyzer() -> Result<Analyzer, Box<dyn std::error::Error>> {
Ok(Analyzer::builder()
.enable_linkcheck(false)
.enable_nlp(false)
.add_report(false)
.build()?)
}
async fn create_standard_analyzer() -> Result<Analyzer, Box<dyn std::error::Error>> {
Ok(Analyzer::builder()
.with_profile_name("content_article")?
.build()?)
}
async fn create_full_featured_analyzer() -> Result<Analyzer, Box<dyn std::error::Error>> {
Ok(Analyzer::builder()
.with_profile_name("content_article")?
.enable_linkcheck(true)
.enable_nlp(true)
.add_report(true)
.build()?)
}
async fn create_nlp_analyzer() -> Result<Analyzer, Box<dyn std::error::Error>> {
Ok(Analyzer::builder()
.with_profile_name("content_article")?
.enable_nlp(true)
.enable_linkcheck(false)
.build()?)
}
async fn create_linkcheck_analyzer() -> Result<Analyzer, Box<dyn std::error::Error>> {
Ok(Analyzer::builder()
.with_profile_name("content_article")?
.enable_linkcheck(true)
.linkcheck_sample(10)
.enable_nlp(false)
.build()?)
}
async fn create_seo_optimized_analyzer() -> Result<Analyzer, Box<dyn std::error::Error>> {
Ok(Analyzer::builder()
.with_profile_name("content_article")?
.enable_linkcheck(true)
.enable_nlp(false)
.build()?)
}
async fn create_content_optimized_analyzer() -> Result<Analyzer, Box<dyn std::error::Error>> {
Ok(Analyzer::builder()
.with_profile_name("content_article")?
.enable_nlp(true)
.enable_linkcheck(false)
.build()?)
}
async fn create_speed_optimized_analyzer() -> Result<Analyzer, Box<dyn std::error::Error>> {
Ok(Analyzer::builder()
.enable_linkcheck(false)
.enable_nlp(false)
.add_report(false)
.build()?)
}
async fn create_comprehensive_analyzer() -> Result<Analyzer, Box<dyn std::error::Error>> {
Ok(Analyzer::builder()
.with_profile_name("content_article")?
.enable_linkcheck(true)
.linkcheck_sample(50)
.enable_nlp(true)
.add_report(true)
.build()?)
}
fn create_large_html_content() -> String {
let mut html = String::from(
r#"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Large Content Test Document</title>
<meta name="description" content="Large document for testing memory usage and performance.">
</head>
<body>
<h1>Large Document Performance Test</h1>
"#,
);
for i in 1..=20 {
html.push_str(&format!(r#"
<h2>Section {}</h2>
<p>This is section {} with substantial content to test memory usage and processing performance.
The content includes multiple sentences to ensure realistic text analysis and provide
sufficient data for all metrics calculations.</p>
<h3>Subsection {}.1</h3>
<p>Additional content in subsection {}.1 to create deeper heading structure and more
comprehensive text analysis opportunities.</p>
<ul>
<li><a href="https://example{}.com">Link {}</a></li>
<li><a href="/internal-{}.html">Internal link {}</a></li>
</ul>
<img src="image{}.jpg" alt="Test image {} for media analysis">
"#, i, i, i, i, i, i, i, i, i, i));
}
html.push_str("</body></html>");
html
}
fn estimate_report_size(report: &webpage_quality_analyzer::PageQualityReport) -> usize {
let json_size = serde_json::to_string(report).unwrap_or_default().len();
json_size / 1024
}
fn count_metadata_fields(metadata: &webpage_quality_analyzer::ExtractedMetadata) -> usize {
let mut count = 0;
if !metadata.title.is_empty() {
count += 1;
}
if metadata.meta_description.is_some() {
count += 1;
}
if metadata.author.is_some() {
count += 1;
}
if metadata.language.is_some() {
count += 1;
}
if metadata.charset.is_some() {
count += 1;
}
count += metadata.og_tags.len();
count += metadata.twitter_tags.len();
count
}
fn count_document_elements(document: &webpage_quality_analyzer::ProcessedDocument) -> usize {
document.headings.len() + document.links.len() + document.images.len() + document.forms.len()
}