#[cfg(feature = "std")]
use std::time::Instant;
#[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;
for _ in 0..10 {
let _ = clockhash256(&data);
}
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
}
#[cfg(feature = "std")]
pub fn benchmark_sizes() -> Vec<(usize, f64)> {
let sizes = [64, 1024, 8192, 65536, 524288]; let iterations = [1000, 100, 50, 10, 5];
sizes
.iter()
.zip(iterations.iter())
.map(|(&size, &iters)| (size, measure_throughput(size, iters)))
.collect()
}
#[cfg(feature = "std")]
pub fn verify_performance(target_throughput: f64) -> bool {
let results = benchmark_sizes();
results
.iter()
.any(|&(_, throughput)| throughput >= target_throughput)
}
#[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));
}
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
}
pub fn estimate_memory_usage(input_size: usize) -> usize {
let hasher_size = 168;
let input_size = input_size;
let padding_overhead = 128;
hasher_size + input_size + padding_overhead
}
#[cfg(feature = "std")]
pub fn cpu_features() -> String {
let mut features = Vec::new();
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() {
#[cfg(feature = "std")]
{
let meets_target = verify_performance(1.0); 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");
}
}
}
}