iai_callgrind_runner/runner/callgrind/
model.rs1use std::borrow::Cow;
4use std::hash::Hash;
5
6use anyhow::Result;
7use indexmap::{indexmap, IndexMap};
8use serde::{Deserialize, Serialize};
9
10use super::CacheSummary;
11use crate::api::EventKind;
12use crate::runner::metrics::Summarize;
13
14pub type Metrics = crate::runner::metrics::Metrics<EventKind>;
15
16#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
17pub struct Calls {
18 amount: u64,
19 positions: Positions,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub enum PositionType {
24 Instr,
25 Line,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
29pub struct Positions(IndexMap<PositionType, u64>);
30
31impl Calls {
32 pub fn from<I>(mut iter: impl Iterator<Item = I>, mut positions: Positions) -> Self
33 where
34 I: AsRef<str>,
35 {
36 let amount = iter.next().unwrap().as_ref().parse().unwrap();
37 positions.set_iter_str(iter);
38 Self { amount, positions }
39 }
40}
41
42impl Metrics {
43 pub fn make_summary(&mut self) -> Result<()> {
52 let CacheSummary {
53 l1_hits,
54 l3_hits,
55 ram_hits,
56 total_memory_rw,
57 cycles,
58 } = (&*self).try_into()?;
59
60 self.insert(EventKind::L1hits, l1_hits);
61 self.insert(EventKind::LLhits, l3_hits);
62 self.insert(EventKind::RamHits, ram_hits);
63 self.insert(EventKind::TotalRW, total_memory_rw);
64 self.insert(EventKind::EstimatedCycles, cycles);
65
66 Ok(())
67 }
68
69 pub fn is_summarized(&self) -> bool {
73 self.metric_by_kind(&EventKind::EstimatedCycles).is_some()
74 }
75
76 pub fn can_summarize(&self) -> bool {
81 self.metric_by_kind(&EventKind::I1mr).is_some()
82 }
83}
84
85impl Default for Metrics {
86 fn default() -> Self {
87 Self(indexmap! {EventKind::Ir => 0})
88 }
89}
90
91impl Summarize for EventKind {
92 fn summarize(costs: &mut Cow<Metrics>) {
93 if !costs.is_summarized() {
94 let _ = costs.to_mut().make_summary();
95 }
96 }
97}
98
99impl Positions {
100 pub fn set_iter_str<I, T>(&mut self, iter: T)
101 where
102 I: AsRef<str>,
103 T: IntoIterator<Item = I>,
104 {
105 for ((_, old), pos) in self.0.iter_mut().zip(iter.into_iter()) {
106 let pos = pos.as_ref();
107 *old = if let Some(hex) = pos.strip_prefix("0x") {
108 u64::from_str_radix(hex, 16).unwrap()
109 } else {
110 pos.parse::<u64>().unwrap()
111 }
112 }
113 }
114
115 pub fn len(&self) -> usize {
116 self.0.len()
117 }
118
119 pub fn is_empty(&self) -> bool {
120 self.0.is_empty()
121 }
122}
123
124impl Default for Positions {
125 fn default() -> Self {
126 Self(indexmap! {PositionType::Line => 0})
127 }
128}
129
130impl<I> FromIterator<I> for Positions
131where
132 I: AsRef<str>,
133{
134 fn from_iter<T>(iter: T) -> Self
135 where
136 T: IntoIterator<Item = I>,
137 {
138 Self(
139 iter.into_iter()
140 .map(|p| (PositionType::from(p), 0))
141 .collect::<IndexMap<_, _>>(),
142 )
143 }
144}
145
146impl<T> From<T> for PositionType
147where
148 T: AsRef<str>,
149{
150 fn from(value: T) -> Self {
151 let value = value.as_ref();
152 match value.to_lowercase().as_str() {
154 "instr" | "addr" => Self::Instr,
155 "line" => Self::Line,
156 _ => panic!("Unknown positions type: '{value}"),
157 }
158 }
159}