Skip to main content

cbtop/performance_prediction/
types.rs

1//! Types for the performance prediction model.
2
3/// Minimum samples required for fitting
4pub const MIN_SAMPLES_FOR_FIT: usize = 5;
5
6/// Performance data point
7#[derive(Debug, Clone, Copy)]
8pub struct DataPoint {
9    /// Problem size (elements)
10    pub size: usize,
11    /// Performance metric (GFLOP/s, throughput, etc.)
12    pub performance: f64,
13    /// Latency (microseconds)
14    pub latency_us: f64,
15}
16
17impl DataPoint {
18    /// Create new data point
19    pub fn new(size: usize, performance: f64, latency_us: f64) -> Self {
20        Self {
21            size,
22            performance,
23            latency_us,
24        }
25    }
26}
27
28/// Model type for curve fitting
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30pub enum ModelType {
31    /// Linear: y = a*x + b
32    Linear,
33    /// Polynomial: y = a*x^2 + b*x + c
34    Polynomial,
35    /// Exponential decay: y = a * exp(-b*x) + c
36    ExponentialDecay,
37    /// Logarithmic: y = a * log(x) + b
38    Logarithmic,
39    /// Roofline: y = min(peak, bandwidth * intensity)
40    Roofline,
41}
42
43impl ModelType {
44    /// Get model name
45    pub fn name(&self) -> &'static str {
46        match self {
47            Self::Linear => "linear",
48            Self::Polynomial => "polynomial",
49            Self::ExponentialDecay => "exponential_decay",
50            Self::Logarithmic => "logarithmic",
51            Self::Roofline => "roofline",
52        }
53    }
54}
55
56/// Fitted model parameters
57#[derive(Debug, Clone)]
58pub struct FittedModel {
59    /// Model type
60    pub model_type: ModelType,
61    /// Model coefficients
62    pub coefficients: Vec<f64>,
63    /// R-squared (coefficient of determination)
64    pub r_squared: f64,
65    /// Residual sum of squares
66    pub rss: f64,
67    /// Number of data points used
68    pub sample_count: usize,
69}
70
71impl FittedModel {
72    /// Predict performance at given size
73    pub fn predict(&self, size: usize) -> f64 {
74        let x = size as f64;
75        match self.model_type {
76            ModelType::Linear => {
77                // y = a*x + b
78                let a = self.coefficients.first().copied().unwrap_or(0.0);
79                let b = self.coefficients.get(1).copied().unwrap_or(0.0);
80                a * x + b
81            }
82            ModelType::Polynomial => {
83                // y = a*x^2 + b*x + c
84                let a = self.coefficients.first().copied().unwrap_or(0.0);
85                let b = self.coefficients.get(1).copied().unwrap_or(0.0);
86                let c = self.coefficients.get(2).copied().unwrap_or(0.0);
87                a * x * x + b * x + c
88            }
89            ModelType::ExponentialDecay => {
90                // y = a * exp(-b*x) + c
91                let a = self.coefficients.first().copied().unwrap_or(0.0);
92                let b = self.coefficients.get(1).copied().unwrap_or(0.0);
93                let c = self.coefficients.get(2).copied().unwrap_or(0.0);
94                a * (-b * x).exp() + c
95            }
96            ModelType::Logarithmic => {
97                // y = a * log(x) + b
98                let a = self.coefficients.first().copied().unwrap_or(0.0);
99                let b = self.coefficients.get(1).copied().unwrap_or(0.0);
100                if x > 0.0 {
101                    a * x.ln() + b
102                } else {
103                    b
104                }
105            }
106            ModelType::Roofline => {
107                // y = min(peak, bandwidth * intensity)
108                // Simplified: use polynomial approximation
109                let peak = self.coefficients.first().copied().unwrap_or(100.0);
110                let _knee = self.coefficients.get(1).copied().unwrap_or(1000.0);
111                let slope = self.coefficients.get(2).copied().unwrap_or(1.0);
112
113                let linear = slope * x;
114                linear.min(peak).max(0.0)
115            }
116        }
117    }
118
119    /// Check if model has good fit (R-squared > 0.9)
120    pub fn is_good_fit(&self) -> bool {
121        self.r_squared > 0.9
122    }
123}
124
125/// Prediction result with confidence bounds
126#[derive(Debug, Clone)]
127pub struct Prediction {
128    /// Predicted size
129    pub size: usize,
130    /// Predicted performance
131    pub predicted: f64,
132    /// Lower bound (confidence interval)
133    pub lower_bound: f64,
134    /// Upper bound (confidence interval)
135    pub upper_bound: f64,
136    /// Confidence level (e.g., 0.95 for 95%)
137    pub confidence_level: f64,
138    /// Model used for prediction
139    pub model_type: ModelType,
140    /// Is this extrapolation (outside training range)?
141    pub is_extrapolation: bool,
142}
143
144impl Prediction {
145    /// Check if prediction is reasonable
146    pub fn is_reasonable(&self) -> bool {
147        self.predicted > 0.0
148            && self.lower_bound >= 0.0
149            && self.upper_bound >= self.predicted
150            && !self.predicted.is_nan()
151            && !self.predicted.is_infinite()
152    }
153
154    /// Get prediction range width
155    pub fn range_width(&self) -> f64 {
156        self.upper_bound - self.lower_bound
157    }
158
159    /// Get prediction uncertainty (%)
160    pub fn uncertainty_percent(&self) -> f64 {
161        if self.predicted > 0.0 {
162            (self.range_width() / self.predicted) * 100.0 / 2.0
163        } else {
164            100.0
165        }
166    }
167}