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