diagnostics/task_metrics/
component_stats.rs1use crate::task_metrics::measurement::Measurement;
6use crate::task_metrics::runtime_stats_source::RuntimeStatsSource;
7use crate::task_metrics::task_info::TaskInfo;
8use fuchsia_inspect as inspect;
9use futures::lock::Mutex;
10use std::fmt::Debug;
11use std::sync::Arc;
12
13pub struct ComponentStats<T: RuntimeStatsSource + Debug> {
15 tasks: Vec<Arc<Mutex<TaskInfo<T>>>>,
16}
17
18impl<T: 'static + RuntimeStatsSource + Debug + Send + Sync> ComponentStats<T> {
19 pub fn new() -> Self {
21 Self { tasks: vec![] }
22 }
23
24 pub async fn add_task(&mut self, task: Arc<Mutex<TaskInfo<T>>>) {
26 self.tasks.push(task);
27 }
28
29 pub async fn is_alive(&self) -> bool {
34 let mut any_task_alive = false;
35 for task in &self.tasks {
36 if task.lock().await.is_alive().await {
37 any_task_alive = true;
38 }
39 }
40 any_task_alive
41 }
42
43 pub async fn measure(&mut self) -> Measurement {
48 let mut result = Measurement::default();
49 for task in self.tasks.iter_mut() {
50 if let Some(measurement) = task.lock().await.measure_if_no_parent().await {
51 result += measurement;
52 }
53 }
54
55 result
56 }
57
58 pub async fn measure_tracked_dead_tasks(&self) -> Measurement {
61 let mut result = Measurement::default();
62
63 for task in self.tasks.iter() {
64 let locked_task = task.lock().await;
65
66 if locked_task.measurements.no_true_measurements() {
68 continue;
69 }
70
71 if let Some(m) = locked_task.exited_cpu().await {
72 result += m;
73 }
74 }
75
76 result
77 }
78
79 pub async fn clean_stale(&mut self) -> (Vec<zx::sys::zx_koid_t>, Measurement) {
85 let mut deleted_koids = vec![];
86 let mut final_tasks = vec![];
87 let mut exited_cpu_time = Measurement::default();
88 while let Some(task) = self.tasks.pop() {
89 let (is_alive, koid) = {
90 let task_guard = task.lock().await;
91 (task_guard.is_alive().await, task_guard.koid())
92 };
93
94 if is_alive {
95 final_tasks.push(task);
96 } else {
97 deleted_koids.push(koid);
98 let locked_task = task.lock().await;
99 if let Some(m) = locked_task.exited_cpu().await {
100 exited_cpu_time += m;
101 }
102 }
103 }
104 self.tasks = final_tasks;
105 (deleted_koids, exited_cpu_time)
106 }
107
108 pub async fn remove_by_koids(&mut self, remove: &[zx::sys::zx_koid_t]) {
109 let mut final_tasks = vec![];
110 while let Some(task) = self.tasks.pop() {
111 let task_koid = task.lock().await.koid();
112 if !remove.contains(&task_koid) {
113 final_tasks.push(task)
114 }
115 }
116
117 self.tasks = final_tasks;
118 }
119
120 pub async fn gather_dead_tasks(&self) -> Vec<(zx::BootInstant, Arc<Mutex<TaskInfo<T>>>)> {
121 let mut dead_tasks = vec![];
122 for task in &self.tasks {
123 if let Some(t) = task.lock().await.most_recent_measurement().await {
124 dead_tasks.push((t, task.clone()));
125 }
126 }
127
128 dead_tasks
129 }
130
131 pub async fn record_to_node(&self, node: &inspect::Node) -> u64 {
134 for task in &self.tasks {
135 task.lock().await.record_to_node(&node);
136 }
137 self.tasks.len() as u64
138 }
139
140 #[cfg(test)]
141 pub async fn total_measurements(&self) -> usize {
142 let mut sum = 0;
143 for task in &self.tasks {
144 sum += task.lock().await.total_measurements();
145 }
146 sum
147 }
148
149 #[cfg(test)]
150 pub fn tasks_mut(&mut self) -> &mut [Arc<Mutex<TaskInfo<T>>>] {
151 &mut self.tasks
152 }
153}