Skip to main content

trustformers_debug/profiler/
io_monitor.rs

1//! I/O operation monitoring and bandwidth tracking
2// reason: debug/profiling scaffolding — structs are constructed and their fields/methods
3// are retained for the data model, serialization completeness, and future consumers that
4// do not yet read every member. Consolidated from many item-level #[allow(dead_code)].
5#![allow(dead_code)]
6
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::time::{Duration, Instant, SystemTime};
10use uuid::Uuid;
11
12/// I/O operation profiling
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct IoProfile {
15    pub operation_type: IoOperationType,
16    pub file_path: Option<String>,
17    pub bytes_transferred: usize,
18    pub duration: Duration,
19    pub bandwidth_mb_s: f64,
20    pub queue_time: Duration,
21    pub device_type: IoDeviceType,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub enum IoOperationType {
26    FileRead,
27    FileWrite,
28    NetworkRead,
29    NetworkWrite,
30    DatabaseQuery,
31    CacheLoad,
32    CacheStore,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
36pub enum IoDeviceType {
37    SSD,
38    HDD,
39    Network,
40    Memory,
41    Cache,
42}
43
44/// Layer-wise latency analysis
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct LayerLatencyProfile {
47    pub layer_name: String,
48    pub layer_type: String,
49    pub input_shapes: Vec<Vec<usize>>,
50    pub output_shapes: Vec<Vec<usize>>,
51    pub cpu_time: Duration,
52    pub gpu_time: Duration,
53    pub memory_copy_time: Duration,
54    pub sync_time: Duration,
55    pub parameter_count: usize,
56    pub flops: u64,
57    pub memory_footprint_bytes: usize,
58    pub cache_hit_rate: f64,
59}
60
61#[derive(Debug, Serialize, Deserialize)]
62pub struct IoPerformanceSummary {
63    pub total_operations: usize,
64    pub total_bytes_transferred: usize,
65    pub avg_bandwidth_by_device: HashMap<IoDeviceType, f64>,
66    pub slowest_operations: Vec<String>,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct BandwidthSample {
71    pub timestamp: SystemTime,
72    pub bandwidth_mb_s: f64,
73    pub device_type: IoDeviceType,
74}
75
76/// I/O operation monitor
77#[derive(Debug)]
78pub struct IoMonitor {
79    pub(crate) active_operations: HashMap<Uuid, IoOperation>,
80    pub(crate) bandwidth_history: Vec<BandwidthSample>,
81    pub(crate) io_queue_depth: usize,
82}
83
84#[derive(Debug)]
85pub struct IoOperation {
86    pub(crate) operation_id: Uuid,
87    pub(crate) start_time: Instant,
88    pub(crate) operation_type: IoOperationType,
89    pub(crate) bytes_expected: usize,
90}
91
92impl Default for IoMonitor {
93    fn default() -> Self {
94        Self::new()
95    }
96}
97
98impl IoMonitor {
99    pub fn new() -> Self {
100        Self {
101            active_operations: HashMap::new(),
102            bandwidth_history: Vec::new(),
103            io_queue_depth: 0,
104        }
105    }
106
107    pub fn start_io_operation(
108        &mut self,
109        operation_type: IoOperationType,
110        bytes_expected: usize,
111    ) -> Uuid {
112        let operation_id = Uuid::new_v4();
113        let operation = IoOperation {
114            operation_id,
115            start_time: Instant::now(),
116            operation_type,
117            bytes_expected,
118        };
119
120        self.active_operations.insert(operation_id, operation);
121        self.io_queue_depth += 1;
122        operation_id
123    }
124
125    pub fn finish_io_operation(
126        &mut self,
127        operation_id: Uuid,
128        bytes_transferred: usize,
129    ) -> Option<IoProfile> {
130        if let Some(operation) = self.active_operations.remove(&operation_id) {
131            let duration = operation.start_time.elapsed();
132            let bandwidth_mb_s = if duration.as_secs_f64() > 0.0 {
133                bytes_transferred as f64 / (1024.0 * 1024.0) / duration.as_secs_f64()
134            } else {
135                0.0
136            };
137
138            self.io_queue_depth = self.io_queue_depth.saturating_sub(1);
139
140            let device_type = match operation.operation_type {
141                IoOperationType::FileRead | IoOperationType::FileWrite => IoDeviceType::SSD,
142                IoOperationType::NetworkRead | IoOperationType::NetworkWrite => {
143                    IoDeviceType::Network
144                },
145                IoOperationType::CacheLoad | IoOperationType::CacheStore => IoDeviceType::Cache,
146                _ => IoDeviceType::Memory,
147            };
148
149            // Record bandwidth sample
150            self.bandwidth_history.push(BandwidthSample {
151                timestamp: SystemTime::now(),
152                bandwidth_mb_s,
153                device_type: device_type.clone(),
154            });
155
156            // Keep only recent samples
157            if self.bandwidth_history.len() > 1000 {
158                self.bandwidth_history.drain(0..500);
159            }
160
161            Some(IoProfile {
162                operation_type: operation.operation_type,
163                file_path: None, // Would be filled in practice
164                bytes_transferred,
165                duration,
166                bandwidth_mb_s,
167                queue_time: Duration::from_millis(self.io_queue_depth as u64 * 10), // Simplified
168                device_type,
169            })
170        } else {
171            None
172        }
173    }
174
175    pub fn get_average_bandwidth(&self, device_type: &IoDeviceType) -> f64 {
176        let samples: Vec<f64> = self
177            .bandwidth_history
178            .iter()
179            .filter(|s| &s.device_type == device_type)
180            .map(|s| s.bandwidth_mb_s)
181            .collect();
182
183        if samples.is_empty() {
184            0.0
185        } else {
186            samples.iter().sum::<f64>() / samples.len() as f64
187        }
188    }
189}
190
191#[cfg(test)]
192mod tests {
193    use super::*;
194
195    #[test]
196    fn test_io_monitor_new() {
197        let monitor = IoMonitor::new();
198        assert_eq!(monitor.io_queue_depth, 0);
199        assert!(monitor.bandwidth_history.is_empty());
200    }
201
202    #[test]
203    fn test_io_monitor_start_operation() {
204        let mut monitor = IoMonitor::new();
205        let _id = monitor.start_io_operation(IoOperationType::FileRead, 4096);
206        assert_eq!(monitor.io_queue_depth, 1);
207        assert_eq!(monitor.active_operations.len(), 1);
208    }
209
210    #[test]
211    fn test_io_monitor_finish_operation() {
212        let mut monitor = IoMonitor::new();
213        let id = monitor.start_io_operation(IoOperationType::FileWrite, 8192);
214        let profile = monitor.finish_io_operation(id, 8192);
215        assert!(profile.is_some());
216        let p = profile.expect("profile should be Some");
217        assert_eq!(p.bytes_transferred, 8192);
218        assert_eq!(monitor.io_queue_depth, 0);
219    }
220
221    #[test]
222    fn test_io_monitor_finish_nonexistent() {
223        let mut monitor = IoMonitor::new();
224        let profile = monitor.finish_io_operation(Uuid::new_v4(), 100);
225        assert!(profile.is_none());
226    }
227
228    #[test]
229    fn test_io_monitor_average_bandwidth_empty() {
230        let monitor = IoMonitor::new();
231        assert!((monitor.get_average_bandwidth(&IoDeviceType::SSD) - 0.0).abs() < 1e-9);
232    }
233
234    #[test]
235    fn test_io_monitor_device_type_mapping() {
236        let mut monitor = IoMonitor::new();
237        let id = monitor.start_io_operation(IoOperationType::NetworkRead, 1024);
238        let profile = monitor.finish_io_operation(id, 1024);
239        assert!(profile.is_some());
240        let p = profile.expect("profile should be Some");
241        assert_eq!(p.device_type, IoDeviceType::Network);
242    }
243
244    #[test]
245    fn test_io_monitor_cache_device_type() {
246        let mut monitor = IoMonitor::new();
247        let id = monitor.start_io_operation(IoOperationType::CacheLoad, 512);
248        let profile = monitor.finish_io_operation(id, 512);
249        assert!(profile.is_some());
250        let p = profile.expect("profile should be Some");
251        assert_eq!(p.device_type, IoDeviceType::Cache);
252    }
253}