ringkernel_procint/analytics/
pattern_analysis.rs1use crate::models::{GpuPatternMatch, PatternSeverity, PatternType};
6use std::collections::HashMap;
7
8#[derive(Debug, Default)]
10pub struct PatternAggregator {
11 pub type_counts: HashMap<PatternType, u64>,
13 pub severity_counts: HashMap<PatternSeverity, u64>,
15 pub recent_patterns: Vec<PatternSummary>,
17 max_recent: usize,
19 pub total_detected: u64,
21}
22
23impl PatternAggregator {
24 pub fn new() -> Self {
26 Self {
27 max_recent: 100,
28 ..Default::default()
29 }
30 }
31
32 pub fn with_max_recent(mut self, max: usize) -> Self {
34 self.max_recent = max;
35 self
36 }
37
38 pub fn add_patterns(&mut self, patterns: &[GpuPatternMatch]) {
40 for pattern in patterns {
41 let pattern_type = pattern.get_pattern_type();
42 let severity = pattern.get_severity();
43
44 *self.type_counts.entry(pattern_type).or_insert(0) += 1;
45 *self.severity_counts.entry(severity).or_insert(0) += 1;
46 self.total_detected += 1;
47
48 let summary = PatternSummary {
50 pattern_type,
51 severity,
52 confidence: pattern.confidence,
53 frequency: pattern.frequency,
54 activities: pattern.activities().to_vec(),
55 impact: pattern.impact,
56 };
57 self.recent_patterns.push(summary);
58
59 if self.recent_patterns.len() > self.max_recent {
61 self.recent_patterns.remove(0);
62 }
63 }
64 }
65
66 pub fn count_by_type(&self, pattern_type: PatternType) -> u64 {
68 *self.type_counts.get(&pattern_type).unwrap_or(&0)
69 }
70
71 pub fn count_by_severity(&self, severity: PatternSeverity) -> u64 {
73 *self.severity_counts.get(&severity).unwrap_or(&0)
74 }
75
76 pub fn top_patterns(&self, n: usize) -> Vec<&PatternSummary> {
78 let mut sorted: Vec<_> = self.recent_patterns.iter().collect();
79 sorted.sort_by_key(|a| std::cmp::Reverse(a.frequency));
80 sorted.truncate(n);
81 sorted
82 }
83
84 pub fn critical_patterns(&self) -> Vec<&PatternSummary> {
86 self.recent_patterns
87 .iter()
88 .filter(|p| p.severity == PatternSeverity::Critical)
89 .collect()
90 }
91
92 pub fn distribution(&self) -> PatternDistribution {
94 PatternDistribution {
95 bottleneck: self.count_by_type(PatternType::Bottleneck),
96 loop_count: self.count_by_type(PatternType::Loop),
97 rework: self.count_by_type(PatternType::Rework),
98 long_running: self.count_by_type(PatternType::LongRunning),
99 circular: self.count_by_type(PatternType::Circular),
100 other: self.total_detected
101 - self.count_by_type(PatternType::Bottleneck)
102 - self.count_by_type(PatternType::Loop)
103 - self.count_by_type(PatternType::Rework)
104 - self.count_by_type(PatternType::LongRunning)
105 - self.count_by_type(PatternType::Circular),
106 }
107 }
108
109 pub fn reset(&mut self) {
111 self.type_counts.clear();
112 self.severity_counts.clear();
113 self.recent_patterns.clear();
114 self.total_detected = 0;
115 }
116}
117
118#[derive(Debug, Clone)]
120pub struct PatternSummary {
121 pub pattern_type: PatternType,
123 pub severity: PatternSeverity,
125 pub confidence: f32,
127 pub frequency: u32,
129 pub activities: Vec<u32>,
131 pub impact: f32,
133}
134
135#[derive(Debug, Clone, Default)]
137pub struct PatternDistribution {
138 pub bottleneck: u64,
140 pub loop_count: u64,
142 pub rework: u64,
144 pub long_running: u64,
146 pub circular: u64,
148 pub other: u64,
150}
151
152impl PatternDistribution {
153 pub fn total(&self) -> u64 {
155 self.bottleneck
156 + self.loop_count
157 + self.rework
158 + self.long_running
159 + self.circular
160 + self.other
161 }
162
163 pub fn percentages(&self) -> [f32; 6] {
165 let total = self.total() as f32;
166 if total == 0.0 {
167 return [0.0; 6];
168 }
169 [
170 self.bottleneck as f32 / total * 100.0,
171 self.loop_count as f32 / total * 100.0,
172 self.rework as f32 / total * 100.0,
173 self.long_running as f32 / total * 100.0,
174 self.circular as f32 / total * 100.0,
175 self.other as f32 / total * 100.0,
176 ]
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 fn create_test_patterns() -> Vec<GpuPatternMatch> {
185 vec![
186 GpuPatternMatch::new(PatternType::Bottleneck, PatternSeverity::Critical)
187 .with_metrics(0.9, 50, 10000.0),
188 GpuPatternMatch::new(PatternType::Loop, PatternSeverity::Warning)
189 .with_metrics(0.7, 30, 5000.0),
190 ]
191 }
192
193 #[test]
194 fn test_pattern_aggregation() {
195 let mut agg = PatternAggregator::new();
196 let patterns = create_test_patterns();
197 agg.add_patterns(&patterns);
198
199 assert_eq!(agg.total_detected, 2);
200 assert_eq!(agg.count_by_type(PatternType::Bottleneck), 1);
201 assert_eq!(agg.count_by_severity(PatternSeverity::Critical), 1);
202 }
203
204 #[test]
205 fn test_distribution() {
206 let mut agg = PatternAggregator::new();
207 let patterns = create_test_patterns();
208 agg.add_patterns(&patterns);
209
210 let dist = agg.distribution();
211 assert_eq!(dist.bottleneck, 1);
212 assert_eq!(dist.loop_count, 1);
213 }
214}