iai_callgrind_runner/runner/callgrind/
model.rs1use std::borrow::Cow;
4use std::hash::Hash;
5use std::str::FromStr;
6
7use anyhow::{anyhow, Result};
8use indexmap::{indexmap, IndexMap};
9use serde::{Deserialize, Serialize};
10
11use super::CacheSummary;
12use crate::api::EventKind;
13use crate::runner::metrics::{Metric, Summarize};
14
15pub type Metrics = crate::runner::metrics::Metrics<EventKind>;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
20pub enum PositionType {
21 Instr,
23 Line,
25}
26
27#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
29pub struct Calls {
30 amount: u64,
32 positions: Positions,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct Positions(pub IndexMap<PositionType, u64>);
39
40impl Calls {
41 pub fn from<I, T>(mut iter: T, mut positions: Positions) -> Self
43 where
44 I: AsRef<str>,
45 T: Iterator<Item = I>,
46 {
47 let amount = iter.next().unwrap().as_ref().parse().unwrap();
48 positions.set_iter_str(iter);
49 Self { amount, positions }
50 }
51}
52
53impl Summarize for EventKind {
54 fn summarize(costs: &mut Cow<Metrics>) {
55 if !costs.is_summarized() {
56 let _ = costs.to_mut().make_summary();
57 }
58 }
59}
60
61impl Metrics {
62 pub fn make_summary(&mut self) -> Result<()> {
71 let CacheSummary {
72 l1_hits,
73 l3_hits,
74 ram_hits,
75 total_memory_rw,
76 cycles,
77 i1_miss_rate,
78 d1_miss_rate,
79 ll_miss_rate,
80 lli_miss_rate,
81 lld_miss_rate,
82 l1_hit_rate,
83 l3_hit_rate,
84 ram_hit_rate,
85 } = (&*self).try_into()?;
86
87 self.insert(EventKind::L1hits, l1_hits);
88 self.insert(EventKind::LLhits, l3_hits);
89 self.insert(EventKind::RamHits, ram_hits);
90 self.insert(EventKind::TotalRW, total_memory_rw);
91 self.insert(EventKind::EstimatedCycles, cycles);
92 self.insert(EventKind::I1MissRate, i1_miss_rate);
93 self.insert(EventKind::D1MissRate, d1_miss_rate);
94 self.insert(EventKind::LLiMissRate, lli_miss_rate);
95 self.insert(EventKind::LLdMissRate, lld_miss_rate);
96 self.insert(EventKind::LLMissRate, ll_miss_rate);
97 self.insert(EventKind::L1HitRate, l1_hit_rate);
98 self.insert(EventKind::LLHitRate, l3_hit_rate);
99 self.insert(EventKind::RamHitRate, ram_hit_rate);
100
101 Ok(())
102 }
103
104 pub fn is_summarized(&self) -> bool {
108 self.metric_by_kind(&EventKind::EstimatedCycles).is_some()
109 }
110
111 pub fn can_summarize(&self) -> bool {
116 self.metric_by_kind(&EventKind::I1mr).is_some()
117 }
118}
119
120impl Default for Metrics {
121 fn default() -> Self {
122 Self(indexmap! {EventKind::Ir => Metric::Int(0)})
123 }
124}
125
126impl FromStr for PositionType {
127 type Err = anyhow::Error;
128
129 fn from_str(value: &str) -> std::result::Result<Self, Self::Err> {
130 match value.to_lowercase().as_str() {
132 "instr" | "addr" => Ok(Self::Instr),
133 "line" => Ok(Self::Line),
134 _ => Err(anyhow!("Unknown positions type: '{value}")),
135 }
136 }
137}
138
139impl Positions {
140 pub fn try_from_iter_str<'a, I>(iter: I) -> Result<Self>
142 where
143 I: Iterator<Item = &'a str>,
144 {
145 iter.map(|s| s.parse::<PositionType>().map(|p| (p, 0)))
146 .collect::<Result<IndexMap<_, _>>>()
147 .map(Positions)
148 }
149
150 pub fn set_iter_str<I, T>(&mut self, iter: T)
152 where
153 I: AsRef<str>,
154 T: IntoIterator<Item = I>,
155 {
156 for ((_, old), pos) in self.0.iter_mut().zip(iter.into_iter()) {
157 let pos = pos.as_ref();
158 *old = if let Some(hex) = pos.strip_prefix("0x") {
159 u64::from_str_radix(hex, 16).unwrap()
160 } else {
161 pos.parse::<u64>().unwrap()
162 }
163 }
164 }
165
166 pub fn len(&self) -> usize {
168 self.0.len()
169 }
170
171 pub fn is_empty(&self) -> bool {
173 self.0.is_empty()
174 }
175}
176
177impl Default for Positions {
178 fn default() -> Self {
179 Self(indexmap! {PositionType::Line => 0})
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
190 fn test_metrics_make_summary_when_cache_sim() {
191 use EventKind::*;
192
193 let mut expected = Metrics::with_metric_kinds([
194 (Ir, 1),
195 (Dr, 2),
196 (Dw, 3),
197 (I1mr, 4),
198 (D1mr, 5),
199 (D1mw, 6),
200 (ILmr, 7),
201 (DLmr, 8),
202 (DLmw, 9),
203 (L1hits, 0),
204 (LLhits, 0),
205 (RamHits, 24),
206 (TotalRW, 6),
207 (EstimatedCycles, 840),
208 ]);
209
210 expected.insert_all(&[
211 (I1MissRate, Metric::Float(400.0f64)),
212 (D1MissRate, Metric::Float(220.000_000_000_000_03_f64)),
213 (LLiMissRate, Metric::Float(700.0f64)),
214 (LLdMissRate, Metric::Float(340.0f64)),
215 (LLMissRate, Metric::Float(400.0f64)),
216 (L1HitRate, Metric::Float(0.0f64)),
217 (LLHitRate, Metric::Float(0.0f64)),
218 (RamHitRate, Metric::Float(400.0f64)),
219 ]);
220
221 let mut metrics = Metrics::with_metric_kinds([
222 (Ir, 1),
223 (Dr, 2),
224 (Dw, 3),
225 (I1mr, 4),
226 (D1mr, 5),
227 (D1mw, 6),
228 (ILmr, 7),
229 (DLmr, 8),
230 (DLmw, 9),
231 ]);
232
233 metrics.make_summary().unwrap();
234
235 assert_eq!(metrics, expected);
236 }
237}