fuchsia_inspect/writer/types/
int_linear_histogram.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::writer::{
6    ArithmeticArrayProperty, ArrayProperty, HistogramProperty, InspectType, IntArrayProperty, Node,
7};
8use diagnostics_hierarchy::{ArrayFormat, LinearHistogramParams};
9use log::error;
10use std::borrow::Cow;
11
12#[derive(Debug, Default)]
13/// A linear histogram property for integer values.
14pub struct IntLinearHistogramProperty {
15    array: IntArrayProperty,
16    floor: i64,
17    buckets: usize,
18    step_size: i64,
19}
20
21impl InspectType for IntLinearHistogramProperty {}
22
23impl IntLinearHistogramProperty {
24    pub(crate) fn new(
25        name: Cow<'_, str>,
26        params: LinearHistogramParams<i64>,
27        parent: &Node,
28    ) -> Self {
29        let slots = params.buckets + ArrayFormat::LinearHistogram.extra_slots();
30        let array = parent.create_int_array_internal(name, slots, ArrayFormat::LinearHistogram);
31        array.set(0, params.floor);
32        array.set(1, params.step_size);
33        Self { floor: params.floor, step_size: params.step_size, buckets: params.buckets, array }
34    }
35
36    fn get_index(&self, value: i64) -> usize {
37        let mut current_floor = self.floor;
38        let mut index = ArrayFormat::LinearHistogram.underflow_bucket_index();
39        let overflow_index = ArrayFormat::LinearHistogram.overflow_bucket_index(self.buckets);
40        while value >= current_floor && index < overflow_index {
41            current_floor += self.step_size;
42            index += 1;
43        }
44        index
45    }
46}
47
48impl HistogramProperty for IntLinearHistogramProperty {
49    type Type = i64;
50
51    fn insert(&self, value: i64) {
52        self.insert_multiple(value, 1);
53    }
54
55    fn insert_multiple(&self, value: i64, count: usize) {
56        self.array.add(self.get_index(value), count as i64);
57    }
58
59    fn clear(&self) {
60        if let Some(ref inner_ref) = self.array.inner.inner_ref() {
61            // Ensure we don't delete the array slots that contain histogram metadata.
62            inner_ref
63                .state
64                .try_lock()
65                .and_then(|mut state| {
66                    // Clear histogram buckets starting at first bucket, which
67                    // is the underflow bucket.
68                    state.clear_array(
69                        inner_ref.block_index,
70                        ArrayFormat::LinearHistogram.underflow_bucket_index(),
71                    )
72                })
73                .unwrap_or_else(|err| {
74                    error!(err:?; "Failed to clear property");
75                });
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use crate::writer::Inspector;
84    use crate::writer::testing_utils::GetBlockExt;
85    use inspect_format::{Array, Int};
86
87    #[fuchsia::test]
88    fn int_linear_histogram() {
89        let inspector = Inspector::default();
90        let root = inspector.root();
91        let node = root.create_child("node");
92        {
93            let int_histogram = node.create_int_linear_histogram(
94                "int-histogram",
95                LinearHistogramParams { floor: 10, step_size: 5, buckets: 5 },
96            );
97            int_histogram.insert_multiple(-1, 2); // underflow
98            int_histogram.insert(25);
99            int_histogram.insert(500); // overflow
100            int_histogram.array.get_block::<_, Array<Int>>(|block| {
101                for (i, value) in [10, 5, 2, 0, 0, 0, 1, 0, 1].iter().enumerate() {
102                    assert_eq!(block.get(i).unwrap(), *value);
103                }
104            });
105
106            node.get_block::<_, inspect_format::Node>(|node_block| {
107                assert_eq!(node_block.child_count(), 1);
108            });
109        }
110        node.get_block::<_, inspect_format::Node>(|node_block| {
111            assert_eq!(node_block.child_count(), 0);
112        });
113    }
114}