fuchsia_inspect_contrib/nodes/
mod.rs1use fuchsia_inspect::{InspectType, IntProperty, Node, Property};
8use std::borrow::Cow;
9use std::{fmt, marker};
10pub use zx::{BootTimeline, MonotonicTimeline};
11
12mod dedupe_log;
13mod list;
14mod lru_cache;
15
16pub use dedupe_log::DedupeLogNode;
17pub use list::BoundedListNode;
18pub use lru_cache::LruCacheNode;
19
20pub trait GetCurrentTime: zx::Timeline + Sized {
22 fn get_current_time() -> zx::Instant<Self>;
23}
24
25impl GetCurrentTime for zx::MonotonicTimeline {
26 fn get_current_time() -> zx::MonotonicInstant {
27 zx::MonotonicInstant::get()
28 }
29}
30
31impl GetCurrentTime for zx::BootTimeline {
32 fn get_current_time() -> zx::BootInstant {
33 zx::BootInstant::get()
34 }
35}
36
37pub struct CreateTimeResult<T> {
39 pub timestamp: zx::Instant<T>,
41 pub property: TimeProperty<T>,
43}
44
45pub trait NodeTimeExt<T: zx::Timeline> {
47 fn create_time<'a>(&self, name: impl Into<Cow<'a, str>>) -> CreateTimeResult<T>;
50
51 fn create_time_at<'a>(
53 &self,
54 name: impl Into<Cow<'a, str>>,
55 timestamp: zx::Instant<T>,
56 ) -> TimeProperty<T>;
57
58 fn record_time<'a>(&self, name: impl Into<Cow<'a, str>>) -> zx::Instant<T>;
61}
62
63impl<T> NodeTimeExt<T> for Node
64where
65 T: zx::Timeline + GetCurrentTime,
66{
67 fn create_time<'a>(&self, name: impl Into<Cow<'a, str>>) -> CreateTimeResult<T> {
68 let timestamp = T::get_current_time();
69 CreateTimeResult { timestamp, property: self.create_time_at(name, timestamp) }
70 }
71
72 fn create_time_at<'a>(
73 &self,
74 name: impl Into<Cow<'a, str>>,
75 timestamp: zx::Instant<T>,
76 ) -> TimeProperty<T> {
77 TimeProperty {
78 inner: self.create_int(name, timestamp.into_nanos()),
79 _phantom: marker::PhantomData,
80 }
81 }
82
83 fn record_time<'a>(&self, name: impl Into<Cow<'a, str>>) -> zx::Instant<T> {
84 let instant = T::get_current_time();
85 self.record_int(name, instant.into_nanos());
86 instant
87 }
88}
89
90#[derive(Debug)]
92pub struct TimeProperty<T> {
93 pub(crate) inner: IntProperty,
94 _phantom: marker::PhantomData<T>,
95}
96
97impl<T> TimeProperty<T>
98where
99 T: zx::Timeline + GetCurrentTime,
100{
101 pub fn update(&self) {
103 self.set_at(T::get_current_time());
104 }
105
106 pub fn set_at(&self, timestamp: zx::Instant<T>) {
108 Property::set(&self.inner, timestamp.into_nanos());
109 }
110}
111
112pub type BootTimeProperty = TimeProperty<zx::BootTimeline>;
114
115pub type MonotonicTimeProperty = TimeProperty<zx::MonotonicTimeline>;
117
118impl<T: fmt::Debug + Send + Sync> InspectType for TimeProperty<T> {}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use diagnostics_assertions::{AnyProperty, PropertyAssertion, assert_data_tree};
124 use fuchsia_inspect::{DiagnosticsHierarchyGetter, Inspector};
125 use test_util::assert_lt;
126
127 #[fuchsia::test]
128 async fn test_time_metadata_format() {
129 let inspector = Inspector::default();
130
131 let time_property = inspector
132 .root()
133 .create_time_at("time", zx::MonotonicInstant::from_nanos(123_456_700_000));
134 let t1 = validate_inspector_get_time(&inspector, 123_456_700_000i64).await;
135
136 time_property.set_at(zx::MonotonicInstant::from_nanos(333_005_000_000));
137 let t2 = validate_inspector_get_time(&inspector, 333_005_000_000i64).await;
138
139 time_property.set_at(zx::MonotonicInstant::from_nanos(333_444_000_000));
140 let t3 = validate_inspector_get_time(&inspector, 333_444_000_000i64).await;
141
142 assert_lt!(t1, t2);
143 assert_lt!(t2, t3);
144 }
145
146 #[fuchsia::test]
147 async fn test_create_time_and_update() {
148 let inspector = Inspector::default();
149 let CreateTimeResult { timestamp: recorded_t1, property: time_property }: CreateTimeResult<
150 zx::MonotonicTimeline,
151 > = inspector.root().create_time("time");
152 let t1 = validate_inspector_get_time(&inspector, AnyProperty).await;
153 assert_eq!(recorded_t1.into_nanos(), t1);
154
155 time_property.update();
156 let t2 = validate_inspector_get_time(&inspector, AnyProperty).await;
157
158 time_property.update();
159 let t3 = validate_inspector_get_time(&inspector, AnyProperty).await;
160
161 assert_lt!(t1, t2);
162 assert_lt!(t2, t3);
163 }
164
165 #[fuchsia::test]
166 async fn test_record_time() {
167 let before_time = zx::MonotonicInstant::get().into_nanos();
168 let inspector = Inspector::default();
169 NodeTimeExt::<zx::MonotonicTimeline>::record_time(inspector.root(), "time");
170 let after_time = validate_inspector_get_time(&inspector, AnyProperty).await;
171 assert_lt!(before_time, after_time);
172 }
173
174 #[fuchsia::test]
175 fn test_create_time_no_executor() {
176 let inspector = Inspector::default();
177 let _: CreateTimeResult<zx::MonotonicTimeline> = inspector.root().create_time("time");
178 }
179
180 #[fuchsia::test]
181 fn test_record_time_no_executor() {
182 let inspector = Inspector::default();
183 NodeTimeExt::<zx::MonotonicTimeline>::record_time(inspector.root(), "time");
184 }
185
186 async fn validate_inspector_get_time<T>(inspector: &Inspector, expected: T) -> i64
187 where
188 T: PropertyAssertion<String> + 'static,
189 {
190 let hierarchy = inspector.get_diagnostics_hierarchy().await;
191 assert_data_tree!(hierarchy, root: { time: expected });
192 hierarchy.get_property("time").and_then(|t| t.int()).unwrap()
193 }
194}