Skip to content

Commit 3c19287

Browse files
committed
optimize analysis engine and add debugging output
1 parent b05ac0e commit 3c19287

4 files changed

Lines changed: 96 additions & 17 deletions

File tree

crates/og-analytics/src/engine.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,23 +258,30 @@ impl AnalyticsEngine {
258258
/// Run metrics sequentially with error recovery
259259
async fn run_metrics_sequential_safe(&self, graph: &CodeGraph) -> Result<Vec<MetricResults>> {
260260
debug!("Running metrics sequentially with error recovery");
261+
println!("[ENGINE-ANALYTICS] Starting sequential metrics execution");
261262

262263
let mut results = Vec::new();
263-
for metric in &self.metrics {
264+
for (idx, metric) in self.metrics.iter().enumerate() {
264265
let name = metric.name();
266+
println!("[ENGINE-ANALYTICS] Running metric {} of {}: {}", idx + 1, self.metrics.len(), name);
265267
debug!("Running metric: {}", name);
266268

267269
// Catch panics and convert to errors
270+
println!("[ENGINE-ANALYTICS] About to calculate metric: {}", name);
268271
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
272+
println!("[ENGINE-ANALYTICS] Inside panic catch for metric: {}", name);
269273
metric.calculate(graph)
270274
}));
271275

276+
println!("[ENGINE-ANALYTICS] Metric {} calculation returned", name);
272277
match result {
273278
Ok(Ok(metric_result)) => {
279+
println!("[ENGINE-ANALYTICS] Metric {} completed successfully", name);
274280
debug!("Metric {} completed successfully", name);
275281
results.push(metric_result);
276282
},
277283
Ok(Err(e)) => {
284+
println!("[ENGINE-ANALYTICS] Metric {} failed with error: {}", name, e);
278285
error!("Metric {} failed: {}", name, e);
279286
results.push(MetricResults::new(name.to_string()));
280287
},
@@ -286,12 +293,14 @@ impl AnalyticsEngine {
286293
} else {
287294
"Unknown panic".to_string()
288295
};
296+
println!("[ENGINE-ANALYTICS] Metric {} panicked: {}", name, msg);
289297
error!("Metric {} panicked: {}", name, msg);
290298
results.push(MetricResults::new(name.to_string()));
291299
}
292300
}
293301
}
294302

303+
println!("[ENGINE-ANALYTICS] All metrics completed");
295304
Ok(results)
296305
}
297306

