fuchsia_inspect/writer/types/
uint_exponential_histogram.rs1use crate::writer::{
6 ArithmeticArrayProperty, ArrayProperty, HistogramProperty, InspectType, Node, UintArrayProperty,
7};
8use diagnostics_hierarchy::{ArrayFormat, ExponentialHistogramParams};
9use inspect_format::constants;
10use log::error;
11use std::borrow::Cow;
12
13#[derive(Debug, Default)]
14pub struct UintExponentialHistogramProperty {
16 array: UintArrayProperty,
17 floor: u64,
18 initial_step: u64,
19 step_multiplier: u64,
20 slots: usize,
21}
22
23impl InspectType for UintExponentialHistogramProperty {}
24
25impl UintExponentialHistogramProperty {
26 pub(crate) fn new(
27 name: Cow<'_, str>,
28 params: ExponentialHistogramParams<u64>,
29 parent: &Node,
30 ) -> Self {
31 let slots = params.buckets + constants::EXPONENTIAL_HISTOGRAM_EXTRA_SLOTS;
32 let array =
33 parent.create_uint_array_internal(name, slots, ArrayFormat::ExponentialHistogram);
34 array.set(0, params.floor);
35 array.set(1, params.initial_step);
36 array.set(2, params.step_multiplier);
37 Self {
38 floor: params.floor,
39 initial_step: params.initial_step,
40 step_multiplier: params.step_multiplier,
41 slots,
42 array,
43 }
44 }
45
46 fn get_index(&self, value: u64) -> usize {
47 let mut current_floor = self.floor;
48 let mut offset = self.initial_step;
49 let mut index = constants::EXPONENTIAL_HISTOGRAM_EXTRA_SLOTS - 2;
51 while value >= current_floor && index < self.slots - 1 {
52 current_floor = self.floor + offset;
53 if let Some(o) = self.step_multiplier.checked_mul(offset) {
54 offset = o;
55 } else {
56 return self.slots - 1;
57 };
58 index += 1;
59 }
60 index
61 }
62}
63
64impl HistogramProperty for UintExponentialHistogramProperty {
65 type Type = u64;
66
67 fn insert(&self, value: u64) {
68 self.insert_multiple(value, 1);
69 }
70
71 fn insert_multiple(&self, value: u64, count: usize) {
72 self.array.add(self.get_index(value), count as u64);
73 }
74
75 fn clear(&self) {
76 if let Some(ref inner_ref) = self.array.inner.inner_ref() {
77 inner_ref
79 .state
80 .try_lock()
81 .and_then(|mut state| {
82 state.clear_array(
84 inner_ref.block_index,
85 constants::EXPONENTIAL_HISTOGRAM_EXTRA_SLOTS - 2,
86 )
87 })
88 .unwrap_or_else(|err| {
89 error!(err:?; "Failed to clear property");
90 });
91 }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::writer::Inspector;
99 use crate::writer::testing_utils::GetBlockExt;
100 use inspect_format::{Array, Uint};
101
102 #[fuchsia::test]
103 fn test_uint_exp_histogram() {
104 let inspector = Inspector::default();
105 let root = inspector.root();
106 let node = root.create_child("node");
107 {
108 let uint_histogram = node.create_uint_exponential_histogram(
109 "uint-histogram",
110 ExponentialHistogramParams {
111 floor: 1,
112 initial_step: 1,
113 step_multiplier: 2,
114 buckets: 4,
115 },
116 );
117 uint_histogram.insert_multiple(0, 2); uint_histogram.insert(8);
119 uint_histogram.insert(500); uint_histogram.array.get_block::<_, Array<Uint>>(|block| {
121 for (i, value) in [1, 1, 2, 2, 0, 0, 0, 1, 1].iter().enumerate() {
122 assert_eq!(block.get(i).unwrap(), *value);
123 }
124 });
125
126 uint_histogram.clear();
127 uint_histogram.array.get_block::<_, Array<Uint>>(|block| {
128 for (i, value) in [1, 1, 2, 0, 0, 0, 0, 0, 0].iter().enumerate() {
129 assert_eq!(*value, block.get(i).unwrap());
130 }
131 });
132
133 node.get_block::<_, inspect_format::Node>(|node_block| {
134 assert_eq!(node_block.child_count(), 1);
135 });
136 }
137 node.get_block::<_, inspect_format::Node>(|node_block| {
138 assert_eq!(node_block.child_count(), 0);
139 });
140 }
141
142 #[fuchsia::test]
143 fn overflow_underflow() {
144 let inspector = Inspector::default();
145 let root = inspector.root();
146 let hist = root.create_uint_exponential_histogram(
147 "test",
148 ExponentialHistogramParams {
149 floor: 1,
150 initial_step: u64::MAX / 2,
151 step_multiplier: 2,
152 buckets: 4,
153 },
154 );
155
156 hist.insert((u64::MAX / 2) + 1);
158
159 hist.insert(0);
160
161 hist.array.get_block::<_, Array<Uint>>(|block| {
162 assert_eq!(block.get(0).unwrap(), 1);
163 assert_eq!(block.get(1).unwrap(), u64::MAX / 2);
164 assert_eq!(block.get(2).unwrap(), 2);
165
166 assert_eq!(block.get(3).unwrap(), 1);
167 assert_eq!(block.get(4).unwrap(), 0);
168 assert_eq!(block.get(5).unwrap(), 0);
169 assert_eq!(block.get(6).unwrap(), 0);
170 assert_eq!(block.get(7).unwrap(), 0);
171 assert_eq!(block.get(8).unwrap(), 1);
172 });
173 }
174}