Skip to main content

qvm_scheduler/composer/
timing.rs

1//! Timing management for circuit execution
2
3use crate::{QvmError, Result};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7/// Circuit timing information
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct CircuitTiming {
10    /// Start time (microseconds since epoch)
11    pub start_time: u64,
12    /// Execution duration (microseconds)
13    pub duration: u64,
14    /// Estimated end time
15    pub estimated_end_time: u64,
16}
17
18impl CircuitTiming {
19    /// Create new circuit timing
20    pub fn new(start_time: u64, duration: u64) -> Self {
21        Self {
22            start_time,
23            duration,
24            estimated_end_time: start_time + duration,
25        }
26    }
27
28    /// Check if this timing overlaps with another
29    pub fn overlaps_with(&self, other: &CircuitTiming) -> bool {
30        !(self.estimated_end_time <= other.start_time || other.estimated_end_time <= self.start_time)
31    }
32
33    /// Get the time gap between this and another timing
34    pub fn gap_to(&self, other: &CircuitTiming) -> i64 {
35        if self.estimated_end_time <= other.start_time {
36            (other.start_time - self.estimated_end_time) as i64
37        } else if other.estimated_end_time <= self.start_time {
38            (self.start_time - other.estimated_end_time) as i64
39        } else {
40            0 // Overlapping
41        }
42    }
43}
44
45/// Circuit timer for managing timing operations
46#[derive(Debug, Clone)]
47pub struct CircuitTimer {
48    config: TimerConfig,
49}
50
51/// Timer configuration
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct TimerConfig {
54    /// Time precision (microseconds)
55    pub precision: u64,
56    /// Enable timing optimization
57    pub optimize_timing: bool,
58    /// Buffer time between circuits (microseconds)
59    pub buffer_time: u64,
60    /// Maximum allowed timing drift
61    pub max_drift: u64,
62}
63
64impl Default for TimerConfig {
65    fn default() -> Self {
66        Self {
67            precision: 1, // 1 microsecond precision
68            optimize_timing: true,
69            buffer_time: 1000, // 1ms buffer
70            max_drift: 100, // 100μs max drift
71        }
72    }
73}
74
75impl CircuitTimer {
76    /// Create a new circuit timer
77    pub fn new() -> Self {
78        Self {
79            config: TimerConfig::default(),
80        }
81    }
82
83    /// Create timer with custom configuration
84    pub fn with_config(config: TimerConfig) -> Self {
85        Self { config }
86    }
87
88    /// Create timing for a circuit
89    pub fn create_timing(&self, start_time: u64, duration: u64) -> CircuitTiming {
90        let aligned_start = self.align_time(start_time);
91        let aligned_duration = self.align_time(duration);
92        
93        CircuitTiming::new(aligned_start, aligned_duration)
94    }
95
96    /// Align time to precision boundary
97    fn align_time(&self, time: u64) -> u64 {
98        if self.config.precision <= 1 {
99            return time;
100        }
101
102        let remainder = time % self.config.precision;
103        if remainder == 0 {
104            time
105        } else {
106            time + (self.config.precision - remainder)
107        }
108    }
109
110    /// Optimize timing for multiple circuits
111    pub fn optimize_timings(&self, timings: &mut [CircuitTiming]) -> Result<()> {
112        if !self.config.optimize_timing {
113            return Ok(());
114        }
115
116        // Sort by start time
117        timings.sort_by_key(|t| t.start_time);
118
119        // Compress timeline
120        self.compress_timeline(timings)?;
121
122        // Add buffer times
123        self.add_buffer_times(timings)?;
124
125        Ok(())
126    }
127
128    /// Compress timeline to minimize total execution time
129    fn compress_timeline(&self, timings: &mut [CircuitTiming]) -> Result<()> {
130        let mut current_time = 0;
131
132        for timing in timings.iter_mut() {
133            if timing.start_time > current_time {
134                timing.start_time = current_time;
135                timing.estimated_end_time = current_time + timing.duration;
136            }
137            current_time = timing.estimated_end_time;
138        }
139
140        Ok(())
141    }
142
143    /// Add buffer times between circuits
144    fn add_buffer_times(&self, timings: &mut [CircuitTiming]) -> Result<()> {
145        for i in 1..timings.len() {
146            let prev_end = timings[i - 1].estimated_end_time;
147            let current_start = timings[i].start_time;
148            
149            if current_start < prev_end + self.config.buffer_time {
150                let new_start = prev_end + self.config.buffer_time;
151                timings[i].start_time = new_start;
152                timings[i].estimated_end_time = new_start + timings[i].duration;
153            }
154        }
155
156        Ok(())
157    }
158
159    /// Validate timing constraints
160    pub fn validate_timings(&self, timings: &[CircuitTiming]) -> Result<Vec<TimingViolation>> {
161        let mut violations = Vec::new();
162
163        // Check for overlaps
164        for i in 0..timings.len() {
165            for j in (i + 1)..timings.len() {
166                if timings[i].overlaps_with(&timings[j]) {
167                    violations.push(TimingViolation {
168                        violation_type: ViolationType::Overlap,
169                        circuit1: i,
170                        circuit2: Some(j),
171                        description: format!("Circuits {} and {} have overlapping execution times", i, j),
172                        severity: Severity::Critical,
173                    });
174                }
175            }
176        }
177
178        // Check buffer time violations
179        for i in 1..timings.len() {
180            let gap = timings[i].start_time.saturating_sub(timings[i - 1].estimated_end_time);
181            if gap < self.config.buffer_time {
182                violations.push(TimingViolation {
183                    violation_type: ViolationType::InsufficientBuffer,
184                    circuit1: i - 1,
185                    circuit2: Some(i),
186                    description: format!("Insufficient buffer time between circuits {} and {}", i - 1, i),
187                    severity: Severity::Warning,
188                });
189            }
190        }
191
192        Ok(violations)
193    }
194
195    /// Calculate timing statistics
196    pub fn calculate_statistics(&self, timings: &[CircuitTiming]) -> TimingStatistics {
197        if timings.is_empty() {
198            return TimingStatistics::default();
199        }
200
201        let total_duration = timings.iter().map(|t| t.duration).sum();
202        let total_execution_time = timings.iter()
203            .map(|t| t.estimated_end_time)
204            .max()
205            .unwrap_or(0);
206
207        let gaps: Vec<u64> = (1..timings.len())
208            .map(|i| {
209                timings[i].start_time.saturating_sub(timings[i - 1].estimated_end_time)
210            })
211            .collect();
212
213        let total_gap_time: u64 = gaps.iter().sum();
214        let avg_gap = if gaps.is_empty() { 0.0 } else { total_gap_time as f64 / gaps.len() as f64 };
215
216        let efficiency = if total_execution_time > 0 {
217            total_duration as f64 / total_execution_time as f64
218        } else {
219            0.0
220        };
221
222        TimingStatistics {
223            total_circuits: timings.len(),
224            total_duration,
225            total_execution_time,
226            total_gap_time,
227            average_gap: avg_gap,
228            efficiency,
229            compression_ratio: if total_duration > 0 {
230                total_execution_time as f64 / total_duration as f64
231            } else {
232                1.0
233            },
234        }
235    }
236}
237
238impl Default for CircuitTimer {
239    fn default() -> Self {
240        Self::new()
241    }
242}
243
244/// Timing violation information
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct TimingViolation {
247    /// Type of violation
248    pub violation_type: ViolationType,
249    /// First circuit involved
250    pub circuit1: usize,
251    /// Second circuit involved (if applicable)
252    pub circuit2: Option<usize>,
253    /// Description of the violation
254    pub description: String,
255    /// Severity level
256    pub severity: Severity,
257}
258
259/// Types of timing violations
260#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
261pub enum ViolationType {
262    /// Circuits have overlapping execution times
263    Overlap,
264    /// Insufficient buffer time between circuits
265    InsufficientBuffer,
266    /// Timing precision violation
267    PrecisionViolation,
268    /// Excessive timing drift
269    ExcessiveDrift,
270}
271
272/// Violation severity levels
273#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
274pub enum Severity {
275    /// Critical - execution will fail
276    Critical,
277    /// Warning - execution may have issues
278    Warning,
279    /// Info - minor optimization opportunity
280    Info,
281}
282
283/// Timing statistics
284#[derive(Debug, Clone, Default, Serialize, Deserialize)]
285pub struct TimingStatistics {
286    /// Total number of circuits
287    pub total_circuits: usize,
288    /// Total duration of all circuits
289    pub total_duration: u64,
290    /// Total execution time (including gaps)
291    pub total_execution_time: u64,
292    /// Total gap time between circuits
293    pub total_gap_time: u64,
294    /// Average gap between circuits
295    pub average_gap: f64,
296    /// Timing efficiency (active time / total time)
297    pub efficiency: f64,
298    /// Compression ratio (how much timeline was compressed)
299    pub compression_ratio: f64,
300}
301
302/// Advanced timing optimizer
303pub struct TimingOptimizer;
304
305impl TimingOptimizer {
306    /// Optimize timing using advanced algorithms
307    pub fn optimize_advanced(
308        timings: &mut [CircuitTiming],
309        constraints: &TimingConstraints,
310    ) -> Result<OptimizerResult> {
311        let original_stats = Self::calculate_stats(timings);
312
313        // Apply various optimization techniques
314        Self::apply_parallelization(timings, constraints)?;
315        Self::apply_reordering(timings, constraints)?;
316        Self::apply_compression(timings, constraints)?;
317
318        let optimized_stats = Self::calculate_stats(timings);
319
320        Ok(OptimizerResult {
321            original_duration: original_stats.total_execution_time,
322            optimized_duration: optimized_stats.total_execution_time,
323            improvement: (original_stats.total_execution_time as f64 - optimized_stats.total_execution_time as f64) 
324                        / original_stats.total_execution_time as f64,
325            techniques_applied: vec!["parallelization".to_string(), "reordering".to_string(), "compression".to_string()],
326        })
327    }
328
329    /// Apply parallelization optimization
330    fn apply_parallelization(
331        timings: &mut [CircuitTiming],
332        _constraints: &TimingConstraints,
333    ) -> Result<()> {
334        // Group non-conflicting circuits for parallel execution
335        // This is a simplified implementation
336        for i in 1..timings.len() {
337            // If circuits don't share resources, they can run in parallel
338            if timings[i].start_time > timings[i - 1].start_time + timings[i - 1].duration / 2 {
339                timings[i].start_time = timings[i - 1].start_time;
340                timings[i].estimated_end_time = timings[i].start_time + timings[i].duration;
341            }
342        }
343        Ok(())
344    }
345
346    /// Apply reordering optimization
347    fn apply_reordering(
348        timings: &mut [CircuitTiming],
349        _constraints: &TimingConstraints,
350    ) -> Result<()> {
351        // Sort by duration (shortest first) for better packing
352        timings.sort_by_key(|t| t.duration);
353        
354        // Reassign start times
355        let mut current_time = 0;
356        for timing in timings.iter_mut() {
357            timing.start_time = current_time;
358            timing.estimated_end_time = current_time + timing.duration;
359            current_time += timing.duration;
360        }
361        
362        Ok(())
363    }
364
365    /// Apply compression optimization
366    fn apply_compression(
367        timings: &mut [CircuitTiming],
368        constraints: &TimingConstraints,
369    ) -> Result<()> {
370        let min_gap = constraints.min_gap_time;
371        
372        // Remove excessive gaps
373        for i in 1..timings.len() {
374            let actual_gap = timings[i].start_time.saturating_sub(timings[i - 1].estimated_end_time);
375            if actual_gap > min_gap {
376                let excess = actual_gap - min_gap;
377                timings[i].start_time -= excess;
378                timings[i].estimated_end_time -= excess;
379            }
380        }
381        
382        Ok(())
383    }
384
385    /// Calculate basic statistics
386    fn calculate_stats(timings: &[CircuitTiming]) -> TimingStatistics {
387        let timer = CircuitTimer::new();
388        timer.calculate_statistics(timings)
389    }
390}
391
392/// Timing constraints for optimization
393#[derive(Debug, Clone, Serialize, Deserialize)]
394pub struct TimingConstraints {
395    /// Minimum gap time between circuits
396    pub min_gap_time: u64,
397    /// Maximum allowed total duration
398    pub max_total_duration: Option<u64>,
399    /// Resource conflict information
400    pub resource_conflicts: HashMap<(usize, usize), bool>,
401    /// Priority weights for circuits
402    pub circuit_priorities: Vec<f64>,
403}
404
405impl Default for TimingConstraints {
406    fn default() -> Self {
407        Self {
408            min_gap_time: 1000, // 1ms
409            max_total_duration: None,
410            resource_conflicts: HashMap::new(),
411            circuit_priorities: Vec::new(),
412        }
413    }
414}
415
416/// Result of timing optimization
417#[derive(Debug, Clone, Serialize, Deserialize)]
418pub struct OptimizerResult {
419    /// Original total duration
420    pub original_duration: u64,
421    /// Optimized total duration
422    pub optimized_duration: u64,
423    /// Improvement ratio (0.0 to 1.0)
424    pub improvement: f64,
425    /// List of optimization techniques applied
426    pub techniques_applied: Vec<String>,
427}
428
429#[cfg(test)]
430mod tests {
431    use super::*;
432
433    #[test]
434    fn test_circuit_timing_creation() {
435        let timing = CircuitTiming::new(1000, 5000);
436        assert_eq!(timing.start_time, 1000);
437        assert_eq!(timing.duration, 5000);
438        assert_eq!(timing.estimated_end_time, 6000);
439    }
440
441    #[test]
442    fn test_timing_overlap() {
443        let timing1 = CircuitTiming::new(1000, 3000);
444        let timing2 = CircuitTiming::new(2000, 3000);
445        let timing3 = CircuitTiming::new(5000, 1000);
446
447        assert!(timing1.overlaps_with(&timing2));
448        assert!(!timing1.overlaps_with(&timing3));
449    }
450
451    #[test]
452    fn test_circuit_timer() {
453        let timer = CircuitTimer::new();
454        let timing = timer.create_timing(1001, 2001);
455        
456        // Should align to precision boundary
457        assert_eq!(timing.start_time, 1001);
458        assert_eq!(timing.duration, 2001);
459    }
460
461    #[test]
462    fn test_timing_optimization() {
463        let timer = CircuitTimer::new();
464        let mut timings = vec![
465            CircuitTiming::new(1000, 2000),
466            CircuitTiming::new(5000, 1000), // Large gap
467            CircuitTiming::new(8000, 1500),
468        ];
469
470        timer.optimize_timings(&mut timings).unwrap();
471        
472        // Should compress timeline
473        assert_eq!(timings[0].start_time, 0);
474        assert!(timings[1].start_time >= timings[0].estimated_end_time);
475    }
476
477    #[test]
478    fn test_timing_validation() {
479        let timer = CircuitTimer::new();
480        let timings = vec![
481            CircuitTiming::new(1000, 2000),
482            CircuitTiming::new(1500, 1000), // Overlaps with first
483        ];
484
485        let violations = timer.validate_timings(&timings).unwrap();
486        assert_eq!(violations.len(), 1);
487        assert_eq!(violations[0].violation_type, ViolationType::Overlap);
488    }
489
490    #[test]
491    fn test_timing_statistics() {
492        let timer = CircuitTimer::new();
493        let timings = vec![
494            CircuitTiming::new(0, 1000),
495            CircuitTiming::new(2000, 1500), // 1000μs gap
496            CircuitTiming::new(4000, 500),  // 500μs gap
497        ];
498
499        let stats = timer.calculate_statistics(&timings);
500        assert_eq!(stats.total_circuits, 3);
501        assert_eq!(stats.total_duration, 3000);
502        assert_eq!(stats.total_execution_time, 4500);
503        assert_eq!(stats.total_gap_time, 1500);
504    }
505}