memscope_rs/unified/strategies/
mod.rs1pub mod async_strategy;
26pub mod hybrid_strategy;
27pub mod single_thread;
28pub mod thread_local;
29
30pub use async_strategy::AsyncStrategy;
32pub use hybrid_strategy::HybridStrategy;
33pub use single_thread::SingleThreadStrategy;
34pub use thread_local::ThreadLocalStrategy;
35
36use crate::unified::tracking_dispatcher::{MemoryTracker, TrackerConfig, TrackerError};
37use std::collections::HashMap;
38use tracing::{debug, info};
39
40pub struct StrategyFactory {
43 strategy_configs: HashMap<String, TrackerConfig>,
45 performance_history: PerformanceHistory,
47}
48
49#[derive(Debug, Clone)]
52pub struct PerformanceHistory {
53 pub strategy_performance: HashMap<String, StrategyPerformance>,
55 pub total_sessions: u64,
57 pub average_overhead_percent: f64,
59}
60
61#[derive(Debug, Clone)]
64pub struct StrategyPerformance {
65 pub session_count: u64,
67 pub avg_overhead_percent: f64,
69 pub avg_init_time_us: f64,
71 pub success_rate: f64,
73 pub satisfaction_score: f64,
75}
76
77impl Default for PerformanceHistory {
78 fn default() -> Self {
80 Self {
81 strategy_performance: HashMap::new(),
82 total_sessions: 0,
83 average_overhead_percent: 0.0,
84 }
85 }
86}
87
88impl Default for StrategyPerformance {
89 fn default() -> Self {
91 Self {
92 session_count: 0,
93 avg_overhead_percent: 2.0, avg_init_time_us: 100.0, success_rate: 1.0, satisfaction_score: 0.8, }
98 }
99}
100
101impl StrategyFactory {
102 pub fn new() -> Self {
105 let mut strategy_configs = HashMap::new();
106
107 strategy_configs.insert(
109 "single_thread".to_string(),
110 TrackerConfig {
111 sample_rate: 1.0, max_overhead_mb: 32, thread_affinity: None, custom_params: HashMap::new(),
115 },
116 );
117
118 strategy_configs.insert(
120 "thread_local".to_string(),
121 TrackerConfig {
122 sample_rate: 0.8, max_overhead_mb: 64, thread_affinity: None, custom_params: HashMap::new(),
126 },
127 );
128
129 strategy_configs.insert(
131 "async".to_string(),
132 TrackerConfig {
133 sample_rate: 0.9, max_overhead_mb: 48, thread_affinity: None, custom_params: HashMap::new(),
137 },
138 );
139
140 strategy_configs.insert(
142 "hybrid".to_string(),
143 TrackerConfig {
144 sample_rate: 0.7, max_overhead_mb: 96, thread_affinity: None, custom_params: HashMap::new(),
148 },
149 );
150
151 Self {
152 strategy_configs,
153 performance_history: PerformanceHistory::default(),
154 }
155 }
156
157 pub fn create_single_thread_strategy(&self) -> Result<Box<dyn MemoryTracker>, TrackerError> {
160 debug!("Creating single-thread strategy");
161
162 let config = self
163 .strategy_configs
164 .get("single_thread")
165 .cloned()
166 .unwrap_or_default();
167
168 let mut strategy = SingleThreadStrategy::new();
169 strategy.initialize(config)?;
170
171 info!("Single-thread strategy created successfully");
172 Ok(Box::new(strategy))
173 }
174
175 pub fn create_thread_local_strategy(&self) -> Result<Box<dyn MemoryTracker>, TrackerError> {
178 debug!("Creating thread-local strategy");
179
180 let config = self
181 .strategy_configs
182 .get("thread_local")
183 .cloned()
184 .unwrap_or_default();
185
186 let mut strategy = ThreadLocalStrategy::new();
187 strategy.initialize(config)?;
188
189 info!("Thread-local strategy created successfully");
190 Ok(Box::new(strategy))
191 }
192
193 pub fn create_async_strategy(&self) -> Result<Box<dyn MemoryTracker>, TrackerError> {
196 debug!("Creating async strategy");
197
198 let config = self
199 .strategy_configs
200 .get("async")
201 .cloned()
202 .unwrap_or_default();
203
204 let mut strategy = AsyncStrategy::new();
205 strategy.initialize(config)?;
206
207 info!("Async strategy created successfully");
208 Ok(Box::new(strategy))
209 }
210
211 pub fn create_hybrid_strategy(&self) -> Result<Box<dyn MemoryTracker>, TrackerError> {
214 debug!("Creating hybrid strategy");
215
216 let config = self
217 .strategy_configs
218 .get("hybrid")
219 .cloned()
220 .unwrap_or_default();
221
222 let mut strategy = HybridStrategy::new();
223 strategy.initialize(config)?;
224
225 info!("Hybrid strategy created successfully");
226 Ok(Box::new(strategy))
227 }
228
229 pub fn record_performance(&mut self, strategy_name: &str, performance: StrategyPerformance) {
232 debug!("Recording performance for strategy: {}", strategy_name);
233
234 let (avg_overhead_percent, success_rate) = {
235 let entry = self
236 .performance_history
237 .strategy_performance
238 .entry(strategy_name.to_string())
239 .or_default();
240
241 let weight = 0.1; entry.avg_overhead_percent = (1.0 - weight) * entry.avg_overhead_percent
244 + weight * performance.avg_overhead_percent;
245 entry.avg_init_time_us =
246 (1.0 - weight) * entry.avg_init_time_us + weight * performance.avg_init_time_us;
247 entry.success_rate =
248 (1.0 - weight) * entry.success_rate + weight * performance.success_rate;
249 entry.satisfaction_score =
250 (1.0 - weight) * entry.satisfaction_score + weight * performance.satisfaction_score;
251
252 entry.session_count += 1;
253
254 (entry.avg_overhead_percent, entry.success_rate)
255 };
256
257 self.performance_history.total_sessions += 1;
258
259 self.update_average_overhead();
261
262 info!(
263 "Performance recorded for {}: overhead={:.2}%, success={:.2}%",
264 strategy_name,
265 avg_overhead_percent,
266 success_rate * 100.0
267 );
268 }
269
270 fn update_average_overhead(&mut self) {
272 if self.performance_history.strategy_performance.is_empty() {
273 return;
274 }
275
276 let total_overhead: f64 = self
277 .performance_history
278 .strategy_performance
279 .values()
280 .map(|perf| perf.avg_overhead_percent)
281 .sum();
282
283 self.performance_history.average_overhead_percent =
284 total_overhead / self.performance_history.strategy_performance.len() as f64;
285 }
286
287 pub fn get_performance_history(&self) -> &PerformanceHistory {
290 &self.performance_history
291 }
292
293 pub fn recommend_strategy(&self, requirements: &StrategyRequirements) -> String {
296 debug!("Recommending strategy for requirements: {:?}", requirements);
297
298 let mut best_strategy = "single_thread".to_string();
299 let mut best_score = 0.0;
300
301 for (strategy_name, performance) in &self.performance_history.strategy_performance {
302 let score = self.calculate_strategy_score(strategy_name, performance, requirements);
303
304 if score > best_score {
305 best_score = score;
306 best_strategy = strategy_name.clone();
307 }
308 }
309
310 info!(
311 "Recommended strategy: {} (score: {:.2})",
312 best_strategy, best_score
313 );
314 best_strategy
315 }
316
317 fn calculate_strategy_score(
319 &self,
320 _strategy_name: &str,
321 performance: &StrategyPerformance,
322 requirements: &StrategyRequirements,
323 ) -> f64 {
324 let overhead_weight = 0.3;
326 let speed_weight = 0.3;
327 let reliability_weight = 0.4;
328
329 let overhead_score = if requirements.max_overhead_percent > 0.0 {
331 (requirements.max_overhead_percent - performance.avg_overhead_percent).max(0.0)
332 / requirements.max_overhead_percent
333 } else {
334 1.0 - (performance.avg_overhead_percent / 10.0) };
336
337 let speed_score = 1.0 - (performance.avg_init_time_us / 10000.0).min(1.0); let reliability_score = performance.success_rate * performance.satisfaction_score;
342
343 let score = overhead_weight * overhead_score
344 + speed_weight * speed_score
345 + reliability_weight * reliability_score;
346
347 score.clamp(0.0, 1.0) }
349}
350
351impl Default for StrategyFactory {
352 fn default() -> Self {
354 Self::new()
355 }
356}
357
358#[derive(Debug, Clone)]
361pub struct StrategyRequirements {
362 pub max_overhead_percent: f64,
364 pub preferred_init_time_us: f64,
366 pub min_success_rate: f64,
368 pub environment_constraints: Vec<String>,
370}
371
372impl Default for StrategyRequirements {
373 fn default() -> Self {
375 Self {
376 max_overhead_percent: 5.0,
377 preferred_init_time_us: 1000.0, min_success_rate: 0.95,
379 environment_constraints: vec![],
380 }
381 }
382}
383
384#[cfg(test)]
385mod tests {
386 use super::*;
387
388 #[test]
389 fn test_strategy_factory_creation() {
390 let factory = StrategyFactory::new();
391 assert_eq!(factory.strategy_configs.len(), 4);
392 assert!(factory.strategy_configs.contains_key("single_thread"));
393 assert!(factory.strategy_configs.contains_key("thread_local"));
394 assert!(factory.strategy_configs.contains_key("async"));
395 assert!(factory.strategy_configs.contains_key("hybrid"));
396 }
397
398 #[test]
399 fn test_single_thread_strategy_creation() {
400 let factory = StrategyFactory::new();
401 let result = factory.create_single_thread_strategy();
402 assert!(result.is_ok());
403 }
404
405 #[test]
406 fn test_all_strategy_creation() {
407 let factory = StrategyFactory::new();
408
409 assert!(factory.create_single_thread_strategy().is_ok());
411 assert!(factory.create_thread_local_strategy().is_ok());
412 assert!(factory.create_async_strategy().is_ok());
413 assert!(factory.create_hybrid_strategy().is_ok());
414 }
415
416 #[test]
417 fn test_performance_recording() {
418 let mut factory = StrategyFactory::new();
419 let performance = StrategyPerformance {
420 session_count: 1,
421 avg_overhead_percent: 2.5,
422 avg_init_time_us: 150.0,
423 success_rate: 0.98,
424 satisfaction_score: 0.9,
425 };
426
427 factory.record_performance("single_thread", performance);
428
429 let history = factory.get_performance_history();
430 assert_eq!(history.total_sessions, 1);
431 assert!(history.strategy_performance.contains_key("single_thread"));
432 }
433
434 #[test]
435 fn test_strategy_recommendation() {
436 let mut factory = StrategyFactory::new();
437
438 factory.record_performance(
440 "single_thread",
441 StrategyPerformance {
442 avg_overhead_percent: 1.0,
443 success_rate: 0.99,
444 satisfaction_score: 0.95,
445 ..Default::default()
446 },
447 );
448
449 let requirements = StrategyRequirements::default();
450 let recommendation = factory.recommend_strategy(&requirements);
451
452 assert_eq!(recommendation, "single_thread");
453 }
454
455 #[test]
456 fn test_performance_history_update() {
457 let mut factory = StrategyFactory::new();
458
459 for i in 0..5 {
461 factory.record_performance(
462 "test_strategy",
463 StrategyPerformance {
464 avg_overhead_percent: 2.0 + i as f64 * 0.1,
465 ..Default::default()
466 },
467 );
468 }
469
470 let history = factory.get_performance_history();
471 assert_eq!(history.total_sessions, 5);
472 assert!(history.average_overhead_percent > 0.0);
473 }
474}