Skip to main content

ringkernel_core/hybrid/
config.rs

1//! Configuration for hybrid CPU-GPU processing.
2
3/// Processing mode for hybrid execution.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum ProcessingMode {
6    /// Always use GPU (if available).
7    GpuOnly,
8    /// Always use CPU (parallel via Rayon or similar).
9    CpuOnly,
10    /// Automatically select based on workload size.
11    Hybrid {
12        /// Minimum elements to use GPU (smaller workloads use CPU).
13        gpu_threshold: usize,
14    },
15    /// Adaptive mode that learns from runtime measurements.
16    Adaptive,
17}
18
19impl Default for ProcessingMode {
20    fn default() -> Self {
21        ProcessingMode::Hybrid {
22            gpu_threshold: 10_000, // 10K elements default threshold
23        }
24    }
25}
26
27impl ProcessingMode {
28    /// Creates a Hybrid mode with the specified threshold.
29    #[must_use]
30    pub fn hybrid(gpu_threshold: usize) -> Self {
31        ProcessingMode::Hybrid { gpu_threshold }
32    }
33
34    /// Returns the GPU threshold if in Hybrid mode.
35    #[must_use]
36    pub fn threshold(&self) -> Option<usize> {
37        match self {
38            ProcessingMode::Hybrid { gpu_threshold } => Some(*gpu_threshold),
39            _ => None,
40        }
41    }
42}
43
44/// Configuration for hybrid processing.
45#[derive(Debug, Clone)]
46pub struct HybridConfig {
47    /// Processing mode.
48    pub mode: ProcessingMode,
49    /// Number of CPU threads (0 = auto-detect from Rayon).
50    pub cpu_threads: usize,
51    /// Whether GPU is available.
52    pub gpu_available: bool,
53    /// Adaptive learning rate (0.0-1.0).
54    pub learning_rate: f32,
55    /// Maximum workload size (0 = unlimited).
56    pub max_workload_size: usize,
57    /// Minimum adaptive threshold (prevents going too low).
58    pub min_adaptive_threshold: usize,
59    /// Maximum adaptive threshold (prevents going too high).
60    pub max_adaptive_threshold: usize,
61}
62
63impl Default for HybridConfig {
64    fn default() -> Self {
65        Self {
66            mode: ProcessingMode::default(),
67            cpu_threads: 0,
68            gpu_available: false,
69            learning_rate: 0.1,
70            max_workload_size: 0,
71            min_adaptive_threshold: 1_000,
72            max_adaptive_threshold: 1_000_000,
73        }
74    }
75}
76
77impl HybridConfig {
78    /// Creates a new configuration with default values.
79    #[must_use]
80    pub fn new() -> Self {
81        Self::default()
82    }
83
84    /// Creates a CPU-only configuration.
85    #[must_use]
86    pub fn cpu_only() -> Self {
87        Self {
88            mode: ProcessingMode::CpuOnly,
89            gpu_available: false,
90            ..Default::default()
91        }
92    }
93
94    /// Creates a GPU-only configuration.
95    #[must_use]
96    pub fn gpu_only() -> Self {
97        Self {
98            mode: ProcessingMode::GpuOnly,
99            gpu_available: true,
100            ..Default::default()
101        }
102    }
103
104    /// Creates an adaptive configuration that learns optimal thresholds.
105    #[must_use]
106    pub fn adaptive() -> Self {
107        Self {
108            mode: ProcessingMode::Adaptive,
109            gpu_available: true,
110            learning_rate: 0.1,
111            ..Default::default()
112        }
113    }
114
115    /// Creates a configuration for small workloads (low threshold).
116    #[must_use]
117    pub fn for_small_workloads() -> Self {
118        Self {
119            mode: ProcessingMode::Hybrid {
120                gpu_threshold: 1_000,
121            },
122            gpu_available: true,
123            ..Default::default()
124        }
125    }
126
127    /// Creates a configuration for large workloads (high threshold).
128    #[must_use]
129    pub fn for_large_workloads() -> Self {
130        Self {
131            mode: ProcessingMode::Hybrid {
132                gpu_threshold: 100_000,
133            },
134            gpu_available: true,
135            ..Default::default()
136        }
137    }
138
139    /// Returns a builder for custom configuration.
140    #[must_use]
141    pub fn builder() -> HybridConfigBuilder {
142        HybridConfigBuilder::new()
143    }
144}
145
146/// Builder for `HybridConfig`.
147#[derive(Debug, Clone)]
148pub struct HybridConfigBuilder {
149    config: HybridConfig,
150}
151
152impl HybridConfigBuilder {
153    /// Creates a new builder with default values.
154    #[must_use]
155    pub fn new() -> Self {
156        Self {
157            config: HybridConfig::default(),
158        }
159    }
160
161    /// Sets the processing mode.
162    #[must_use]
163    pub fn mode(mut self, mode: ProcessingMode) -> Self {
164        self.config.mode = mode;
165        self
166    }
167
168    /// Sets whether GPU is available.
169    #[must_use]
170    pub fn gpu_available(mut self, available: bool) -> Self {
171        self.config.gpu_available = available;
172        self
173    }
174
175    /// Sets the number of CPU threads (0 = auto).
176    #[must_use]
177    pub fn cpu_threads(mut self, threads: usize) -> Self {
178        self.config.cpu_threads = threads;
179        self
180    }
181
182    /// Sets the adaptive learning rate.
183    #[must_use]
184    pub fn learning_rate(mut self, rate: f32) -> Self {
185        self.config.learning_rate = rate.clamp(0.0, 1.0);
186        self
187    }
188
189    /// Sets the maximum workload size.
190    #[must_use]
191    pub fn max_workload_size(mut self, size: usize) -> Self {
192        self.config.max_workload_size = size;
193        self
194    }
195
196    /// Sets the minimum adaptive threshold.
197    #[must_use]
198    pub fn min_adaptive_threshold(mut self, threshold: usize) -> Self {
199        self.config.min_adaptive_threshold = threshold;
200        self
201    }
202
203    /// Sets the maximum adaptive threshold.
204    #[must_use]
205    pub fn max_adaptive_threshold(mut self, threshold: usize) -> Self {
206        self.config.max_adaptive_threshold = threshold;
207        self
208    }
209
210    /// Builds the configuration.
211    #[must_use]
212    pub fn build(self) -> HybridConfig {
213        self.config
214    }
215}
216
217impl Default for HybridConfigBuilder {
218    fn default() -> Self {
219        Self::new()
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use super::*;
226
227    #[test]
228    fn test_processing_mode_default() {
229        let mode = ProcessingMode::default();
230        assert!(matches!(
231            mode,
232            ProcessingMode::Hybrid {
233                gpu_threshold: 10_000
234            }
235        ));
236    }
237
238    #[test]
239    fn test_processing_mode_hybrid() {
240        let mode = ProcessingMode::hybrid(5000);
241        assert_eq!(mode.threshold(), Some(5000));
242    }
243
244    #[test]
245    fn test_config_cpu_only() {
246        let config = HybridConfig::cpu_only();
247        assert_eq!(config.mode, ProcessingMode::CpuOnly);
248        assert!(!config.gpu_available);
249    }
250
251    #[test]
252    fn test_config_gpu_only() {
253        let config = HybridConfig::gpu_only();
254        assert_eq!(config.mode, ProcessingMode::GpuOnly);
255        assert!(config.gpu_available);
256    }
257
258    #[test]
259    fn test_config_builder() {
260        let config = HybridConfig::builder()
261            .mode(ProcessingMode::Adaptive)
262            .gpu_available(true)
263            .learning_rate(0.5)
264            .max_workload_size(1_000_000)
265            .build();
266
267        assert_eq!(config.mode, ProcessingMode::Adaptive);
268        assert!(config.gpu_available);
269        assert!((config.learning_rate - 0.5).abs() < f32::EPSILON);
270        assert_eq!(config.max_workload_size, 1_000_000);
271    }
272
273    #[test]
274    fn test_learning_rate_clamping() {
275        let config = HybridConfig::builder().learning_rate(2.0).build();
276        assert!((config.learning_rate - 1.0).abs() < f32::EPSILON);
277
278        let config = HybridConfig::builder().learning_rate(-0.5).build();
279        assert!(config.learning_rate.abs() < f32::EPSILON);
280    }
281}