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 fn into_recorded(self) -> crate::writer::types::RecordedInspectType {
24 crate::writer::types::RecordedInspectType::UintArray(self.array)
25 }
26}
27
28impl UintExponentialHistogramProperty {
29 pub(crate) fn new(
30 name: Cow<'_, str>,
31 params: ExponentialHistogramParams<u64>,
32 parent: &Node,
33 ) -> Self {
34 let slots = params.buckets + ArrayFormat::ExponentialHistogram.extra_slots();
35 let array =
36 parent.create_uint_array_internal(name, slots, ArrayFormat::ExponentialHistogram);
37 array.set(0, params.floor);
38 array.set(1, params.initial_step);
39 array.set(2, params.step_multiplier);
40 Self {
41 floor: params.floor,
42 initial_step: params.initial_step,
43 step_multiplier: params.step_multiplier,
44 buckets: params.buckets,
45 array,
46 }
47 }
48
49 fn get_index(&self, value: u64) -> usize {
50 let floor = self.floor;
51 let mut bucket_end = floor; let mut step = self.initial_step;
53
54 let mut index = ArrayFormat::ExponentialHistogram.underflow_bucket_index();
55 let overflow_index = ArrayFormat::ExponentialHistogram.overflow_bucket_index(self.buckets);
56 while value >= bucket_end && index < overflow_index {
57 if let Some(c) = floor.checked_add(step) {
58 bucket_end = c;
59 } else {
60 return index + 1;
63 }
64
65 step = step.saturating_mul(self.step_multiplier);
66 index += 1;
67 }
68 index
69 }
70}
71
72impl HistogramProperty for UintExponentialHistogramProperty {
73 type Type = u64;
74
75 fn insert(&self, value: u64) {
76 self.insert_multiple(value, 1);
77 }
78
79 fn insert_multiple(&self, value: u64, count: usize) {
80 self.array.add(self.get_index(value), count as u64);
81 }
82
83 fn clear(&self) {
84 if let Some(ref inner_ref) = self.array.inner.inner_ref() {
85 inner_ref
87 .state
88 .try_lock()
89 .and_then(|mut state| {
90 state.clear_array(
93 inner_ref.block_index,
94 ArrayFormat::ExponentialHistogram.underflow_bucket_index(),
95 )
96 })
97 .unwrap_or_else(|err| {
98 error!(err:?; "Failed to clear property");
99 });
100 }
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use crate::writer::Inspector;
108 use crate::writer::testing_utils::GetBlockExt;
109 use inspect_format::{Array, Uint};
110
111 #[fuchsia::test]
112 fn test_uint_exp_histogram() {
113 let inspector = Inspector::default();
114 let root = inspector.root();
115 let node = root.create_child("node");
116 {
117 let uint_histogram = node.create_uint_exponential_histogram(
118 "uint-histogram",
119 ExponentialHistogramParams {
120 floor: 1,
121 initial_step: 1,
122 step_multiplier: 2,
123 buckets: 4,
124 },
125 );
126 uint_histogram.insert_multiple(0, 2); uint_histogram.insert(8);
128 uint_histogram.insert(500); uint_histogram.array.get_block::<_, Array<Uint>>(|block| {
130 for (i, value) in [1, 1, 2, 2, 0, 0, 0, 1, 1].iter().enumerate() {
131 assert_eq!(block.get(i).unwrap(), *value);
132 }
133 });
134
135 uint_histogram.clear();
136 uint_histogram.array.get_block::<_, Array<Uint>>(|block| {
137 for (i, value) in [1, 1, 2, 0, 0, 0, 0, 0, 0].iter().enumerate() {
138 assert_eq!(*value, block.get(i).unwrap());
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 overflow_underflow() {
153 let inspector = Inspector::default();
154 let root = inspector.root();
155 let hist = root.create_uint_exponential_histogram(
156 "test",
157 ExponentialHistogramParams {
158 floor: 1,
159 initial_step: u64::MAX / 2,
160 step_multiplier: 2,
161 buckets: 4,
162 },
163 );
164
165 hist.insert((u64::MAX / 2) + 1);
174 hist.insert(0);
175
176 hist.array.get_block::<_, Array<Uint>>(|block| {
177 assert_eq!(block.get(0).unwrap(), 1);
178 assert_eq!(block.get(1).unwrap(), u64::MAX / 2);
179 assert_eq!(block.get(2).unwrap(), 2);
180
181 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); });
188 }
189}