Skip to main content

airbender_host/
cycle_marker.rs

1//! Stable host-side cycle marker snapshots collected from transpiler runs.
2
3use std::collections::HashMap;
4
5/// Snapshot of the cumulative cycle and delegation counters at one marker.
6#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
7pub struct Mark {
8    pub cycles: u64,
9    pub delegations: HashMap<u32, u64>,
10}
11
12impl Mark {
13    /// Derive the work performed between two cumulative marker snapshots.
14    pub fn diff(&self, before: &Self) -> Self {
15        let cycles = self
16            .cycles
17            .checked_sub(before.cycles)
18            .expect("cycle markers must be compared in execution order");
19        let mut delegations = HashMap::new();
20
21        for (id, current_count) in &self.delegations {
22            let diff = match before.delegations.get(id) {
23                Some(previous_count) => current_count
24                    .checked_sub(*previous_count)
25                    .expect("delegation counters must be compared in execution order"),
26                None => *current_count,
27            };
28
29            if diff != 0 {
30                delegations.insert(*id, diff);
31            }
32        }
33
34        Self {
35            cycles,
36            delegations,
37        }
38    }
39}
40
41impl From<riscv_transpiler::cycle::Mark> for Mark {
42    fn from(mark: riscv_transpiler::cycle::Mark) -> Self {
43        Self {
44            cycles: mark.cycles,
45            delegations: mark.delegations,
46        }
47    }
48}
49
50/// All marker snapshots captured from one transpiler execution run.
51#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
52pub struct CycleMarker {
53    pub markers: Vec<Mark>,
54    pub delegation_counter: HashMap<u32, u64>,
55}
56
57impl From<riscv_transpiler::cycle::CycleMarker> for CycleMarker {
58    fn from(marker: riscv_transpiler::cycle::CycleMarker) -> Self {
59        Self {
60            markers: marker.markers.into_iter().map(Mark::from).collect(),
61            delegation_counter: marker.delegation_counter,
62        }
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::Mark;
69    use std::collections::HashMap;
70
71    #[test]
72    fn diff_reports_work_between_two_markers() {
73        let before = Mark {
74            cycles: 8,
75            delegations: HashMap::from([(0x7ca, 2), (0x7cb, 5)]),
76        };
77        let after = Mark {
78            cycles: 13,
79            delegations: HashMap::from([(0x7ca, 2), (0x7cb, 8), (0x7cc, 1)]),
80        };
81
82        let diff = after.diff(&before);
83
84        assert_eq!(diff.cycles, 5);
85        assert_eq!(diff.delegations.len(), 2);
86        assert_eq!(diff.delegations.get(&0x7cb), Some(&3));
87        assert_eq!(diff.delegations.get(&0x7cc), Some(&1));
88    }
89}