//! Memory latency measurement

use std::time::Instant;

use super::super::error::ProfilingError;

/// Memory latency result
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct MemoryLatencyResult {
    pub latency_ns: f64,
    pub stride_bytes: u32,
    pub working_set_bytes: u64,
}

/// Test memory latency with stride-based access
pub fn test_memory_latency(size: u64) -> Result<MemoryLatencyResult, ProfilingError> {
    super::super::logging::log_info(&format!("Testing memory latency: {} bytes", size));

    let stride = 64; // Cache line size
    let working_set = size;
    let iterations = 1000;

    let mut data: Vec<u64> = vec![0; (working_set / 8) as usize];

    let start = Instant::now();
    for _ in 0..iterations {
        for i in (0..data.len()).step_by(stride / 8) {
            data[i] = data[i].wrapping_add(1);
            std::hint::black_box(&data[i]);
        }
    }
    let duration = start.elapsed();

    let total_accesses = iterations * (data.len() / (stride / 8));
    let latency_ns = (duration.as_nanos() as f64) / (total_accesses as f64);

    Ok(MemoryLatencyResult {
        latency_ns,
        stride_bytes: stride as u32,
        working_set_bytes: working_set,
    })
}
