1use crate::counter::{AnyCounter, IntoCounter, KnownCounterKind, MaxCountUInt};
2
3/// Multi-map from counters to their counts and input-based initializer.
4#[derive(Default)]
5pub(crate) struct CounterCollection {
6 info: [KnownCounterInfo; KnownCounterKind::COUNT],
7}
8
9#[derive(Default)]
10struct KnownCounterInfo {
11 // TODO: Inlinable vector.
12 counts: Vec<MaxCountUInt>,
13
14 /// `BencherConfig::with_inputs` can only be called once, so the input type
15 /// cannot change.
16 count_input: Option<Box</* unsafe */ dyn Fn(*const ()) -> MaxCountUInt + Sync>>,
17}
18
19impl CounterCollection {
20 #[inline]
21 fn info(&self, counter_kind: KnownCounterKind) -> &KnownCounterInfo {
22 &self.info[counter_kind as usize]
23 }
24
25 #[inline]
26 fn info_mut(&mut self, counter_kind: KnownCounterKind) -> &mut KnownCounterInfo {
27 &mut self.info[counter_kind as usize]
28 }
29
30 #[inline]
31 pub(crate) fn counts(&self, counter_kind: KnownCounterKind) -> &[MaxCountUInt] {
32 &self.info(counter_kind).counts
33 }
34
35 pub(crate) fn mean_count(&self, counter_kind: KnownCounterKind) -> MaxCountUInt {
36 let counts = self.counts(counter_kind);
37
38 let sum: u128 = counts.iter().map(|&c| c as u128).sum();
39
40 (sum / counts.len() as u128) as MaxCountUInt
41 }
42
43 #[inline]
44 pub(crate) fn uses_input_counts(&self, counter_kind: KnownCounterKind) -> bool {
45 self.info(counter_kind).count_input.is_some()
46 }
47
48 pub(crate) fn set_counter(&mut self, counter: AnyCounter) {
49 let new_count = counter.count();
50 let info = self.info_mut(counter.known_kind());
51
52 if let Some(old_count) = info.counts.first_mut() {
53 *old_count = new_count;
54 } else {
55 info.counts.push(new_count);
56 }
57 }
58
59 pub(crate) fn push_counter(&mut self, counter: AnyCounter) {
60 self.info_mut(counter.known_kind()).counts.push(counter.count());
61 }
62
63 /// Set the input-based count generator function for a counter.
64 pub(crate) fn set_input_counter<I, C, F>(&mut self, make_counter: F)
65 where
66 F: Fn(&I) -> C + Sync + 'static,
67 C: IntoCounter,
68 {
69 let info = self.info_mut(KnownCounterKind::of::<C::Counter>());
70
71 // Ignore previously-set counts.
72 info.counts.clear();
73
74 info.count_input = Some(Box::new(move |input: *const ()| {
75 // SAFETY: Callers to `get_input_count` guarantee that the same `&I`
76 // is passed.
77 let counter = unsafe { make_counter(&*input.cast::<I>()) };
78
79 AnyCounter::new(counter).count()
80 }));
81 }
82
83 /// Calls the user-provided closure to get the counter count for a given
84 /// input.
85 ///
86 /// # Safety
87 ///
88 /// The `I` type must be the same as that used by `set_input_counter`.
89 pub(crate) unsafe fn get_input_count<I>(
90 &self,
91 counter_kind: KnownCounterKind,
92 input: &I,
93 ) -> Option<MaxCountUInt> {
94 let from_input = self.info(counter_kind).count_input.as_ref()?;
95
96 // SAFETY: The caller ensures that this is called on the same input type
97 // used for calling `set_input_counter`.
98 Some(unsafe { from_input(input as *const I as *const ()) })
99 }
100
101 /// Removes counts that came from input.
102 pub(crate) fn clear_input_counts(&mut self) {
103 for info in &mut self.info {
104 if info.count_input.is_some() {
105 info.counts.clear();
106 }
107 }
108 }
109}
110
111/// A set of known and (future) custom counters.
112#[derive(Clone, Debug, Default)]
113pub struct CounterSet {
114 counts: [Option<MaxCountUInt>; KnownCounterKind::COUNT],
115}
116
117impl CounterSet {
118 pub fn with(mut self, counter: impl IntoCounter) -> Self {
119 self.insert(counter);
120 self
121 }
122
123 pub fn insert(&mut self, counter: impl IntoCounter) -> &mut Self {
124 let counter = AnyCounter::new(counter);
125 self.counts[counter.known_kind() as usize] = Some(counter.count());
126 self
127 }
128
129 pub(crate) fn get(&self, counter_kind: KnownCounterKind) -> Option<MaxCountUInt> {
130 self.counts[counter_kind as usize]
131 }
132
133 /// Overwrites `other` with values set in `self`.
134 pub(crate) fn overwrite(&self, other: &Self) -> Self {
135 Self { counts: KnownCounterKind::ALL.map(|kind| self.get(kind).or(other.get(kind))) }
136 }
137
138 pub(crate) fn to_collection(&self) -> CounterCollection {
139 CounterCollection {
140 info: KnownCounterKind::ALL.map(|kind| KnownCounterInfo {
141 counts: self.get(kind).into_iter().collect(),
142 count_input: None,
143 }),
144 }
145 }
146}
147