use crate::memory::{
zero_copy_enhanced::{AccessPattern, EnhancedZeroCopy},
SendPtr,
};
use rand::Rng;
use std::collections::HashMap;
use std::ptr::NonNull;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::{Mutex, RwLock};
#[derive(Debug, Clone)]
pub struct AccessHistoryEntry {
pub address: usize,
pub timestamp: Instant,
pub size: usize,
}
#[derive(Debug, Clone)]
pub struct PatternRecognizer {
pub history: Vec<AccessHistoryEntry>,
pub current_pattern: Option<AccessPattern>,
pub confidence: f64,
pub accuracy: f64,
}
impl PatternRecognizer {
pub fn new() -> Self {
Self {
history: Vec::with_capacity(1024),
current_pattern: None,
confidence: 0.0,
accuracy: 0.0,
}
}
pub fn record_access(&mut self, address: usize, size: usize) {
let entry: _ = AccessHistoryEntry {
address,
timestamp: Instant::now(),
size,
};
self.history.push(entry);
if self.history.len() > 1024 {
self.history.remove(0);
}
self.recognize_pattern();
}
fn recognize_pattern(&mut self) {
if self.history.len() < 10 {
return;
}
let recent_accesses: _ = &self.history[self.history.len().saturating_sub(100)..];
let sequential_score: _ = self.calculate_sequential_score(recent_accesses);
let cyclic_score: _ = self.calculate_cyclic_score(recent_accesses);
let random_score: _ = self.calculate_random_score(recent_accesses);
let (pattern, confidence) = if sequential_score > 0.8 {
(Some(AccessPattern::Sequential), sequential_score)
} else if cyclic_score > 0.7 {
(Some(AccessPattern::Sequential), cyclic_score)
} else if random_score > 0.5 {
(Some(AccessPattern::Random), random_score)
} else {
(Some(AccessPattern::Random), 0.5)
};
self.current_pattern = pattern;
self.confidence = confidence;
}
fn calculate_sequential_score(&self, accesses: &[AccessHistoryEntry]) -> f64 {
if accesses.len() < 3 {
return 0.0;
}
let mut sequential_count = 0;
let mut total_transitions = 0;
for i in 1..accesses.len() {
let prev: _ = &accesses[i - 1];
let curr: _ = &accesses[i];
let diff: _ = curr.address as isize - prev.address as isize;
let expected_diff: _ = prev.size as isize;
if (diff - expected_diff).abs() < (prev.size / 4) as isize {
sequential_count += 1;
}
total_transitions += 1;
}
if total_transitions > 0 {
sequential_count as f64 / total_transitions as f64
} else {
0.0
}
}
fn calculate_cyclic_score(&self, accesses: &[AccessHistoryEntry]) -> f64 {
if accesses.len() < 5 {
return 0.0;
}
let mut sequence_counts: HashMap<Vec<usize>, usize> = HashMap::new();
let sequence_length = 3.min(accesses.len());
for i in 0..=accesses.len() - sequence_length {
let sequence: Vec<usize> = accesses[i..i + sequence_length]
.iter()
.map(|a| a.address)
.collect();
*sequence_counts.entry(sequence).or_insert(0) += 1;
}
let max_count: _ = sequence_counts.values().max().unwrap_or(&0);
let total_sequences: _ = accesses.len() - sequence_length + 1;
if total_sequences > 0 {
*max_count as f64 / total_sequences as f64
} else {
0.0
}
}
fn calculate_random_score(&self, accesses: &[AccessHistoryEntry]) -> f64 {
if accesses.len() < 5 {
return 0.0;
}
let addresses: Vec<usize> = accesses.iter().map(|a| a.address).collect();
let mean: _ = addresses.iter().sum::<usize>() as f64 / addresses.len() as f64;
let variance: _ = addresses
.iter()
.map(|&addr| (addr as f64 - mean).powi(2))
.sum::<f64>()
/ addresses.len() as f64;
let normalized_variance: _ = (variance / 1_000_000_000.0).min(1.0);
normalized_variance
}
pub fn predict_next_address(&self) -> Option<usize> {
if self.history.is_empty() {
return None;
}
let last_access: _ = &self.history[self.history.len() - 1];
match self.current_pattern {
Some(AccessPattern::Sequential) => {
Some(last_access.address + last_access.size)
}
Some(AccessPattern::Random) => {
self.predict_random_address()
}
None => None,
}
}
fn predict_random_address(&self) -> Option<usize> {
if self.history.len() < 5 {
return None;
}
let addresses: Vec<usize> = self.history.iter().map(|a| a.address).collect();
let mean: _ = addresses.iter().sum::<usize>() as f64 / addresses.len() as f64;
let variance: _ = addresses
.iter()
.map(|&addr| (addr as f64 - mean).powi(2))
.sum::<f64>()
/ addresses.len() as f64;
let std_dev: _ = variance.sqrt();
let mut rng = rand::rng();
let prediction: _ = mean + rng.random_range(-std_dev..std_dev);
Some(prediction as usize)
}
}
#[derive(Debug, Clone)]
pub struct PrefetchStrategy {
pub window_size: usize,
pub prefetch_depth: usize,
pub min_confidence: f64,
pub prefetch_delay: Duration,
}
impl Default for PrefetchStrategy {
fn default() -> Self {
Self {
window_size: 4096,
prefetch_depth: 4,
min_confidence: 0.7,
prefetch_delay: Duration::from_micros(100),
}
}
}
#[derive(Debug)]
pub struct SmartPrefetcher {
recognizer: Arc<RwLock<PatternRecognizer>>,
strategy: PrefetchStrategy,
zero_copy: Arc<EnhancedZeroCopy>,
prefetch_queue: Arc<Mutex<Vec<PrefetchTask>>>,
stats: Arc<PrefetchStats>,
enabled: Arc<AtomicBool>,
}
#[derive(Debug)]
struct PrefetchTask {
pub address: SendPtr,
pub size: usize,
pub priority: usize,
pub created_at: Instant,
}
unsafe impl Send for PrefetchTask {}
unsafe impl Sync for PrefetchTask {}
#[derive(Debug, Default)]
pub struct PrefetchStats {
pub total_prefetch_requests: AtomicUsize,
pub successful_prefetches: AtomicUsize,
pub wasted_prefetches: AtomicUsize,
pub average_confidence: AtomicUsize,
pub pattern_accuracies: HashMap<String, AtomicUsize>,
}
impl SmartPrefetcher {
pub fn new(zero_copy: Arc<EnhancedZeroCopy>, strategy: PrefetchStrategy) -> Self {
Self {
recognizer: Arc::new(RwLock::new(PatternRecognizer::new())),
strategy,
zero_copy,
prefetch_queue: Arc::new(Mutex::new(Vec::new())),
stats: Arc::new(PrefetchStats::default()),
enabled: Arc::new(AtomicBool::new(true)),
}
}
pub async fn record_access(&self, address: usize, size: usize) {
{
let mut recognizer = self.recognizer.write().await;
recognizer.record_access(address, size);
}
self.stats
.total_prefetch_requests
.fetch_add(1, Ordering::Relaxed);
if self.enabled.load(Ordering::Relaxed) {
self.trigger_predictive_prefetch().await;
}
}
async fn trigger_predictive_prefetch(&self) {
let recognizer: _ = self.recognizer.read().await;
if recognizer.confidence < self.strategy.min_confidence {
return;
}
if let Some(predicted_addr) = recognizer.predict_next_address() {
let Some(addr) = NonNull::new(predicted_addr as *mut u8) else {
self.stats.wasted_prefetches.fetch_add(1, Ordering::Relaxed);
return;
};
let task: _ = PrefetchTask {
address: SendPtr(addr),
size: self.strategy.window_size,
priority: (recognizer.confidence * 100.0) as usize,
created_at: Instant::now(),
};
{
let mut queue = self.prefetch_queue.lock().await;
queue.push(task);
queue.sort_by(|a, b| b.priority.cmp(&a.priority));
}
self.execute_prefetch_queue().await;
}
}
async fn execute_prefetch_queue(&self) {
let mut queue = self.prefetch_queue.lock().await;
while let Some(task) = queue.pop() {
if task.created_at.elapsed() > Duration::from_secs(1) {
continue;
}
if self.execute_prefetch(&task).await {
self.stats
.successful_prefetches
.fetch_add(1, Ordering::Relaxed);
} else {
self.stats.wasted_prefetches.fetch_add(1, Ordering::Relaxed);
}
}
}
async fn execute_prefetch(&self, task: &PrefetchTask) -> bool {
let result: _ = self.zero_copy.smart_prefetch(task.address, task.size).await;
match result {
Ok(_) => true,
Err(_) => false,
}
}
pub fn enable(&self) {
self.enabled.store(true, Ordering::Relaxed);
}
pub fn disable(&self) {
self.enabled.store(false, Ordering::Relaxed);
}
pub async fn get_current_pattern(&self) -> Option<(AccessPattern, f64)> {
let recognizer: _ = self.recognizer.read().await;
recognizer
.current_pattern
.map(|p| (p, recognizer.confidence))
}
pub async fn get_stats(&self) -> SmartPrefetchStatsSnapshot {
let recognizer: _ = self.recognizer.read().await;
SmartPrefetchStatsSnapshot {
total_prefetch_requests: self.stats.total_prefetch_requests.load(Ordering::Relaxed),
successful_prefetches: self.stats.successful_prefetches.load(Ordering::Relaxed),
wasted_prefetches: self.stats.wasted_prefetches.load(Ordering::Relaxed),
current_pattern: recognizer.current_pattern,
confidence: recognizer.confidence,
queue_size: self.prefetch_queue.lock().await.len(),
}
}
pub async fn cleanup_expired_tasks(&self) {
let mut queue = self.prefetch_queue.lock().await;
let now: _ = Instant::now();
queue.retain(|task| now.duration_since(task.created_at) < Duration::from_secs(1));
}
}
#[derive(Debug, Clone)]
pub struct SmartPrefetchStatsSnapshot {
pub total_prefetch_requests: usize,
pub successful_prefetches: usize,
pub wasted_prefetches: usize,
pub current_pattern: Option<AccessPattern>,
pub confidence: f64,
pub queue_size: usize,
}
impl SmartPrefetchStatsSnapshot {
pub fn success_rate(&self) -> f64 {
if self.total_prefetch_requests == 0 {
0.0
} else {
self.successful_prefetches as f64 / self.total_prefetch_requests as f64
}
}
pub fn waste_rate(&self) -> f64 {
if self.total_prefetch_requests == 0 {
0.0
} else {
self.wasted_prefetches as f64 / self.total_prefetch_requests as f64
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_pattern_recognizer() {
let mut recognizer = PatternRecognizer::new();
for i in 0..10 {
recognizer.record_access(i * 1024, 1024);
}
assert!(recognizer.current_pattern.is_some());
assert!(recognizer.confidence > 0.0);
}
#[tokio::test]
async fn test_smart_prefetcher() {
let zero_copy = Arc::new(EnhancedZeroCopy::default());
let prefetcher: _ = SmartPrefetcher::new(zero_copy, PrefetchStrategy::default());
for i in 0..5 {
prefetcher.record_access(i * 1024, 1024).await;
}
let stats: _ = prefetcher.get_stats().await;
assert!(stats.total_prefetch_requests > 0);
}
#[test]
fn test_prefetch_strategy() {
let strategy: _ = PrefetchStrategy::default();
assert_eq!(strategy.window_size, 4096);
assert_eq!(strategy.prefetch_depth, 4);
assert!(strategy.min_confidence > 0.0);
}
}