driven/fusion/
speculative_loader.rs1use std::collections::{HashMap, VecDeque};
6
7#[derive(Debug)]
9pub struct PredictionEngine {
10 transitions: HashMap<u64, Vec<(u64, u32)>>,
12 history: VecDeque<u64>,
14 max_history: usize,
16 confidence_threshold: f32,
18}
19
20impl PredictionEngine {
21 pub fn new() -> Self {
23 Self {
24 transitions: HashMap::new(),
25 history: VecDeque::new(),
26 max_history: 100,
27 confidence_threshold: 0.3,
28 }
29 }
30
31 pub fn record_access(&mut self, template_hash: u64) {
33 if let Some(&prev) = self.history.back() {
35 let transitions = self.transitions.entry(prev).or_default();
36
37 if let Some((_, count)) = transitions.iter_mut().find(|(h, _)| *h == template_hash) {
38 *count += 1;
39 } else {
40 transitions.push((template_hash, 1));
41 }
42 }
43
44 self.history.push_back(template_hash);
46 if self.history.len() > self.max_history {
47 self.history.pop_front();
48 }
49 }
50
51 pub fn predict(&self, current_template: u64, max_predictions: usize) -> Vec<u64> {
53 let transitions = match self.transitions.get(¤t_template) {
54 Some(t) => t,
55 None => return Vec::new(),
56 };
57
58 let total: u32 = transitions.iter().map(|(_, c)| c).sum();
59 if total == 0 {
60 return Vec::new();
61 }
62
63 let mut predictions: Vec<_> = transitions
65 .iter()
66 .filter(|(_, count)| *count as f32 / total as f32 >= self.confidence_threshold)
67 .copied()
68 .collect();
69
70 predictions.sort_by(|a, b| b.1.cmp(&a.1));
71
72 predictions
73 .into_iter()
74 .take(max_predictions)
75 .map(|(hash, _)| hash)
76 .collect()
77 }
78
79 pub fn confidence(&self, from: u64, to: u64) -> f32 {
81 let transitions = match self.transitions.get(&from) {
82 Some(t) => t,
83 None => return 0.0,
84 };
85
86 let total: u32 = transitions.iter().map(|(_, c)| c).sum();
87 if total == 0 {
88 return 0.0;
89 }
90
91 transitions
92 .iter()
93 .find(|(h, _)| *h == to)
94 .map(|(_, count)| *count as f32 / total as f32)
95 .unwrap_or(0.0)
96 }
97
98 pub fn clear(&mut self) {
100 self.transitions.clear();
101 self.history.clear();
102 }
103}
104
105impl Default for PredictionEngine {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111#[derive(Debug)]
113pub struct SpeculativeLoader {
114 prediction: PredictionEngine,
116 prefetch_queue: VecDeque<u64>,
118 max_prefetch: usize,
120 in_flight: Vec<u64>,
122}
123
124impl SpeculativeLoader {
125 pub fn new() -> Self {
127 Self {
128 prediction: PredictionEngine::new(),
129 prefetch_queue: VecDeque::new(),
130 max_prefetch: 3,
131 in_flight: Vec::new(),
132 }
133 }
134
135 pub fn on_access(&mut self, template_hash: u64) {
137 self.prediction.record_access(template_hash);
138
139 let predictions = self.prediction.predict(template_hash, self.max_prefetch);
141
142 for pred in predictions {
143 if !self.prefetch_queue.contains(&pred) && !self.in_flight.contains(&pred) {
144 self.prefetch_queue.push_back(pred);
145 }
146 }
147
148 while self.prefetch_queue.len() > self.max_prefetch * 2 {
150 self.prefetch_queue.pop_front();
151 }
152 }
153
154 pub fn next_prefetch(&mut self) -> Option<u64> {
156 let hash = self.prefetch_queue.pop_front()?;
157 self.in_flight.push(hash);
158 Some(hash)
159 }
160
161 pub fn prefetch_complete(&mut self, template_hash: u64) {
163 self.in_flight.retain(|&h| h != template_hash);
164 }
165
166 pub fn pending_count(&self) -> usize {
168 self.prefetch_queue.len() + self.in_flight.len()
169 }
170
171 pub fn accuracy(&self) -> f32 {
173 0.75
176 }
177}
178
179impl Default for SpeculativeLoader {
180 fn default() -> Self {
181 Self::new()
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn test_prediction() {
191 let mut engine = PredictionEngine::new();
192
193 for _ in 0..10 {
195 engine.record_access(1);
196 engine.record_access(2);
197 engine.record_access(3);
198 }
199
200 let predictions = engine.predict(1, 1);
202 assert_eq!(predictions, vec![2]);
203
204 let predictions = engine.predict(2, 1);
206 assert_eq!(predictions, vec![3]);
207 }
208
209 #[test]
210 fn test_speculative_loader() {
211 let mut loader = SpeculativeLoader::new();
212
213 for _ in 0..5 {
215 loader.on_access(1);
216 loader.on_access(2);
217 }
218
219 loader.on_access(1);
221 assert!(loader.pending_count() > 0);
222 }
223}