1use serde::{Deserialize, Serialize};
9use std::time::Duration;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct RuntimeConfig {
14 pub gpu_enabled: bool,
16 pub primary_backend: String,
18 pub fallback_backend: Option<String>,
20 pub max_kernel_instances: usize,
22 pub max_queue_depth: usize,
24 pub drain_timeout: Duration,
26 pub health_check_interval: Duration,
28 pub hot_reload_enabled: bool,
30 pub structured_logging: bool,
32 pub log_level: String,
34 pub metrics_interval: Duration,
36 pub backend: BackendConfig,
38 pub worker_threads: usize,
40}
41
42impl Default for RuntimeConfig {
43 fn default() -> Self {
44 Self::development()
45 }
46}
47
48impl RuntimeConfig {
49 pub fn development() -> Self {
51 Self {
52 gpu_enabled: false,
53 primary_backend: "cpu".to_string(),
54 fallback_backend: None,
55 max_kernel_instances: 100,
56 max_queue_depth: 1000,
57 drain_timeout: Duration::from_secs(5),
58 health_check_interval: Duration::from_secs(30),
59 hot_reload_enabled: true,
60 structured_logging: false,
61 log_level: "debug".to_string(),
62 metrics_interval: Duration::from_secs(60),
63 backend: BackendConfig::default(),
64 worker_threads: 0,
65 }
66 }
67
68 pub fn production() -> Self {
70 Self {
71 gpu_enabled: true,
72 primary_backend: "cuda".to_string(),
73 fallback_backend: Some("cpu".to_string()),
74 max_kernel_instances: 1000,
75 max_queue_depth: 10_000,
76 drain_timeout: Duration::from_secs(30),
77 health_check_interval: Duration::from_secs(10),
78 hot_reload_enabled: false,
79 structured_logging: true,
80 log_level: "info".to_string(),
81 metrics_interval: Duration::from_secs(15),
82 backend: BackendConfig::production(),
83 worker_threads: 0,
84 }
85 }
86
87 pub fn high_performance() -> Self {
89 Self {
90 gpu_enabled: true,
91 primary_backend: "cuda".to_string(),
92 fallback_backend: None,
93 max_kernel_instances: 10_000,
94 max_queue_depth: 100_000,
95 drain_timeout: Duration::from_secs(10),
96 health_check_interval: Duration::from_secs(5),
97 hot_reload_enabled: false,
98 structured_logging: true,
99 log_level: "warn".to_string(),
100 metrics_interval: Duration::from_secs(5),
101 backend: BackendConfig::high_performance(),
102 worker_threads: 0,
103 }
104 }
105
106 pub fn testing() -> Self {
108 Self {
109 gpu_enabled: false,
110 primary_backend: "cpu".to_string(),
111 fallback_backend: None,
112 max_kernel_instances: 10,
113 max_queue_depth: 100,
114 drain_timeout: Duration::from_millis(100),
115 health_check_interval: Duration::from_secs(1),
116 hot_reload_enabled: false,
117 structured_logging: false,
118 log_level: "trace".to_string(),
119 metrics_interval: Duration::from_secs(1),
120 backend: BackendConfig::testing(),
121 worker_threads: 1,
122 }
123 }
124
125 pub fn from_env() -> Self {
127 let mut config = Self::default();
128
129 if let Ok(val) = std::env::var("RUSTKERNEL_GPU_ENABLED") {
130 config.gpu_enabled = val.parse().unwrap_or(config.gpu_enabled);
131 }
132 if let Ok(val) = std::env::var("RUSTKERNEL_BACKEND") {
133 config.primary_backend = val;
134 }
135 if let Ok(val) = std::env::var("RUSTKERNEL_FALLBACK_BACKEND") {
136 config.fallback_backend = Some(val);
137 }
138 if let Ok(val) = std::env::var("RUSTKERNEL_MAX_INSTANCES") {
139 config.max_kernel_instances = val.parse().unwrap_or(config.max_kernel_instances);
140 }
141 if let Ok(val) = std::env::var("RUSTKERNEL_QUEUE_DEPTH") {
142 config.max_queue_depth = val.parse().unwrap_or(config.max_queue_depth);
143 }
144 if let Ok(val) = std::env::var("RUSTKERNEL_DRAIN_TIMEOUT_SECS") {
145 config.drain_timeout =
146 Duration::from_secs(val.parse().unwrap_or(config.drain_timeout.as_secs()));
147 }
148 if let Ok(val) = std::env::var("RUSTKERNEL_LOG_LEVEL") {
149 config.log_level = val;
150 }
151 if let Ok(val) = std::env::var("RUSTKERNEL_STRUCTURED_LOGGING") {
152 config.structured_logging = val.parse().unwrap_or(config.structured_logging);
153 }
154 if let Ok(val) = std::env::var("RUSTKERNEL_WORKER_THREADS") {
155 config.worker_threads = val.parse().unwrap_or(config.worker_threads);
156 }
157
158 config
159 }
160
161 pub fn from_file(path: &std::path::Path) -> Result<Self, ConfigError> {
163 let contents = std::fs::read_to_string(path).map_err(ConfigError::IoError)?;
164
165 let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("toml");
166
167 match ext {
168 "json" => serde_json::from_str(&contents).map_err(ConfigError::JsonError),
169 "toml" => toml::from_str(&contents).map_err(ConfigError::TomlError),
170 _ => Err(ConfigError::UnsupportedFormat(ext.to_string())),
171 }
172 }
173
174 pub fn builder() -> RuntimeConfigBuilder {
176 RuntimeConfigBuilder::default()
177 }
178
179 pub fn validate(&self) -> Result<(), ConfigError> {
181 if self.max_kernel_instances == 0 {
182 return Err(ConfigError::InvalidValue(
183 "max_kernel_instances must be > 0".to_string(),
184 ));
185 }
186 if self.max_queue_depth == 0 {
187 return Err(ConfigError::InvalidValue(
188 "max_queue_depth must be > 0".to_string(),
189 ));
190 }
191 if self.drain_timeout.is_zero() {
192 return Err(ConfigError::InvalidValue(
193 "drain_timeout must be > 0".to_string(),
194 ));
195 }
196 Ok(())
197 }
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct BackendConfig {
203 pub cuda_device: i32,
205 pub cuda_unified_memory: bool,
207 pub memory_limit_bytes: u64,
209 pub memory_pooling: bool,
211 pub pool_initial_bytes: u64,
213 pub pool_growth_factor: f32,
215 pub async_memory: bool,
217 pub kernel_fusion: bool,
219 pub max_batch_size: usize,
221}
222
223impl Default for BackendConfig {
224 fn default() -> Self {
225 Self {
226 cuda_device: 0,
227 cuda_unified_memory: false,
228 memory_limit_bytes: 0,
229 memory_pooling: true,
230 pool_initial_bytes: 64 * 1024 * 1024, pool_growth_factor: 2.0,
232 async_memory: true,
233 kernel_fusion: false,
234 max_batch_size: 1024,
235 }
236 }
237}
238
239impl BackendConfig {
240 pub fn production() -> Self {
242 Self {
243 cuda_device: 0,
244 cuda_unified_memory: false,
245 memory_limit_bytes: 0,
246 memory_pooling: true,
247 pool_initial_bytes: 256 * 1024 * 1024, pool_growth_factor: 1.5,
249 async_memory: true,
250 kernel_fusion: true,
251 max_batch_size: 4096,
252 }
253 }
254
255 pub fn high_performance() -> Self {
257 Self {
258 cuda_device: 0,
259 cuda_unified_memory: false,
260 memory_limit_bytes: 0,
261 memory_pooling: true,
262 pool_initial_bytes: 1024 * 1024 * 1024, pool_growth_factor: 1.25,
264 async_memory: true,
265 kernel_fusion: true,
266 max_batch_size: 16384,
267 }
268 }
269
270 pub fn testing() -> Self {
272 Self {
273 cuda_device: 0,
274 cuda_unified_memory: false,
275 memory_limit_bytes: 16 * 1024 * 1024, memory_pooling: false,
277 pool_initial_bytes: 1024 * 1024, pool_growth_factor: 2.0,
279 async_memory: false,
280 kernel_fusion: false,
281 max_batch_size: 64,
282 }
283 }
284}
285
286#[derive(Debug, Clone, Default)]
288pub struct RuntimeConfigBuilder {
289 config: RuntimeConfig,
290}
291
292impl RuntimeConfigBuilder {
293 pub fn development() -> Self {
295 Self {
296 config: RuntimeConfig::development(),
297 }
298 }
299
300 pub fn production() -> Self {
302 Self {
303 config: RuntimeConfig::production(),
304 }
305 }
306
307 pub fn high_performance() -> Self {
309 Self {
310 config: RuntimeConfig::high_performance(),
311 }
312 }
313
314 pub fn gpu_enabled(mut self, enabled: bool) -> Self {
316 self.config.gpu_enabled = enabled;
317 self
318 }
319
320 pub fn primary_backend(mut self, backend: impl Into<String>) -> Self {
322 self.config.primary_backend = backend.into();
323 self
324 }
325
326 pub fn fallback_backend(mut self, backend: impl Into<String>) -> Self {
328 self.config.fallback_backend = Some(backend.into());
329 self
330 }
331
332 pub fn max_kernel_instances(mut self, count: usize) -> Self {
334 self.config.max_kernel_instances = count;
335 self
336 }
337
338 pub fn max_queue_depth(mut self, depth: usize) -> Self {
340 self.config.max_queue_depth = depth;
341 self
342 }
343
344 pub fn drain_timeout(mut self, timeout: Duration) -> Self {
346 self.config.drain_timeout = timeout;
347 self
348 }
349
350 pub fn health_check_interval(mut self, interval: Duration) -> Self {
352 self.config.health_check_interval = interval;
353 self
354 }
355
356 pub fn hot_reload(mut self, enabled: bool) -> Self {
358 self.config.hot_reload_enabled = enabled;
359 self
360 }
361
362 pub fn structured_logging(mut self, enabled: bool) -> Self {
364 self.config.structured_logging = enabled;
365 self
366 }
367
368 pub fn log_level(mut self, level: impl Into<String>) -> Self {
370 self.config.log_level = level.into();
371 self
372 }
373
374 pub fn metrics_interval(mut self, interval: Duration) -> Self {
376 self.config.metrics_interval = interval;
377 self
378 }
379
380 pub fn backend_config(mut self, config: BackendConfig) -> Self {
382 self.config.backend = config;
383 self
384 }
385
386 pub fn worker_threads(mut self, count: usize) -> Self {
388 self.config.worker_threads = count;
389 self
390 }
391
392 pub fn build(self) -> Result<RuntimeConfig, ConfigError> {
394 self.config.validate()?;
395 Ok(self.config)
396 }
397
398 pub fn build_unchecked(self) -> RuntimeConfig {
400 self.config
401 }
402}
403
404#[derive(Debug, thiserror::Error)]
406pub enum ConfigError {
407 #[error("IO error: {0}")]
409 IoError(#[from] std::io::Error),
410
411 #[error("JSON parse error: {0}")]
413 JsonError(#[from] serde_json::Error),
414
415 #[error("TOML parse error: {0}")]
417 TomlError(#[from] toml::de::Error),
418
419 #[error("Unsupported config format: {0}")]
421 UnsupportedFormat(String),
422
423 #[error("Invalid config value: {0}")]
425 InvalidValue(String),
426
427 #[error("Missing required field: {0}")]
429 MissingField(String),
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435
436 #[test]
437 fn test_default_config() {
438 let config = RuntimeConfig::default();
439 assert!(!config.gpu_enabled);
440 assert_eq!(config.primary_backend, "cpu");
441 }
442
443 #[test]
444 fn test_production_config() {
445 let config = RuntimeConfig::production();
446 assert!(config.gpu_enabled);
447 assert_eq!(config.primary_backend, "cuda");
448 assert!(config.structured_logging);
449 }
450
451 #[test]
452 fn test_config_validation() {
453 let config = RuntimeConfig {
454 max_kernel_instances: 0,
455 ..RuntimeConfig::default()
456 };
457 assert!(config.validate().is_err());
458
459 let config = RuntimeConfig {
460 max_kernel_instances: 100,
461 max_queue_depth: 0,
462 ..RuntimeConfig::default()
463 };
464 assert!(config.validate().is_err());
465
466 let config = RuntimeConfig {
467 max_kernel_instances: 100,
468 max_queue_depth: 1000,
469 ..RuntimeConfig::default()
470 };
471 assert!(config.validate().is_ok());
472 }
473
474 #[test]
475 fn test_config_builder() {
476 let config = RuntimeConfigBuilder::production()
477 .gpu_enabled(false)
478 .max_kernel_instances(500)
479 .build()
480 .unwrap();
481
482 assert!(!config.gpu_enabled);
483 assert_eq!(config.max_kernel_instances, 500);
484 }
485}