petaplot_core/compute/
prefetcher.rs1use std::collections::VecDeque;
2use std::time::Instant;
3use crate::error::Result;
4use crate::storage::mmap_reader::MmapReader;
5
6#[derive(Debug, Clone, PartialEq)]
8pub struct PrefetchRequest {
9 pub offset_bytes: usize,
10 pub length_bytes: usize,
11 pub target_time_start: f64,
12 pub target_time_end: f64,
13}
14
15pub struct SpeculativePrefetcher {
17 last_center_time: f64,
18 last_update: Instant,
19 current_velocity: f64, prediction_window_secs: f64,
21 cache_capacity: usize,
22 lru_cache: VecDeque<PrefetchRequest>,
23}
24
25impl Default for SpeculativePrefetcher {
26 fn default() -> Self {
27 Self {
28 last_center_time: 0.0,
29 last_update: Instant::now(),
30 current_velocity: 0.0,
31 prediction_window_secs: 0.200, cache_capacity: 16,
33 lru_cache: VecDeque::new(),
34 }
35 }
36}
37
38impl SpeculativePrefetcher {
39 pub fn new(prediction_window_secs: f64, cache_capacity: usize) -> Self {
40 Self {
41 prediction_window_secs,
42 cache_capacity,
43 ..Default::default()
44 }
45 }
46
47 pub fn update_position(&mut self, current_center_time: f64) {
50 let now = Instant::now();
51 let dt = now.duration_since(self.last_update).as_secs_f64();
52
53 if dt > 0.001 {
54 let dx = current_center_time - self.last_center_time;
55 let instant_velocity = dx / dt;
56
57 self.current_velocity = 0.6 * self.current_velocity + 0.4 * instant_velocity;
59 self.last_center_time = current_center_time;
60 self.last_update = now;
61 }
62 }
63
64 pub fn current_velocity(&self) -> f64 {
66 self.current_velocity
67 }
68
69 pub fn predict_future_range(&self, current_span: f64) -> (f64, f64) {
71 let delta_t = self.current_velocity * self.prediction_window_secs;
72 let future_center = self.last_center_time + delta_t;
73 let half_span = current_span / 2.0;
74
75 (future_center - half_span, future_center + half_span)
76 }
77
78 pub fn prefetch_mmap(&mut self, reader: &MmapReader, offset_bytes: usize, length_bytes: usize) -> Result<()> {
80 let req = PrefetchRequest {
81 offset_bytes,
82 length_bytes,
83 target_time_start: 0.0,
84 target_time_end: 0.0,
85 };
86
87 if self.lru_cache.contains(&req) {
88 return Ok(());
89 }
90
91 reader.advise_will_need(offset_bytes, length_bytes)?;
93
94 if self.lru_cache.len() >= self.cache_capacity {
96 self.lru_cache.pop_back();
97 }
98 self.lru_cache.push_front(req);
99
100 Ok(())
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use std::thread::sleep;
108 use std::time::Duration;
109
110 #[test]
111 fn test_velocity_prediction() {
112 let mut prefetcher = SpeculativePrefetcher::new(0.2, 10);
113
114 prefetcher.update_position(0.0);
115 sleep(Duration::from_millis(10));
116 prefetcher.update_position(10.0);
117
118 assert!(prefetcher.current_velocity() > 0.0);
119
120 let (future_start, future_end) = prefetcher.predict_future_range(5.0);
121 assert!(future_start > 7.5);
122 assert!(future_end > future_start);
123 }
124}