1#![allow(dead_code)]
10
11use anyhow::Result;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use tokio::time::{Duration, Instant};
15use tracing::{debug, info};
16
17#[derive(Debug)]
19pub struct AICodeAnalyzer {
20 config: AIAnalysisConfig,
21 analysis_cache: HashMap<String, CachedAnalysis>,
22 pattern_database: ModelPatternDatabase,
23 performance_monitor: AnalysisPerformanceMonitor,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct AIAnalysisConfig {
29 pub enable_deep_analysis: bool,
31 pub enable_pattern_recognition: bool,
33 pub enable_optimization_suggestions: bool,
35 pub enable_vulnerability_detection: bool,
37 pub enable_performance_prediction: bool,
39 pub max_analysis_time_secs: u64,
41 pub confidence_threshold: f64,
43 pub enable_caching: bool,
45 pub cache_expiration_hours: u64,
47}
48
49impl Default for AIAnalysisConfig {
50 fn default() -> Self {
51 Self {
52 enable_deep_analysis: true,
53 enable_pattern_recognition: true,
54 enable_optimization_suggestions: true,
55 enable_vulnerability_detection: true,
56 enable_performance_prediction: true,
57 max_analysis_time_secs: 30,
58 confidence_threshold: 0.75,
59 enable_caching: true,
60 cache_expiration_hours: 24,
61 }
62 }
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67struct CachedAnalysis {
68 result: CodeAnalysisResult,
69 timestamp: std::time::SystemTime,
70 code_hash: String,
71}
72
73#[derive(Debug)]
75struct AnalysisPerformanceMonitor {
76 analysis_count: u64,
77 total_analysis_time: Duration,
78 cache_hits: u64,
79 cache_misses: u64,
80}
81
82impl AnalysisPerformanceMonitor {
83 fn new() -> Self {
84 Self {
85 analysis_count: 0,
86 total_analysis_time: Duration::from_secs(0),
87 cache_hits: 0,
88 cache_misses: 0,
89 }
90 }
91
92 fn record_analysis(&mut self, duration: Duration, cache_hit: bool) {
93 self.analysis_count += 1;
94 self.total_analysis_time += duration;
95 if cache_hit {
96 self.cache_hits += 1;
97 } else {
98 self.cache_misses += 1;
99 }
100 }
101
102 fn average_analysis_time(&self) -> Duration {
103 if self.analysis_count > 0 {
104 self.total_analysis_time / self.analysis_count as u32
105 } else {
106 Duration::from_secs(0)
107 }
108 }
109
110 fn cache_hit_rate(&self) -> f64 {
111 let total = self.cache_hits + self.cache_misses;
112 if total > 0 {
113 self.cache_hits as f64 / total as f64
114 } else {
115 0.0
116 }
117 }
118}
119
120impl AICodeAnalyzer {
121 pub fn new(config: AIAnalysisConfig) -> Self {
123 Self {
124 config,
125 analysis_cache: HashMap::new(),
126 pattern_database: ModelPatternDatabase::new(),
127 performance_monitor: AnalysisPerformanceMonitor::new(),
128 }
129 }
130
131 pub async fn analyze_model_code(
133 &mut self,
134 code: &str,
135 context: ModelContext,
136 ) -> Result<CodeAnalysisResult> {
137 let start_time = Instant::now();
138 let code_hash = self.compute_code_hash(code);
139
140 if self.config.enable_caching {
142 if let Some(cached) = self.get_cached_analysis(&code_hash) {
143 let result = cached.result.clone();
144 self.performance_monitor.record_analysis(start_time.elapsed(), true);
145 return Ok(result);
146 }
147 }
148
149 info!(
150 "Starting AI code analysis for {} lines of code",
151 code.lines().count()
152 );
153
154 let mut result = CodeAnalysisResult::new();
155
156 if self.config.enable_pattern_recognition {
158 let patterns = self.detect_code_patterns(code, &context).await?;
159 result.detected_patterns = patterns;
160 }
161
162 if self.config.enable_deep_analysis {
164 let issues = self.perform_deep_analysis(code, &context).await?;
165 result.identified_issues = issues;
166 }
167
168 if self.config.enable_optimization_suggestions {
170 let optimizations = self.generate_optimization_suggestions(code, &context).await?;
171 result.optimization_suggestions = optimizations;
172 }
173
174 if self.config.enable_vulnerability_detection {
176 let vulnerabilities = self.detect_vulnerabilities(code, &context).await?;
177 result.security_issues = vulnerabilities;
178 }
179
180 if self.config.enable_performance_prediction {
182 let predictions = self.predict_performance_characteristics(code, &context).await?;
183 result.performance_predictions = predictions;
184 }
185
186 result.quality_score = self.calculate_quality_score(&result);
188 result.analysis_metadata = AnalysisMetadata {
189 analysis_duration: start_time.elapsed(),
190 confidence_score: self.calculate_confidence_score(&result),
191 analyzer_version: "1.0.0".to_string(),
192 timestamp: std::time::SystemTime::now(),
193 };
194
195 if self.config.enable_caching {
197 self.cache_analysis(code_hash, &result);
198 }
199
200 self.performance_monitor.record_analysis(start_time.elapsed(), false);
201
202 info!(
203 "AI code analysis completed in {:?} with quality score: {:.2}",
204 start_time.elapsed(),
205 result.quality_score
206 );
207
208 Ok(result)
209 }
210
211 pub async fn analyze_tensor_operations(
213 &self,
214 operations: &[TensorOperation],
215 ) -> Result<TensorOptimizationReport> {
216 debug!("Analyzing {} tensor operations", operations.len());
217
218 let mut report = TensorOptimizationReport::new();
219
220 report.fusion_opportunities = self.detect_fusion_opportunities(operations).await?;
222 report.memory_optimizations = self.detect_memory_optimizations(operations).await?;
223 report.parallelization_opportunities =
224 self.detect_parallelization_opportunities(operations).await?;
225 report.redundant_operations = self.detect_redundant_operations(operations).await?;
226
227 report.estimated_speedup = self.estimate_optimization_speedup(&report);
229 report.estimated_memory_savings = self.estimate_memory_savings(&report);
230
231 Ok(report)
232 }
233
234 pub async fn automated_debugging_assistance(
236 &self,
237 error_context: &ErrorContext,
238 ) -> Result<DebuggingAssistance> {
239 info!(
240 "Providing automated debugging assistance for error: {}",
241 error_context.error_type
242 );
243
244 let mut assistance = DebuggingAssistance::new();
245
246 assistance.probable_causes = self.analyze_error_patterns(error_context).await?;
248 assistance.suggested_fixes = self.generate_suggested_fixes(error_context).await?;
249 assistance.debugging_steps = self.generate_debugging_steps(error_context).await?;
250 assistance.related_documentation = self.find_related_documentation(error_context).await?;
251
252 assistance.confidence_score = self.calculate_debugging_confidence(&assistance);
254
255 Ok(assistance)
256 }
257
258 pub fn get_performance_metrics(&self) -> AnalysisPerformanceMetrics {
260 AnalysisPerformanceMetrics {
261 total_analyses: self.performance_monitor.analysis_count,
262 average_analysis_time: self.performance_monitor.average_analysis_time(),
263 cache_hit_rate: self.performance_monitor.cache_hit_rate(),
264 cached_results: self.analysis_cache.len(),
265 }
266 }
267
268 async fn detect_code_patterns(
271 &self,
272 code: &str,
273 context: &ModelContext,
274 ) -> Result<Vec<DetectedPattern>> {
275 debug!("Detecting code patterns");
276
277 let mut patterns = Vec::new();
278
279 if code.contains("torch.cuda.empty_cache()") && context.model_type == ModelType::Production
281 {
282 patterns.push(DetectedPattern {
283 pattern_type: PatternType::AntiPattern,
284 name: "Frequent CUDA Cache Clearing".to_string(),
285 description: "Frequent CUDA cache clearing can hurt performance".to_string(),
286 severity: Severity::Medium,
287 confidence: 0.85,
288 recommendations: vec![
289 "Consider using gradient accumulation instead".to_string(),
290 "Review memory management strategy".to_string(),
291 ],
292 });
293 }
294
295 if code.contains("grad_norm") && code.contains("clip") {
297 patterns.push(DetectedPattern {
298 pattern_type: PatternType::GoodPattern,
299 name: "Gradient Clipping".to_string(),
300 description: "Proper gradient clipping implementation detected".to_string(),
301 severity: Severity::Info,
302 confidence: 0.9,
303 recommendations: vec!["Consider adaptive gradient clipping".to_string()],
304 });
305 }
306
307 if code.contains("detach()") && code.contains("requires_grad") {
309 patterns.push(DetectedPattern {
310 pattern_type: PatternType::OptimizationOpportunity,
311 name: "Gradient Computation Inefficiency".to_string(),
312 description: "Potential inefficient gradient computation detected".to_string(),
313 severity: Severity::Medium,
314 confidence: 0.75,
315 recommendations: vec![
316 "Consider using torch.no_grad() context".to_string(),
317 "Review gradient requirements".to_string(),
318 ],
319 });
320 }
321
322 Ok(patterns)
323 }
324
325 async fn perform_deep_analysis(
326 &self,
327 code: &str,
328 _context: &ModelContext,
329 ) -> Result<Vec<IdentifiedIssue>> {
330 debug!("Performing deep AI analysis");
331
332 let mut issues = Vec::new();
333
334 tokio::time::sleep(Duration::from_millis(100)).await;
336
337 if code.contains("log") && !code.contains("log1p") && code.contains("softmax") {
339 issues.push(IdentifiedIssue {
340 issue_type: IssueType::NumericalStability,
341 title: "Potential Numerical Instability in Log-Softmax".to_string(),
342 description: "Using log(softmax(x)) can cause numerical instability. Consider using log_softmax directly.".to_string(),
343 severity: Severity::High,
344 confidence: 0.88,
345 suggested_fix: "Replace log(softmax(x)) with log_softmax(x)".to_string(),
346 code_location: None, });
348 }
349
350 if code.contains("attention") && code.contains("matmul") && !code.contains("flash") {
352 issues.push(IdentifiedIssue {
353 issue_type: IssueType::Performance,
354 title: "Inefficient Attention Implementation".to_string(),
355 description:
356 "Standard attention implementation may be inefficient for large sequences."
357 .to_string(),
358 severity: Severity::Medium,
359 confidence: 0.75,
360 suggested_fix:
361 "Consider using Flash Attention or other optimized attention mechanisms"
362 .to_string(),
363 code_location: None,
364 });
365 }
366
367 if code.contains("accumulate") && !code.contains("zero_grad") {
369 issues.push(IdentifiedIssue {
370 issue_type: IssueType::MemoryLeak,
371 title: "Potential Gradient Accumulation Memory Leak".to_string(),
372 description: "Gradient accumulation without zero_grad() can cause memory leaks."
373 .to_string(),
374 severity: Severity::High,
375 confidence: 0.82,
376 suggested_fix: "Ensure optimizer.zero_grad() is called appropriately".to_string(),
377 code_location: None,
378 });
379 }
380
381 Ok(issues)
382 }
383
384 async fn generate_optimization_suggestions(
385 &self,
386 code: &str,
387 context: &ModelContext,
388 ) -> Result<Vec<OptimizationSuggestion>> {
389 debug!("Generating optimization suggestions");
390
391 let mut suggestions = Vec::new();
392
393 if context.model_type == ModelType::Training && !code.contains("autocast") {
395 suggestions.push(OptimizationSuggestion {
396 optimization_type: OptimizationType::MixedPrecision,
397 title: "Enable Mixed Precision Training".to_string(),
398 description: "Mixed precision training can significantly speed up training and reduce memory usage.".to_string(),
399 potential_speedup: 1.5,
400 memory_savings: 0.4,
401 implementation_effort: ImplementationEffort::Low,
402 confidence: 0.9,
403 code_example: Some("with torch.autocast(device_type='cuda', dtype=torch.float16):".to_string()),
404 });
405 }
406
407 if context.model_type == ModelType::Production && !code.contains("compile") {
409 suggestions.push(OptimizationSuggestion {
410 optimization_type: OptimizationType::ModelCompilation,
411 title: "Enable Model Compilation".to_string(),
412 description: "Model compilation can provide significant inference speedups."
413 .to_string(),
414 potential_speedup: 2.0,
415 memory_savings: 0.0,
416 implementation_effort: ImplementationEffort::Low,
417 confidence: 0.85,
418 code_example: Some("model = torch.compile(model)".to_string()),
419 });
420 }
421
422 if context.model_size > 1_000_000_000 && !code.contains("checkpoint") {
424 suggestions.push(OptimizationSuggestion {
425 optimization_type: OptimizationType::MemoryOptimization,
426 title: "Enable Gradient Checkpointing".to_string(),
427 description:
428 "Gradient checkpointing can significantly reduce memory usage for large models."
429 .to_string(),
430 potential_speedup: 0.8, memory_savings: 0.6,
432 implementation_effort: ImplementationEffort::Medium,
433 confidence: 0.88,
434 code_example: Some("torch.utils.checkpoint.checkpoint(layer, x)".to_string()),
435 });
436 }
437
438 Ok(suggestions)
439 }
440
441 async fn detect_vulnerabilities(
442 &self,
443 code: &str,
444 context: &ModelContext,
445 ) -> Result<Vec<SecurityIssue>> {
446 debug!("Detecting security vulnerabilities");
447
448 let mut vulnerabilities = Vec::new();
449
450 if code.contains("pickle.load") && !code.contains("safe_load") {
452 vulnerabilities.push(SecurityIssue {
453 vulnerability_type: VulnerabilityType::CodeExecution,
454 title: "Unsafe Pickle Loading".to_string(),
455 description:
456 "Loading pickle files can execute arbitrary code. Use safe alternatives."
457 .to_string(),
458 severity: Severity::Critical,
459 confidence: 0.95,
460 mitigation: "Use torch.load with weights_only=True or safetensors".to_string(),
461 cve_references: vec!["CWE-502".to_string()],
462 });
463 }
464
465 if code.contains("state_dict")
467 && code.contains("save")
468 && context.model_type == ModelType::Production
469 {
470 vulnerabilities.push(SecurityIssue {
471 vulnerability_type: VulnerabilityType::DataExposure,
472 title: "Potential Model Parameter Exposure".to_string(),
473 description: "Saving full model state may expose sensitive parameters.".to_string(),
474 severity: Severity::Medium,
475 confidence: 0.7,
476 mitigation: "Consider differential privacy or parameter encryption".to_string(),
477 cve_references: vec![],
478 });
479 }
480
481 if code.contains("input") && !code.contains("validate") && !code.contains("sanitize") {
483 vulnerabilities.push(SecurityIssue {
484 vulnerability_type: VulnerabilityType::InputValidation,
485 title: "Missing Input Validation".to_string(),
486 description: "Input validation is important for preventing adversarial attacks."
487 .to_string(),
488 severity: Severity::Medium,
489 confidence: 0.65,
490 mitigation: "Implement input validation and sanitization".to_string(),
491 cve_references: vec![],
492 });
493 }
494
495 Ok(vulnerabilities)
496 }
497
498 async fn predict_performance_characteristics(
499 &self,
500 code: &str,
501 context: &ModelContext,
502 ) -> Result<PerformancePredictions> {
503 debug!("Predicting performance characteristics");
504
505 tokio::time::sleep(Duration::from_millis(50)).await;
507
508 let mut predictions = PerformancePredictions::new();
509
510 predictions.estimated_memory_usage = self.estimate_memory_usage(code, context);
512 predictions.estimated_training_time = self.estimate_training_time(code, context);
513 predictions.estimated_inference_latency = self.estimate_inference_latency(code, context);
514 predictions.scaling_characteristics = self.predict_scaling_behavior(code, context);
515
516 predictions.predicted_bottlenecks = vec![
518 "Attention computation may become bottleneck for long sequences".to_string(),
519 "Memory bandwidth may limit performance for large batch sizes".to_string(),
520 ];
521
522 predictions.confidence_score = 0.75;
523
524 Ok(predictions)
525 }
526
527 async fn detect_fusion_opportunities(
528 &self,
529 operations: &[TensorOperation],
530 ) -> Result<Vec<FusionOpportunity>> {
531 let mut opportunities = Vec::new();
532
533 for window in operations.windows(2) {
535 if let [op1, op2] = window {
536 if matches!(op1.op_type, OperationType::MatMul)
537 && matches!(op2.op_type, OperationType::Add)
538 {
539 opportunities.push(FusionOpportunity {
540 operations: vec![op1.clone(), op2.clone()],
541 fusion_type: FusionType::GEMM,
542 estimated_speedup: 1.3,
543 description: "MatMul + Add can be fused into GEMM operation".to_string(),
544 });
545 }
546 }
547 }
548
549 for window in operations.windows(2) {
551 if let [op1, op2] = window {
552 if matches!(op1.op_type, OperationType::Linear)
553 && matches!(op2.op_type, OperationType::Activation)
554 {
555 opportunities.push(FusionOpportunity {
556 operations: vec![op1.clone(), op2.clone()],
557 fusion_type: FusionType::LinearActivation,
558 estimated_speedup: 1.2,
559 description: "Linear + Activation can be fused".to_string(),
560 });
561 }
562 }
563 }
564
565 Ok(opportunities)
566 }
567
568 async fn detect_memory_optimizations(
569 &self,
570 operations: &[TensorOperation],
571 ) -> Result<Vec<MemoryOptimization>> {
572 let mut optimizations = Vec::new();
573
574 for op in operations {
576 if op.can_be_inplace() && !op.is_inplace {
577 optimizations.push(MemoryOptimization {
578 operation: op.clone(),
579 optimization_type: MemoryOptimizationType::InPlace,
580 memory_savings: op.output_size_bytes,
581 description: format!("Operation {} can be performed in-place", op.name),
582 });
583 }
584 }
585
586 let mut tensor_usage = HashMap::new();
588 for op in operations {
589 for input in &op.inputs {
590 *tensor_usage.entry(input.clone()).or_insert(0) += 1;
591 }
592 }
593
594 for (tensor, usage_count) in tensor_usage {
595 if usage_count == 1 {
596 optimizations.push(MemoryOptimization {
597 operation: TensorOperation::default(),
598 optimization_type: MemoryOptimizationType::TensorReuse,
599 memory_savings: 0, description: format!("Tensor {} can be reused", tensor),
601 });
602 }
603 }
604
605 Ok(optimizations)
606 }
607
608 async fn detect_parallelization_opportunities(
609 &self,
610 operations: &[TensorOperation],
611 ) -> Result<Vec<ParallelizationOpportunity>> {
612 let mut opportunities = Vec::new();
613
614 for (i, op1) in operations.iter().enumerate() {
616 for op2 in operations.iter().skip(i + 1) {
617 if self.operations_are_independent(op1, op2) {
618 opportunities.push(ParallelizationOpportunity {
619 operations: vec![op1.clone(), op2.clone()],
620 parallelization_type: ParallelizationType::DataParallel,
621 estimated_speedup: 1.8,
622 description: "Operations can run in parallel".to_string(),
623 });
624 }
625 }
626 }
627
628 Ok(opportunities)
629 }
630
631 async fn detect_redundant_operations(
632 &self,
633 operations: &[TensorOperation],
634 ) -> Result<Vec<RedundantOperation>> {
635 let mut redundant = Vec::new();
636
637 for (i, op1) in operations.iter().enumerate() {
639 for (_j, op2) in operations.iter().enumerate().skip(i + 1) {
640 if self.operations_are_equivalent(op1, op2) {
641 redundant.push(RedundantOperation {
642 original_operation: op1.clone(),
643 redundant_operation: op2.clone(),
644 redundancy_type: RedundancyType::Duplicate,
645 description: "Operations produce identical results".to_string(),
646 });
647 }
648 }
649 }
650
651 Ok(redundant)
652 }
653
654 fn operations_are_independent(&self, op1: &TensorOperation, op2: &TensorOperation) -> bool {
657 for input1 in &op1.inputs {
659 for output2 in &op2.outputs {
660 if input1 == output2 {
661 return false;
662 }
663 }
664 }
665 for input2 in &op2.inputs {
666 for output1 in &op1.outputs {
667 if input2 == output1 {
668 return false;
669 }
670 }
671 }
672 true
673 }
674
675 fn operations_are_equivalent(&self, op1: &TensorOperation, op2: &TensorOperation) -> bool {
676 op1.op_type == op2.op_type && op1.inputs == op2.inputs && op1.parameters == op2.parameters
677 }
678
679 fn compute_code_hash(&self, code: &str) -> String {
680 use std::collections::hash_map::DefaultHasher;
681 use std::hash::{Hash, Hasher};
682
683 let mut hasher = DefaultHasher::new();
684 code.hash(&mut hasher);
685 format!("{:x}", hasher.finish())
686 }
687
688 fn get_cached_analysis(&self, code_hash: &str) -> Option<&CachedAnalysis> {
689 self.analysis_cache.get(code_hash).and_then(|cached| {
690 let age = std::time::SystemTime::now()
691 .duration_since(cached.timestamp)
692 .unwrap_or_default();
693
694 if age.as_secs() < self.config.cache_expiration_hours * 3600 {
695 Some(cached)
696 } else {
697 None
698 }
699 })
700 }
701
702 fn cache_analysis(&mut self, code_hash: String, result: &CodeAnalysisResult) {
703 self.analysis_cache.insert(
704 code_hash.clone(),
705 CachedAnalysis {
706 result: result.clone(),
707 timestamp: std::time::SystemTime::now(),
708 code_hash,
709 },
710 );
711 }
712
713 fn calculate_quality_score(&self, result: &CodeAnalysisResult) -> f64 {
714 let mut score: f64 = 100.0;
715
716 for issue in &result.identified_issues {
718 match issue.severity {
719 Severity::Critical => score -= 20.0,
720 Severity::High => score -= 10.0,
721 Severity::Medium => score -= 5.0,
722 Severity::Low => score -= 2.0,
723 Severity::Info => score -= 0.0,
724 }
725 }
726
727 for vulnerability in &result.security_issues {
729 match vulnerability.severity {
730 Severity::Critical => score -= 25.0,
731 Severity::High => score -= 15.0,
732 Severity::Medium => score -= 8.0,
733 Severity::Low => score -= 3.0,
734 Severity::Info => score -= 0.0,
735 }
736 }
737
738 for pattern in &result.detected_patterns {
740 if pattern.pattern_type == PatternType::GoodPattern {
741 score += 2.0;
742 }
743 }
744
745 score.max(0.0).min(100.0)
746 }
747
748 fn calculate_confidence_score(&self, result: &CodeAnalysisResult) -> f64 {
749 let mut total_confidence = 0.0;
750 let mut count = 0;
751
752 for issue in &result.identified_issues {
753 total_confidence += issue.confidence;
754 count += 1;
755 }
756
757 for pattern in &result.detected_patterns {
758 total_confidence += pattern.confidence;
759 count += 1;
760 }
761
762 if count > 0 {
763 total_confidence / count as f64
764 } else {
765 1.0
766 }
767 }
768
769 fn estimate_memory_usage(&self, code: &str, context: &ModelContext) -> f64 {
770 let base_memory = context.model_size as f64 * 4.0; let mut multiplier = 1.0;
774 if code.contains("gradient_accumulation") {
775 multiplier += 0.5;
776 }
777 if code.contains("mixed_precision") {
778 multiplier *= 0.7;
779 }
780
781 base_memory * multiplier / 1_000_000.0 }
783
784 fn estimate_training_time(&self, code: &str, context: &ModelContext) -> f64 {
785 let base_time = (context.model_size as f64).log10() * 10.0;
787
788 let mut multiplier = 1.0;
789 if code.contains("mixed_precision") {
790 multiplier *= 0.6;
791 }
792 if code.contains("gradient_checkpointing") {
793 multiplier *= 1.3;
794 }
795
796 base_time * multiplier
797 }
798
799 fn estimate_inference_latency(&self, code: &str, context: &ModelContext) -> f64 {
800 let base_latency = (context.model_size as f64).log10() * 5.0;
802
803 let mut multiplier = 1.0;
804 if code.contains("compile") {
805 multiplier *= 0.5;
806 }
807 if code.contains("quantization") {
808 multiplier *= 0.7;
809 }
810
811 base_latency * multiplier
812 }
813
814 fn predict_scaling_behavior(
815 &self,
816 _code: &str,
817 context: &ModelContext,
818 ) -> ScalingCharacteristics {
819 ScalingCharacteristics {
820 batch_size_scaling: if context.model_size > 1_000_000_000 {
821 ScalingBehavior::Sublinear
822 } else {
823 ScalingBehavior::Linear
824 },
825 sequence_length_scaling: ScalingBehavior::Quadratic, model_size_scaling: ScalingBehavior::Linear,
827 memory_scaling: ScalingBehavior::Linear,
828 }
829 }
830
831 fn estimate_optimization_speedup(&self, report: &TensorOptimizationReport) -> f64 {
832 let mut speedup = 1.0;
833
834 for fusion in &report.fusion_opportunities {
835 speedup *= fusion.estimated_speedup;
836 }
837
838 for parallel in &report.parallelization_opportunities {
839 speedup *= parallel.estimated_speedup;
840 }
841
842 speedup.min(10.0) }
844
845 fn estimate_memory_savings(&self, report: &TensorOptimizationReport) -> f64 {
846 let total_savings: u64 =
847 report.memory_optimizations.iter().map(|opt| opt.memory_savings).sum();
848
849 total_savings as f64 / 1_000_000.0 }
851
852 async fn analyze_error_patterns(
853 &self,
854 error_context: &ErrorContext,
855 ) -> Result<Vec<ProbableCause>> {
856 let mut causes = Vec::new();
857
858 match error_context.error_type.as_str() {
859 "OutOfMemoryError" => {
860 causes.push(ProbableCause {
861 cause: "Batch size too large".to_string(),
862 probability: 0.8,
863 evidence: vec!["GPU memory limit exceeded".to_string()],
864 });
865 causes.push(ProbableCause {
866 cause: "Model too large for available memory".to_string(),
867 probability: 0.6,
868 evidence: vec!["Model parameter count".to_string()],
869 });
870 },
871 "GradientExplosion" => {
872 causes.push(ProbableCause {
873 cause: "Learning rate too high".to_string(),
874 probability: 0.7,
875 evidence: vec!["Gradient norm increasing rapidly".to_string()],
876 });
877 },
878 _ => {
879 causes.push(ProbableCause {
880 cause: "Unknown error pattern".to_string(),
881 probability: 0.3,
882 evidence: vec![],
883 });
884 },
885 }
886
887 Ok(causes)
888 }
889
890 async fn generate_suggested_fixes(
891 &self,
892 error_context: &ErrorContext,
893 ) -> Result<Vec<SuggestedFix>> {
894 let mut fixes = Vec::new();
895
896 match error_context.error_type.as_str() {
897 "OutOfMemoryError" => {
898 fixes.push(SuggestedFix {
899 description: "Reduce batch size".to_string(),
900 implementation: "batch_size = batch_size // 2".to_string(),
901 confidence: 0.9,
902 estimated_impact: "Should free ~50% of memory".to_string(),
903 });
904 fixes.push(SuggestedFix {
905 description: "Enable gradient checkpointing".to_string(),
906 implementation: "model.gradient_checkpointing_enable()".to_string(),
907 confidence: 0.8,
908 estimated_impact: "Reduces memory by ~40% with 10-20% speed penalty"
909 .to_string(),
910 });
911 },
912 "GradientExplosion" => {
913 fixes.push(SuggestedFix {
914 description: "Add gradient clipping".to_string(),
915 implementation:
916 "torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)"
917 .to_string(),
918 confidence: 0.95,
919 estimated_impact: "Prevents gradient explosion".to_string(),
920 });
921 },
922 _ => {},
923 }
924
925 Ok(fixes)
926 }
927
928 async fn generate_debugging_steps(
929 &self,
930 error_context: &ErrorContext,
931 ) -> Result<Vec<DebuggingStep>> {
932 let mut steps = Vec::new();
933
934 steps.push(DebuggingStep {
935 step_number: 1,
936 description: "Check system resources".to_string(),
937 command: Some("nvidia-smi".to_string()),
938 expected_output: "GPU memory usage and availability".to_string(),
939 });
940
941 steps.push(DebuggingStep {
942 step_number: 2,
943 description: "Verify model configuration".to_string(),
944 command: Some("print(model)".to_string()),
945 expected_output: "Model architecture and parameter count".to_string(),
946 });
947
948 if error_context.error_type.as_str() == "OutOfMemoryError" {
949 steps.push(DebuggingStep {
950 step_number: 3,
951 description: "Check tensor shapes and batch size".to_string(),
952 command: Some(
953 "print(f'Batch size: {batch_size}, Input shape: {input.shape}')".to_string(),
954 ),
955 expected_output: "Current batch size and input dimensions".to_string(),
956 });
957 }
958
959 Ok(steps)
960 }
961
962 async fn find_related_documentation(
963 &self,
964 error_context: &ErrorContext,
965 ) -> Result<Vec<DocumentationReference>> {
966 let mut references = Vec::new();
967
968 match error_context.error_type.as_str() {
969 "OutOfMemoryError" => {
970 references.push(DocumentationReference {
971 title: "Memory Management Best Practices".to_string(),
972 url: "https://docs.trustformers.ai/memory-management".to_string(),
973 relevance_score: 0.95,
974 });
975 references.push(DocumentationReference {
976 title: "Gradient Checkpointing Guide".to_string(),
977 url: "https://docs.trustformers.ai/gradient-checkpointing".to_string(),
978 relevance_score: 0.8,
979 });
980 },
981 "GradientExplosion" => {
982 references.push(DocumentationReference {
983 title: "Training Stability Guide".to_string(),
984 url: "https://docs.trustformers.ai/training-stability".to_string(),
985 relevance_score: 0.9,
986 });
987 },
988 _ => {},
989 }
990
991 Ok(references)
992 }
993
994 fn calculate_debugging_confidence(&self, assistance: &DebuggingAssistance) -> f64 {
995 let avg_cause_probability =
996 assistance.probable_causes.iter().map(|cause| cause.probability).sum::<f64>()
997 / assistance.probable_causes.len().max(1) as f64;
998
999 let avg_fix_confidence =
1000 assistance.suggested_fixes.iter().map(|fix| fix.confidence).sum::<f64>()
1001 / assistance.suggested_fixes.len().max(1) as f64;
1002
1003 (avg_cause_probability + avg_fix_confidence) / 2.0
1004 }
1005}
1006
1007#[derive(Debug)]
1011struct ModelPatternDatabase {
1012 patterns: HashMap<String, PatternDefinition>,
1013}
1014
1015impl ModelPatternDatabase {
1016 fn new() -> Self {
1017 let mut patterns = HashMap::new();
1018
1019 patterns.insert(
1021 "gradient_clipping".to_string(),
1022 PatternDefinition {
1023 name: "Gradient Clipping".to_string(),
1024 pattern_type: PatternType::GoodPattern,
1025 keywords: vec![
1026 "clip_grad_norm".to_string(),
1027 "gradient".to_string(),
1028 "clip".to_string(),
1029 ],
1030 severity: Severity::Info,
1031 description: "Proper gradient clipping prevents gradient explosion".to_string(),
1032 },
1033 );
1034
1035 Self { patterns }
1036 }
1037}
1038
1039#[derive(Debug, Clone)]
1040struct PatternDefinition {
1041 name: String,
1042 pattern_type: PatternType,
1043 keywords: Vec<String>,
1044 severity: Severity,
1045 description: String,
1046}
1047
1048#[derive(Debug, Clone)]
1050pub struct ModelContext {
1051 pub model_type: ModelType,
1052 pub model_size: u64, pub framework: String,
1054 pub target_hardware: String,
1055 pub training_stage: TrainingStage,
1056}
1057
1058#[derive(Debug, Clone, PartialEq)]
1059pub enum ModelType {
1060 Training,
1061 Inference,
1062 Production,
1063 Development,
1064}
1065
1066#[derive(Debug, Clone)]
1067pub enum TrainingStage {
1068 Training,
1069 Development,
1070 Pretraining,
1071 Finetuning,
1072 Evaluation,
1073 Inference,
1074}
1075
1076#[derive(Debug, Clone, Serialize, Deserialize)]
1078pub struct CodeAnalysisResult {
1079 pub quality_score: f64,
1080 pub detected_patterns: Vec<DetectedPattern>,
1081 pub identified_issues: Vec<IdentifiedIssue>,
1082 pub optimization_suggestions: Vec<OptimizationSuggestion>,
1083 pub security_issues: Vec<SecurityIssue>,
1084 pub performance_predictions: PerformancePredictions,
1085 pub analysis_metadata: AnalysisMetadata,
1086}
1087
1088impl CodeAnalysisResult {
1089 fn new() -> Self {
1090 Self {
1091 quality_score: 0.0,
1092 detected_patterns: Vec::new(),
1093 identified_issues: Vec::new(),
1094 optimization_suggestions: Vec::new(),
1095 security_issues: Vec::new(),
1096 performance_predictions: PerformancePredictions::new(),
1097 analysis_metadata: AnalysisMetadata::default(),
1098 }
1099 }
1100}
1101
1102#[derive(Debug, Clone, Serialize, Deserialize)]
1103pub struct DetectedPattern {
1104 pub pattern_type: PatternType,
1105 pub name: String,
1106 pub description: String,
1107 pub severity: Severity,
1108 pub confidence: f64,
1109 pub recommendations: Vec<String>,
1110}
1111
1112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1113pub enum PatternType {
1114 GoodPattern,
1115 AntiPattern,
1116 OptimizationOpportunity,
1117 SecurityConcern,
1118}
1119
1120#[derive(Debug, Clone, Serialize, Deserialize)]
1121pub struct IdentifiedIssue {
1122 pub issue_type: IssueType,
1123 pub title: String,
1124 pub description: String,
1125 pub severity: Severity,
1126 pub confidence: f64,
1127 pub suggested_fix: String,
1128 pub code_location: Option<CodeLocation>,
1129}
1130
1131#[derive(Debug, Clone, Serialize, Deserialize)]
1132pub enum IssueType {
1133 NumericalStability,
1134 Performance,
1135 MemoryLeak,
1136 LogicError,
1137 TypeMismatch,
1138 ResourceLeak,
1139}
1140
1141#[derive(Debug, Clone, Serialize, Deserialize)]
1142pub struct CodeLocation {
1143 pub file: String,
1144 pub line: u32,
1145 pub column: u32,
1146}
1147
1148#[derive(Debug, Clone, Serialize, Deserialize)]
1149pub struct OptimizationSuggestion {
1150 pub optimization_type: OptimizationType,
1151 pub title: String,
1152 pub description: String,
1153 pub potential_speedup: f64,
1154 pub memory_savings: f64,
1155 pub implementation_effort: ImplementationEffort,
1156 pub confidence: f64,
1157 pub code_example: Option<String>,
1158}
1159
1160#[derive(Debug, Clone, Serialize, Deserialize)]
1161pub enum OptimizationType {
1162 MixedPrecision,
1163 ModelCompilation,
1164 MemoryOptimization,
1165 ComputationOptimization,
1166 IOOptimization,
1167 ParallelizationOptimization,
1168}
1169
1170#[derive(Debug, Clone, Serialize, Deserialize)]
1171pub enum ImplementationEffort {
1172 Low,
1173 Medium,
1174 High,
1175}
1176
1177#[derive(Debug, Clone, Serialize, Deserialize)]
1178pub struct SecurityIssue {
1179 pub vulnerability_type: VulnerabilityType,
1180 pub title: String,
1181 pub description: String,
1182 pub severity: Severity,
1183 pub confidence: f64,
1184 pub mitigation: String,
1185 pub cve_references: Vec<String>,
1186}
1187
1188#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1189pub enum VulnerabilityType {
1190 CodeExecution,
1191 DataExposure,
1192 InputValidation,
1193 AuthenticationBypass,
1194 PrivilegeEscalation,
1195}
1196
1197#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1198pub enum Severity {
1199 Critical,
1200 High,
1201 Medium,
1202 Low,
1203 Info,
1204}
1205
1206#[derive(Debug, Clone, Serialize, Deserialize)]
1207pub struct PerformancePredictions {
1208 pub estimated_memory_usage: f64, pub estimated_training_time: f64, pub estimated_inference_latency: f64, pub scaling_characteristics: ScalingCharacteristics,
1212 pub predicted_bottlenecks: Vec<String>,
1213 pub confidence_score: f64,
1214}
1215
1216impl PerformancePredictions {
1217 fn new() -> Self {
1218 Self {
1219 estimated_memory_usage: 0.0,
1220 estimated_training_time: 0.0,
1221 estimated_inference_latency: 0.0,
1222 scaling_characteristics: ScalingCharacteristics::default(),
1223 predicted_bottlenecks: Vec::new(),
1224 confidence_score: 0.0,
1225 }
1226 }
1227}
1228
1229#[derive(Debug, Clone, Serialize, Deserialize)]
1230pub struct ScalingCharacteristics {
1231 pub batch_size_scaling: ScalingBehavior,
1232 pub sequence_length_scaling: ScalingBehavior,
1233 pub model_size_scaling: ScalingBehavior,
1234 pub memory_scaling: ScalingBehavior,
1235}
1236
1237impl Default for ScalingCharacteristics {
1238 fn default() -> Self {
1239 Self {
1240 batch_size_scaling: ScalingBehavior::Linear,
1241 sequence_length_scaling: ScalingBehavior::Linear,
1242 model_size_scaling: ScalingBehavior::Linear,
1243 memory_scaling: ScalingBehavior::Linear,
1244 }
1245 }
1246}
1247
1248#[derive(Debug, Clone, Serialize, Deserialize)]
1249pub enum ScalingBehavior {
1250 Constant,
1251 Linear,
1252 Quadratic,
1253 Exponential,
1254 Sublinear,
1255}
1256
1257#[derive(Debug, Clone, Serialize, Deserialize)]
1258pub struct AnalysisMetadata {
1259 pub analysis_duration: Duration,
1260 pub confidence_score: f64,
1261 pub analyzer_version: String,
1262 pub timestamp: std::time::SystemTime,
1263}
1264
1265impl Default for AnalysisMetadata {
1266 fn default() -> Self {
1267 Self {
1268 analysis_duration: Duration::from_secs(0),
1269 confidence_score: 0.0,
1270 analyzer_version: "1.0.0".to_string(),
1271 timestamp: std::time::SystemTime::now(),
1272 }
1273 }
1274}
1275
1276#[derive(Debug, Clone)]
1279pub struct TensorOperation {
1280 pub name: String,
1281 pub op_type: OperationType,
1282 pub inputs: Vec<String>,
1283 pub outputs: Vec<String>,
1284 pub parameters: HashMap<String, String>,
1285 pub output_size_bytes: u64,
1286 pub is_inplace: bool,
1287}
1288
1289impl Default for TensorOperation {
1290 fn default() -> Self {
1291 Self {
1292 name: String::new(),
1293 op_type: OperationType::Unknown,
1294 inputs: Vec::new(),
1295 outputs: Vec::new(),
1296 parameters: HashMap::new(),
1297 output_size_bytes: 0,
1298 is_inplace: false,
1299 }
1300 }
1301}
1302
1303impl TensorOperation {
1304 fn can_be_inplace(&self) -> bool {
1305 matches!(
1306 self.op_type,
1307 OperationType::Add | OperationType::Mul | OperationType::Activation
1308 )
1309 }
1310}
1311
1312#[derive(Debug, Clone, PartialEq)]
1313pub enum OperationType {
1314 MatMul,
1315 Add,
1316 Mul,
1317 Conv2D,
1318 Linear,
1319 Activation,
1320 Pooling,
1321 BatchNorm,
1322 LayerNorm,
1323 Attention,
1324 Unknown,
1325}
1326
1327#[derive(Debug, Clone)]
1328pub struct TensorOptimizationReport {
1329 pub fusion_opportunities: Vec<FusionOpportunity>,
1330 pub memory_optimizations: Vec<MemoryOptimization>,
1331 pub parallelization_opportunities: Vec<ParallelizationOpportunity>,
1332 pub redundant_operations: Vec<RedundantOperation>,
1333 pub estimated_speedup: f64,
1334 pub estimated_memory_savings: f64,
1335}
1336
1337impl TensorOptimizationReport {
1338 fn new() -> Self {
1339 Self {
1340 fusion_opportunities: Vec::new(),
1341 memory_optimizations: Vec::new(),
1342 parallelization_opportunities: Vec::new(),
1343 redundant_operations: Vec::new(),
1344 estimated_speedup: 1.0,
1345 estimated_memory_savings: 0.0,
1346 }
1347 }
1348}
1349
1350#[derive(Debug, Clone)]
1351pub struct FusionOpportunity {
1352 pub operations: Vec<TensorOperation>,
1353 pub fusion_type: FusionType,
1354 pub estimated_speedup: f64,
1355 pub description: String,
1356}
1357
1358#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1359pub enum FusionType {
1360 GEMM,
1361 LinearActivation,
1362 ConvBatchNorm,
1363 AttentionQKV,
1364}
1365
1366#[derive(Debug, Clone)]
1367pub struct MemoryOptimization {
1368 pub operation: TensorOperation,
1369 pub optimization_type: MemoryOptimizationType,
1370 pub memory_savings: u64,
1371 pub description: String,
1372}
1373
1374#[derive(Debug, Clone)]
1375pub enum MemoryOptimizationType {
1376 InPlace,
1377 TensorReuse,
1378 MemoryPool,
1379 GradientCheckpointing,
1380}
1381
1382#[derive(Debug, Clone)]
1383pub struct ParallelizationOpportunity {
1384 pub operations: Vec<TensorOperation>,
1385 pub parallelization_type: ParallelizationType,
1386 pub estimated_speedup: f64,
1387 pub description: String,
1388}
1389
1390#[derive(Debug, Clone)]
1391pub enum ParallelizationType {
1392 DataParallel,
1393 ModelParallel,
1394 PipelineParallel,
1395 TensorParallel,
1396}
1397
1398#[derive(Debug, Clone)]
1399pub struct RedundantOperation {
1400 pub original_operation: TensorOperation,
1401 pub redundant_operation: TensorOperation,
1402 pub redundancy_type: RedundancyType,
1403 pub description: String,
1404}
1405
1406#[derive(Debug, Clone)]
1407pub enum RedundancyType {
1408 Duplicate,
1409 Subsumed,
1410 Unnecessary,
1411}
1412
1413#[derive(Debug, Clone)]
1416pub struct ErrorContext {
1417 pub error_type: String,
1418 pub error_message: String,
1419 pub stack_trace: Option<String>,
1420 pub system_info: SystemInfo,
1421 pub model_info: Option<ModelContext>,
1422}
1423
1424#[derive(Debug, Clone)]
1425pub struct SystemInfo {
1426 pub gpu_memory_total: u64,
1427 pub gpu_memory_used: u64,
1428 pub cpu_count: u32,
1429 pub ram_total: u64,
1430 pub ram_used: u64,
1431}
1432
1433#[derive(Debug, Clone)]
1434pub struct DebuggingAssistance {
1435 pub probable_causes: Vec<ProbableCause>,
1436 pub suggested_fixes: Vec<SuggestedFix>,
1437 pub debugging_steps: Vec<DebuggingStep>,
1438 pub related_documentation: Vec<DocumentationReference>,
1439 pub confidence_score: f64,
1440}
1441
1442impl DebuggingAssistance {
1443 fn new() -> Self {
1444 Self {
1445 probable_causes: Vec::new(),
1446 suggested_fixes: Vec::new(),
1447 debugging_steps: Vec::new(),
1448 related_documentation: Vec::new(),
1449 confidence_score: 0.0,
1450 }
1451 }
1452}
1453
1454#[derive(Debug, Clone)]
1455pub struct ProbableCause {
1456 pub cause: String,
1457 pub probability: f64,
1458 pub evidence: Vec<String>,
1459}
1460
1461#[derive(Debug, Clone)]
1462pub struct SuggestedFix {
1463 pub description: String,
1464 pub implementation: String,
1465 pub confidence: f64,
1466 pub estimated_impact: String,
1467}
1468
1469#[derive(Debug, Clone)]
1470pub struct DebuggingStep {
1471 pub step_number: u32,
1472 pub description: String,
1473 pub command: Option<String>,
1474 pub expected_output: String,
1475}
1476
1477#[derive(Debug, Clone)]
1478pub struct DocumentationReference {
1479 pub title: String,
1480 pub url: String,
1481 pub relevance_score: f64,
1482}
1483
1484#[derive(Debug, Serialize, Deserialize)]
1487pub struct AnalysisPerformanceMetrics {
1488 pub total_analyses: u64,
1489 pub average_analysis_time: Duration,
1490 pub cache_hit_rate: f64,
1491 pub cached_results: usize,
1492}
1493
1494#[macro_export]
1496macro_rules! ai_analyze {
1497 ($code:expr, $context:expr) => {{
1498 let mut analyzer = AICodeAnalyzer::new(AIAnalysisConfig::default());
1499 analyzer.analyze_model_code($code, $context).await
1500 }};
1501}
1502
1503#[path = "ai_code_analyzer_tests.rs"]
1504mod ai_code_analyzer_tests;
1505
1506#[cfg(test)]
1507mod tests {
1508 use super::*;
1509
1510 #[tokio::test]
1511 async fn test_ai_code_analyzer_creation() {
1512 let analyzer = AICodeAnalyzer::new(AIAnalysisConfig::default());
1513 assert!(analyzer.config.enable_deep_analysis);
1514 }
1515
1516 #[tokio::test]
1517 async fn test_pattern_detection() {
1518 let mut analyzer = AICodeAnalyzer::new(AIAnalysisConfig::default());
1519
1520 let code = r#"
1521 import torch
1522
1523 def train_step(model, data):
1524 torch.cuda.empty_cache() # Should trigger anti-pattern
1525 grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) # Good pattern
1526 return grad_norm
1527 "#;
1528
1529 let context = ModelContext {
1530 model_type: ModelType::Production,
1531 model_size: 1_000_000,
1532 framework: "PyTorch".to_string(),
1533 target_hardware: "CUDA".to_string(),
1534 training_stage: TrainingStage::Training,
1535 };
1536
1537 let result = analyzer
1538 .analyze_model_code(code, context)
1539 .await
1540 .expect("async operation failed");
1541 assert!(!result.detected_patterns.is_empty());
1542 }
1543
1544 #[tokio::test]
1545 async fn test_security_vulnerability_detection() {
1546 let mut analyzer = AICodeAnalyzer::new(AIAnalysisConfig::default());
1547
1548 let code = r#"
1549 import pickle
1550
1551 def load_model(path):
1552 with open(path, 'rb') as f:
1553 model = pickle.load(f) # Should trigger security warning
1554 return model
1555 "#;
1556
1557 let context = ModelContext {
1558 model_type: ModelType::Production,
1559 model_size: 1_000_000,
1560 framework: "PyTorch".to_string(),
1561 target_hardware: "CUDA".to_string(),
1562 training_stage: TrainingStage::Inference,
1563 };
1564
1565 let result = analyzer
1566 .analyze_model_code(code, context)
1567 .await
1568 .expect("async operation failed");
1569 assert!(!result.security_issues.is_empty());
1570 assert_eq!(
1571 result.security_issues[0].vulnerability_type,
1572 VulnerabilityType::CodeExecution
1573 );
1574 }
1575
1576 #[tokio::test]
1577 async fn test_tensor_operation_analysis() {
1578 let analyzer = AICodeAnalyzer::new(AIAnalysisConfig::default());
1579
1580 let operations = vec![
1581 TensorOperation {
1582 name: "matmul1".to_string(),
1583 op_type: OperationType::MatMul,
1584 inputs: vec!["a".to_string(), "b".to_string()],
1585 outputs: vec!["c".to_string()],
1586 parameters: HashMap::new(),
1587 output_size_bytes: 1024,
1588 is_inplace: false,
1589 },
1590 TensorOperation {
1591 name: "add1".to_string(),
1592 op_type: OperationType::Add,
1593 inputs: vec!["c".to_string(), "bias".to_string()],
1594 outputs: vec!["d".to_string()],
1595 parameters: HashMap::new(),
1596 output_size_bytes: 1024,
1597 is_inplace: false,
1598 },
1599 ];
1600
1601 let report = analyzer
1602 .analyze_tensor_operations(&operations)
1603 .await
1604 .expect("tensor operation failed");
1605 assert!(!report.fusion_opportunities.is_empty());
1606 assert_eq!(report.fusion_opportunities[0].fusion_type, FusionType::GEMM);
1607 }
1608
1609 #[tokio::test]
1610 async fn test_performance_metrics() {
1611 let mut analyzer = AICodeAnalyzer::new(AIAnalysisConfig::default());
1612
1613 let code = "print('hello')";
1615 let context = ModelContext {
1616 model_type: ModelType::Development,
1617 model_size: 1000,
1618 framework: "PyTorch".to_string(),
1619 target_hardware: "CPU".to_string(),
1620 training_stage: TrainingStage::Development,
1621 };
1622
1623 analyzer
1624 .analyze_model_code(code, context.clone())
1625 .await
1626 .expect("async operation failed");
1627 analyzer
1628 .analyze_model_code(code, context)
1629 .await
1630 .expect("async operation failed"); let metrics = analyzer.get_performance_metrics();
1633 assert_eq!(metrics.total_analyses, 2);
1634 assert!(metrics.cache_hit_rate > 0.0);
1635 }
1636
1637 #[tokio::test]
1638 async fn test_debugging_assistance() {
1639 let analyzer = AICodeAnalyzer::new(AIAnalysisConfig::default());
1640
1641 let error_context = ErrorContext {
1642 error_type: "OutOfMemoryError".to_string(),
1643 error_message: "CUDA out of memory".to_string(),
1644 stack_trace: None,
1645 system_info: SystemInfo {
1646 gpu_memory_total: 8_000_000_000,
1647 gpu_memory_used: 7_500_000_000,
1648 cpu_count: 8,
1649 ram_total: 32_000_000_000,
1650 ram_used: 16_000_000_000,
1651 },
1652 model_info: None,
1653 };
1654
1655 let assistance = analyzer
1656 .automated_debugging_assistance(&error_context)
1657 .await
1658 .expect("async operation failed");
1659 assert!(!assistance.probable_causes.is_empty());
1660 assert!(!assistance.suggested_fixes.is_empty());
1661 assert!(assistance.confidence_score > 0.0);
1662 }
1663}