fuchsia_inspect/writer/types/
int_exponential_histogram.rs1use crate::writer::{
6 ArithmeticArrayProperty, ArrayProperty, HistogramProperty, InspectType, IntArrayProperty, Node,
7};
8use diagnostics_hierarchy::{ArrayFormat, ExponentialHistogramParams};
9use log::error;
10use std::borrow::Cow;
11
12#[derive(Debug, Default)]
13pub struct IntExponentialHistogramProperty {
15 array: IntArrayProperty,
16 floor: i64,
17 initial_step: i64,
18 step_multiplier: i64,
19 buckets: usize,
20}
21
22impl InspectType for IntExponentialHistogramProperty {}
23
24impl IntExponentialHistogramProperty {
25 pub(crate) fn new(
26 name: Cow<'_, str>,
27 params: ExponentialHistogramParams<i64>,
28 parent: &Node,
29 ) -> Self {
30 let slots = params.buckets + ArrayFormat::ExponentialHistogram.extra_slots();
31 let array =
32 parent.create_int_array_internal(name, slots, ArrayFormat::ExponentialHistogram);
33 array.set(0, params.floor);
34 array.set(1, params.initial_step);
35 array.set(2, params.step_multiplier);
36 Self {
37 floor: params.floor,
38 initial_step: params.initial_step,
39 step_multiplier: params.step_multiplier,
40 buckets: params.buckets,
41 array,
42 }
43 }
44
45 fn get_index(&self, value: i64) -> usize {
46 let value = value as i128;
50 let floor = self.floor as i128;
51 let mut bucket_end = floor; let mut step = self.initial_step as i128;
53
54 let mut index = ArrayFormat::ExponentialHistogram.underflow_bucket_index();
55 let overflow_index = ArrayFormat::ExponentialHistogram.overflow_bucket_index(self.buckets);
56
57 while value >= bucket_end && index < overflow_index {
58 if let Some(c) = floor.checked_add(step) {
59 bucket_end = c;
60 } else {
61 return index + 1;
64 }
65
66 if bucket_end > i64::MAX as i128 {
67 return index + 1;
70 }
71
72 step = step.saturating_mul(self.step_multiplier as i128);
73 index += 1;
74 }
75 index
76 }
77}
78
79impl HistogramProperty for IntExponentialHistogramProperty {
80 type Type = i64;
81
82 fn insert(&self, value: i64) {
83 self.insert_multiple(value, 1);
84 }
85
86 fn insert_multiple(&self, value: i64, count: usize) {
87 self.array.add(self.get_index(value), count as i64);
88 }
89
90 fn clear(&self) {
91 if let Some(ref inner_ref) = self.array.inner.inner_ref() {
92 inner_ref
94 .state
95 .try_lock()
96 .and_then(|mut state| {
97 state.clear_array(
100 inner_ref.block_index,
101 ArrayFormat::ExponentialHistogram.underflow_bucket_index(),
102 )
103 })
104 .unwrap_or_else(|err| {
105 error!(err:?; "Failed to clear property");
106 });
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::writer::Inspector;
115 use crate::writer::testing_utils::GetBlockExt;
116 use inspect_format::{Array, Int};
117
118 #[fuchsia::test]
119 fn test_int_exp_histogram() {
120 let inspector = Inspector::default();
121 let root = inspector.root();
122 let node = root.create_child("node");
123 {
124 let int_histogram = node.create_int_exponential_histogram(
125 "int-histogram",
126 ExponentialHistogramParams {
127 floor: 1,
128 initial_step: 1,
129 step_multiplier: 2,
130 buckets: 4,
131 },
132 );
133 int_histogram.insert_multiple(-1, 2); int_histogram.insert(8);
135 int_histogram.insert(500); int_histogram.array.get_block::<_, Array<Int>>(|block| {
137 for (i, value) in [1, 1, 2, 2, 0, 0, 0, 1, 1].iter().enumerate() {
138 assert_eq!(block.get(i).unwrap(), *value);
139 }
140 });
141
142 node.get_block::<_, inspect_format::Node>(|node_block| {
143 assert_eq!(node_block.child_count(), 1);
144 });
145 }
146 node.get_block::<_, inspect_format::Node>(|node_block| {
147 assert_eq!(node_block.child_count(), 0);
148 });
149 }
150
151 #[fuchsia::test]
152 fn exp_histogram_insert() {
153 let inspector = Inspector::default();
154 let root = inspector.root();
155 let hist = root.create_int_exponential_histogram(
156 "test",
157 ExponentialHistogramParams {
158 floor: 0,
159 initial_step: 2,
160 step_multiplier: 4,
161 buckets: 4,
162 },
163 );
164 for i in -200..200 {
165 hist.insert(i);
166 }
167 hist.array.get_block::<_, Array<Int>>(|block| {
168 assert_eq!(block.get(0).unwrap(), 0);
169 assert_eq!(block.get(1).unwrap(), 2);
170 assert_eq!(block.get(2).unwrap(), 4);
171
172 let i = 3;
174 assert_eq!(block.get(i).unwrap(), 200);
175 assert_eq!(block.get(i + 1).unwrap(), 2);
176 assert_eq!(block.get(i + 2).unwrap(), 6);
177 assert_eq!(block.get(i + 3).unwrap(), 24);
178 assert_eq!(block.get(i + 4).unwrap(), 96);
179 assert_eq!(block.get(i + 5).unwrap(), 72);
180 });
181 }
182
183 #[fuchsia::test]
184 fn overflow_underflow() {
185 let inspector = Inspector::default();
186 let root = inspector.root();
187 let hist = root.create_int_exponential_histogram(
188 "test",
189 ExponentialHistogramParams {
190 floor: 0,
191 initial_step: i64::MAX / 2,
192 step_multiplier: 2,
193 buckets: 4,
194 },
195 );
196
197 hist.insert((i64::MAX / 2) + 1);
199
200 hist.insert(-5);
201
202 hist.array.get_block::<_, Array<Int>>(|block| {
203 assert_eq!(block.get(0).unwrap(), 0);
204 assert_eq!(block.get(1).unwrap(), i64::MAX / 2);
205 assert_eq!(block.get(2).unwrap(), 2);
206
207 assert_eq!(block.get(3).unwrap(), 1);
208 assert_eq!(block.get(4).unwrap(), 0);
209 assert_eq!(block.get(5).unwrap(), 1);
210 assert_eq!(block.get(6).unwrap(), 0);
211 assert_eq!(block.get(7).unwrap(), 0);
212 assert_eq!(block.get(8).unwrap(), 0);
213 });
214 }
215}