crates/og-analytics/src/metrics/centrality.rs

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl CentralityMetrics {
5656
/// Calculate betweenness centrality
5757
fn calculate_betweenness(&self, graph: &CodeGraph) -> HashMap<String, f64> {
5858
debug!("Calculating betweenness centrality");
59+
println!("[CENTRALITY] Betweenness: node_count = {}", graph.graph.node_count());
5960

6061
let mut betweenness = HashMap::new();
6162
let node_count = graph.graph.node_count();
@@ -77,20 +78,50 @@ impl CentralityMetrics {
7778
}
7879
}
7980

80-
// Simple betweenness centrality calculation
81-
// For each pair of nodes, find shortest paths and count
82-
for source in graph.graph.node_indices() {
83-
let paths = petgraph::algo::dijkstra(&graph.graph, source, None, |_| 1.0);
81+
// For large graphs, use sampling to avoid O(n³) complexity
82+
const MAX_FULL_CALC_NODES: usize = 100;
83+
const SAMPLE_SIZE: usize = 50;
84+
85+
if node_count > MAX_FULL_CALC_NODES {
86+
println!("[CENTRALITY] Large graph detected ({} nodes), using sampling approach", node_count);
87+
88+
// Sample a subset of source nodes for approximation
89+
let node_indices: Vec<_> = graph.graph.node_indices().collect();
90+
let sample_size = SAMPLE_SIZE.min(node_count);
91+
let step = node_count / sample_size;
8492

85-
for target in graph.graph.node_indices() {
86-
if source != target {
87-
// Count paths through intermediate nodes
88-
for intermediate in graph.graph.node_indices() {
89-
if intermediate != source && intermediate != target {
90-
// Simplified: increment if on a path
91-
if paths.contains_key(&intermediate) && paths.contains_key(&target) {
92-
if let Some(node) = graph.graph.node_weight(intermediate) {
93-
*betweenness.entry(node.id.clone()).or_insert(0.0) += 1.0;
93+
for (i, &source) in node_indices.iter().step_by(step.max(1)).enumerate() {
94+
if i >= sample_size {
95+
break;
96+
}
97+
98+
// Use petgraph's built-in betweenness calculation for this source
99+
let paths = petgraph::algo::dijkstra(&graph.graph, source, None, |_| 1.0);
100+
101+
// Just count nodes on shortest paths (simplified)
102+
for (node_idx, _) in paths.iter() {
103+
if let Some(node) = graph.graph.node_weight(*node_idx) {
104+
*betweenness.entry(node.id.clone()).or_insert(0.0) += 1.0;
105+
}
106+
}
107+
}
108+
} else {
109+
println!("[CENTRALITY] Small graph ({} nodes), using full calculation", node_count);
110+
111+
// Original O(n³) algorithm for small graphs
112+
for source in graph.graph.node_indices() {
113+
let paths = petgraph::algo::dijkstra(&graph.graph, source, None, |_| 1.0);
114+
115+
for target in graph.graph.node_indices() {
116+
if source != target {
117+
// Count paths through intermediate nodes
118+
for intermediate in graph.graph.node_indices() {
119+
if intermediate != source && intermediate != target {
120+
// Simplified: increment if on a path
121+
if paths.contains_key(&intermediate) && paths.contains_key(&target) {
122+
if let Some(node) = graph.graph.node_weight(intermediate) {
123+
*betweenness.entry(node.id.clone()).or_insert(0.0) += 1.0;
124+
}
94125
}
95126
}
96127
}
@@ -182,7 +213,7 @@ impl CentralityMetrics {
182213
}
183214

184215
/// Calculate eigenvector centrality
185-
fn calculate_eigenvector(&self, graph: &CodeGraph) -> HashMap<String, f64> {
216+
fn calculate_eigenvector_centrality(&self, graph: &CodeGraph) -> HashMap<String, f64> {
186217
debug!("Calculating eigenvector centrality");
187218

188219
let node_count = graph.graph.node_count();
@@ -407,14 +438,21 @@ impl CentralityMetrics {
407438

408439
impl Metric for CentralityMetrics {
409440
fn calculate(&self, graph: &CodeGraph) -> Result<MetricResults> {
441+
println!("[CENTRALITY] Starting centrality metrics calculation");
410442
let mut results = MetricResults::new("centrality".to_string());
411443

412444
// Calculate all centrality metrics
445+
println!("[CENTRALITY] Calculating degree centrality...");
413446
let degree_centrality = self.calculate_degree(graph);
447+
println!("[CENTRALITY] Degree centrality done. Calculating betweenness...");
414448
let betweenness = self.calculate_betweenness(graph);
449+
println!("[CENTRALITY] Betweenness done. Calculating closeness...");
415450
let closeness = self.calculate_closeness(graph);
451+
println!("[CENTRALITY] Closeness done. Calculating k-core...");
416452
let k_core = self.calculate_k_core(graph);
453+
println!("[CENTRALITY] K-core done. Calculating clustering...");
417454
let clustering = self.calculate_clustering(graph);
455+
println!("[CENTRALITY] Clustering done.");
418456

419457
// Store degree centrality
420458
for (node_id, (in_degree, out_degree)) in degree_centrality {
@@ -469,7 +507,7 @@ impl Metric for CentralityMetrics {
469507

470508
// Calculate eigenvector if enabled
471509
if self.calculate_eigenvector {
472-
let eigenvector = self.calculate_eigenvector(graph);
510+
let eigenvector = self.calculate_eigenvector_centrality(graph);
473511
results.add_value("eigenvector_map".to_string(), MetricValue::Map(eigenvector.clone()));
474512
for (node_id, value) in eigenvector {
475513
results.add_value(

crates/og-analytics/src/metrics/community.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,19 @@ impl CommunityDetection {
5858
let mut improvement = true;
5959
let mut iteration = 0;
6060

61+
println!("[LOUVAIN] Starting iterations (max_iterations = {})", self.max_iterations);
6162
while improvement && iteration < self.max_iterations {
6263
improvement = false;
6364
iteration += 1;
65+
println!("[LOUVAIN] Iteration {} of {}", iteration, self.max_iterations);
6466

6567
// Phase 1: Local optimization
66-
for node_idx in graph.graph.node_indices() {
68+
let node_count = graph.graph.node_count();
69+
println!("[LOUVAIN] Processing {} nodes in iteration {}", node_count, iteration);
70+
for (idx, node_idx) in graph.graph.node_indices().enumerate() {
71+
if idx % 100 == 0 {
72+
println!("[LOUVAIN] Processing node {} of {}", idx, node_count);
73+
}
6774
let current_community = communities[&node_idx];
6875
let mut best_community = current_community;
6976
let mut best_gain = 0.0;
@@ -117,6 +124,7 @@ impl CommunityDetection {
117124
}
118125
}
119126

127+
println!("[LOUVAIN] Completed after {} iterations", iteration);
120128
debug!("Louvain completed after {} iterations", iteration);
121129
self.node_indices_to_string_map(graph, &communities)
122130
}
@@ -406,12 +414,16 @@ impl CommunityDetection {
406414

407415
impl Metric for CommunityDetection {
408416
fn calculate(&self, graph: &CodeGraph) -> Result<MetricResults> {
417+
println!("[COMMUNITY] Starting community detection");
409418
let mut results = MetricResults::new("community".to_string());
410419

411420
// Run Louvain algorithm
421+
println!("[COMMUNITY] Running Louvain algorithm on {} nodes...", graph.graph.node_count());
412422
let communities = self.louvain(graph);
423+
println!("[COMMUNITY] Louvain complete, found {} community assignments", communities.len());
413424

414425
// Store community assignments
426+
println!("[COMMUNITY] Storing community assignments...");
415427
for (node_id, community) in &communities {
416428
results.add_value(
417429
format!("{}_community", node_id),
@@ -420,17 +432,22 @@ impl Metric for CommunityDetection {
420432
}
421433

422434
// Calculate modularity
435+
println!("[COMMUNITY] Calculating modularity...");
423436
let modularity = self.calculate_modularity(graph, &communities);
437+
println!("[COMMUNITY] Modularity = {}", modularity);
424438
results.add_value("modularity".to_string(), MetricValue::Float(modularity));
425439

426440
// Identify clusters
441+
println!("[COMMUNITY] Identifying clusters...");
427442
let clusters = self.identify_clusters(&communities);
443+
println!("[COMMUNITY] Found {} clusters", clusters.len());
428444
results.add_value(
429445
"num_communities".to_string(),
430446
MetricValue::Integer(clusters.len() as i64),
431447
);
432448

433449
// Store cluster sizes
450+
println!("[COMMUNITY] Storing cluster sizes...");
434451
for (i, cluster) in clusters.iter().enumerate() {
435452
results.add_value(
436453
format!("community_{}_size", i),
@@ -439,14 +456,17 @@ impl Metric for CommunityDetection {
439456
}
440457

441458
// Find refactoring boundaries
459+
println!("[COMMUNITY] Finding refactoring boundaries...");
442460
let boundaries = self.find_refactoring_boundaries(graph, &communities);
461+
println!("[COMMUNITY] Found {} boundaries", boundaries.len());
443462
for (node_id, score) in boundaries {
444463
results.add_value(
445464
format!("{}_boundary_score", node_id),
446465
MetricValue::Float(score),
447466
);
448467
}
449468

469+
println!("[COMMUNITY] Community detection complete");
450470
Ok(results)
451471
}
452472

crates/og-analytics/src/metrics/risk.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,10 +324,13 @@ struct RiskScore {
324324

325325
impl Metric for RiskAnalysis {
326326
fn calculate(&self, graph: &CodeGraph) -> Result<MetricResults> {
327+
println!("[RISK] Starting risk analysis");
327328
let mut results = MetricResults::new("risk".to_string());
328329

329330
// Calculate risk scores
331+
println!("[RISK] Identifying high-risk nodes...");
330332
let risk_scores = self.identify_high_risk_nodes(graph);
333+
println!("[RISK] Found {} high-risk nodes", risk_scores.len());
331334
for (node_id, scores) in risk_scores {
332335
results.add_value(
333336
format!("{}_risk", node_id),
@@ -348,7 +351,9 @@ impl Metric for RiskAnalysis {
348351
}
349352

350353
// Find chokepoints
354+
println!("[RISK] Finding chokepoints...");
351355
let chokepoints = self.find_chokepoints(graph);
356+
println!("[RISK] Found {} chokepoints", chokepoints.len());
352357
for (node_id, score) in chokepoints {
353358
results.add_value(
354359
format!("{}_chokepoint", node_id),
@@ -357,7 +362,9 @@ impl Metric for RiskAnalysis {
357362
}
358363

359364
// Detect circular dependencies
365+
println!("[RISK] Detecting circular dependencies...");
360366
let circular_deps = self.detect_circular_dependencies(graph);
367+
println!("[RISK] Found {} circular dependencies", circular_deps.len());
361368
results.add_value(
362369
"circular_dependencies".to_string(),
363370
MetricValue::Integer(circular_deps.len() as i64),
@@ -377,7 +384,9 @@ impl Metric for RiskAnalysis {
377384
}
378385

379386
// Calculate technical debt
387+
println!("[RISK] Calculating technical debt...");
380388
let debt_scores = self.calculate_technical_debt(graph);
389+
println!("[RISK] Calculated debt for {} nodes", debt_scores.len());
381390
for (node_id, score) in debt_scores {
382391
results.add_value(
383392
format!("{}_technical_debt", node_id),
@@ -386,14 +395,17 @@ impl Metric for RiskAnalysis {
386395
}
387396

388397
// Calculate change propagation
398+
println!("[RISK] Calculating change propagation...");
389399
let propagation = self.calculate_change_propagation(graph);
400+
println!("[RISK] Calculated propagation for {} nodes", propagation.len());
390401
for (node_id, score) in propagation {
391402
results.add_value(
392403
format!("{}_change_propagation", node_id),
393404
MetricValue::Float(score),
394405
);
395406
}
396407

408+
println!("[RISK] Risk analysis complete");
397409
Ok(results)
398410
}
399411

0 commit comments

Comments
 (0)