openvm_prof/
instruction_count.rs

1use std::collections::HashMap;
2
3use crate::types::MetricDb;
4
5pub fn generate_instruction_count_table(db: &MetricDb) -> String {
6    let mut markdown_output = String::new();
7
8    // Find the table that has "opcode" and "frequency"
9    for (label_keys, metrics_dict) in &db.dict_by_label_types {
10        let has_opcode = label_keys.iter().any(|k| k == "opcode");
11        let has_frequency = metrics_dict
12            .values()
13            .flat_map(|metrics| metrics.iter().map(|m| m.name.clone()))
14            .any(|name| name == "frequency");
15
16        if !has_opcode || !has_frequency {
17            continue;
18        }
19
20        // Aggregate frequencies by opcode (and group if present)
21        let mut aggregated: HashMap<(Option<String>, String), f64> = HashMap::new();
22        let group_index = label_keys.iter().position(|k| k == "group");
23        let opcode_index = label_keys.iter().position(|k| k == "opcode");
24
25        for (label_values, metrics) in metrics_dict {
26            // Get opcode value
27            let opcode = if let Some(idx) = opcode_index {
28                label_values.get(idx).cloned().unwrap_or_default()
29            } else {
30                continue;
31            };
32
33            // Get group value if present
34            let group = if let Some(idx) = group_index {
35                label_values.get(idx).cloned()
36            } else {
37                None
38            };
39
40            // Get frequency value
41            let frequency = metrics
42                .iter()
43                .find(|m| m.name == "frequency")
44                .map(|m| m.value)
45                .unwrap_or(0.0);
46
47            // Aggregate by (group, opcode) tuple
48            let key = (group, opcode);
49            *aggregated.entry(key).or_insert(0.0) += frequency;
50        }
51
52        // Create table header
53        let mut header_parts = Vec::new();
54        if group_index.is_some() {
55            header_parts.push("group".to_string());
56        }
57        header_parts.push("opcode".to_string());
58        header_parts.push("frequency".to_string());
59
60        let header = format!("| {} |", header_parts.join(" | "));
61        let separator = format!("| {} |", vec!["---"; header_parts.len()].join(" | "));
62
63        markdown_output.push_str(&header);
64        markdown_output.push('\n');
65        markdown_output.push_str(&separator);
66        markdown_output.push('\n');
67
68        // Sort by frequency (descending)
69        let mut sorted_entries: Vec<_> = aggregated.into_iter().collect();
70        sorted_entries.sort_by(|(_, freq_a), (_, freq_b)| {
71            freq_b
72                .partial_cmp(freq_a)
73                .unwrap_or(std::cmp::Ordering::Equal)
74        });
75
76        // Generate rows
77        for ((group, opcode), frequency) in sorted_entries {
78            let formatted_freq = MetricDb::format_number(frequency);
79            if let Some(group_val) = group {
80                markdown_output.push_str(&format!(
81                    "| {} | {} | {} |\n",
82                    group_val, opcode, formatted_freq
83                ));
84            } else {
85                markdown_output.push_str(&format!("| {} | {} |\n", opcode, formatted_freq));
86            }
87        }
88
89        markdown_output.push('\n');
90        break; // Only process the first matching table
91    }
92
93    markdown_output
94}