clock-hash 1.0.0

ClockHash-256: Consensus hash function for ClockinChain
Documentation
//! Performance benchmarking utilities for ClockHash-256
//!
//! This module provides tools for measuring and validating the performance
//! characteristics of ClockHash-256 implementations.

#[cfg(feature = "std")]
use std::time::Instant;

/// Measure the throughput of ClockHash-256 for a given data size
///
/// # Arguments
///
/// * `data_size` - Size of data to hash in bytes
/// * `iterations` - Number of iterations to measure
///
/// # Returns
///
/// Returns the throughput in MB/s
#[cfg(feature = "std")]
pub fn measure_throughput(data_size: usize, iterations: usize) -> f64 {
    use crate::clockhash256;

    let data = vec![0xAAu8; data_size];
    let mut total_time = 0u128;

    // Warm up
    for _ in 0..10 {
        let _ = clockhash256(&data);
    }

    // Measure
    for _ in 0..iterations {
        let start = Instant::now();
        let _hash = clockhash256(&data);
        total_time += start.elapsed().as_nanos();
    }

    let avg_time_ns = total_time as f64 / iterations as f64;
    let throughput_mbs = (data_size as f64 / 1_000_000.0) / (avg_time_ns / 1_000_000_000.0);

    throughput_mbs
}

/// Benchmark different input sizes and return performance characteristics
///
/// # Returns
///
/// Returns a vector of (data_size, throughput_mb_s) tuples
#[cfg(feature = "std")]
pub fn benchmark_sizes() -> Vec<(usize, f64)> {
    let sizes = [64, 1024, 8192, 65536, 524288]; // 64B to 512KB
    let iterations = [1000, 100, 50, 10, 5]; // Fewer iterations for larger sizes

    sizes
        .iter()
        .zip(iterations.iter())
        .map(|(&size, &iters)| (size, measure_throughput(size, iters)))
        .collect()
}

/// Verify that performance meets minimum requirements
///
/// # Arguments
///
/// * `target_throughput` - Minimum required throughput in MB/s
///
/// # Returns
///
/// Returns `true` if performance meets the target
#[cfg(feature = "std")]
pub fn verify_performance(target_throughput: f64) -> bool {
    let results = benchmark_sizes();

    // Check if any size meets the target (focus on larger sizes for steady-state performance)
    results
        .iter()
        .any(|&(_, throughput)| throughput >= target_throughput)
}

/// Get performance statistics
///
/// # Returns
///
/// Returns basic performance statistics as a formatted string
#[cfg(feature = "std")]
pub fn performance_stats() -> String {
    let results = benchmark_sizes();

    let mut stats = String::from("ClockHash-256 Performance Benchmark Results:\n");
    stats.push_str("Size (bytes) | Throughput (MB/s)\n");
    stats.push_str("-------------|-----------------\n");

    for &(size, throughput) in &results {
        stats.push_str(&format!("{:>11} | {:>15.2}\n", size, throughput));
    }

    // Add summary
    if let Some((_, max_throughput)) = results.iter().max_by(|a, b| a.1.partial_cmp(&b.1).unwrap())
    {
        stats.push_str(&format!("\nPeak throughput: {:.2} MB/s\n", max_throughput));

        if *max_throughput >= 100.0 {
            stats.push_str("✓ Performance target met (>= 100 MB/s)\n");
        } else {
            stats.push_str("⚠ Performance below target (< 100 MB/s)\n");
        }
    }

    stats
}

/// Memory usage estimation for ClockHash-256 operations
///
/// # Arguments
///
/// * `input_size` - Size of input data in bytes
///
/// # Returns
///
/// Returns estimated memory usage in bytes
pub fn estimate_memory_usage(input_size: usize) -> usize {
    // ClockHasher struct: 8 * 8 (state) + 128 (buffer) + 8 (buffer_len) + 8 (message_len) = ~168 bytes
    let hasher_size = 168;

    // Input data size
    let input_size = input_size;

    // Padding overhead (up to 128 bytes for padding)
    let padding_overhead = 128;

    hasher_size + input_size + padding_overhead
}

/// CPU feature detection for performance optimization
///
/// # Returns
///
/// Returns a string describing detected CPU features relevant to ClockHash-256
#[cfg(feature = "std")]
pub fn cpu_features() -> String {
    let mut features = Vec::new();

    // Check for SIMD availability (this is a simplified check)
    if cfg!(target_feature = "avx2") {
        features.push("AVX2 available".to_string());
    } else {
        features.push("AVX2 not available".to_string());
    }

    if cfg!(target_feature = "avx512f") {
        features.push("AVX-512 available".to_string());
    }

    if let Ok(arch) = std::env::var("CARGO_CFG_TARGET_ARCH") {
        features.push(format!("Target architecture: {}", arch));
    }

    features.join(", ")
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[cfg(feature = "std")]
    fn test_measure_throughput() {
        let throughput = measure_throughput(1024, 10);
        assert!(throughput > 0.0, "Throughput should be positive");
        println!("Measured throughput: {:.2} MB/s", throughput);
    }

    #[test]
    #[cfg(feature = "std")]
    fn test_benchmark_sizes() {
        let results = benchmark_sizes();
        assert!(!results.is_empty(), "Should have benchmark results");

        for (size, throughput) in results {
            assert!(size > 0, "Data size should be positive");
            assert!(throughput > 0.0, "Throughput should be positive");
        }
    }

    #[test]
    #[cfg(feature = "std")]
    fn test_performance_stats() {
        let stats = performance_stats();
        assert!(!stats.is_empty(), "Performance stats should not be empty");
        println!("{}", stats);
    }

    #[test]
    fn test_estimate_memory_usage() {
        let usage = estimate_memory_usage(1024);
        assert!(
            usage >= 1024,
            "Memory usage should at least cover input data"
        );

        let usage_empty = estimate_memory_usage(0);
        assert!(usage_empty > 0, "Even empty input should use some memory");
    }

    #[test]
    #[cfg(feature = "std")]
    fn test_cpu_features() {
        let features = cpu_features();
        assert!(
            !features.is_empty(),
            "CPU features string should not be empty"
        );
        println!("CPU features: {}", features);
    }

    #[test]
    fn test_performance_verification() {
        // Basic performance check - should work even without high performance
        // In practice, this would be more stringent
        #[cfg(feature = "std")]
        {
            let meets_target = verify_performance(1.0); // Very low target for testing
            // This might fail on very slow systems, but should pass in normal conditions
            if !meets_target {
                println!("Warning: Performance verification failed (target: 1.0 MB/s)");
                println!("This may be normal on slow systems or with debug builds");
            }
        }
    }
}