diagnostics/task_metrics/
component_stats.rsuse crate::task_metrics::measurement::Measurement;
use crate::task_metrics::runtime_stats_source::RuntimeStatsSource;
use crate::task_metrics::task_info::TaskInfo;
use fuchsia_inspect as inspect;
use futures::lock::Mutex;
use std::fmt::Debug;
use std::sync::Arc;
pub struct ComponentStats<T: RuntimeStatsSource + Debug> {
tasks: Vec<Arc<Mutex<TaskInfo<T>>>>,
}
impl<T: 'static + RuntimeStatsSource + Debug + Send + Sync> ComponentStats<T> {
pub fn new() -> Self {
Self { tasks: vec![] }
}
pub async fn add_task(&mut self, task: Arc<Mutex<TaskInfo<T>>>) {
self.tasks.push(task);
}
pub async fn is_alive(&self) -> bool {
let mut any_task_alive = false;
for task in &self.tasks {
if task.lock().await.is_alive().await {
any_task_alive = true;
}
}
any_task_alive
}
pub async fn measure(&mut self) -> Measurement {
let mut result = Measurement::default();
for task in self.tasks.iter_mut() {
if let Some(measurement) = task.lock().await.measure_if_no_parent().await {
result += measurement;
}
}
result
}
pub async fn measure_tracked_dead_tasks(&self) -> Measurement {
let mut result = Measurement::default();
for task in self.tasks.iter() {
let locked_task = task.lock().await;
if locked_task.measurements.no_true_measurements() {
continue;
}
if let Some(m) = locked_task.exited_cpu().await {
result += m;
}
}
result
}
pub async fn clean_stale(&mut self) -> (Vec<zx::sys::zx_koid_t>, Measurement) {
let mut deleted_koids = vec![];
let mut final_tasks = vec![];
let mut exited_cpu_time = Measurement::default();
while let Some(task) = self.tasks.pop() {
let (is_alive, koid) = {
let task_guard = task.lock().await;
(task_guard.is_alive().await, task_guard.koid())
};
if is_alive {
final_tasks.push(task);
} else {
deleted_koids.push(koid);
let locked_task = task.lock().await;
if let Some(m) = locked_task.exited_cpu().await {
exited_cpu_time += m;
}
}
}
self.tasks = final_tasks;
(deleted_koids, exited_cpu_time)
}
pub async fn remove_by_koids(&mut self, remove: &[zx::sys::zx_koid_t]) {
let mut final_tasks = vec![];
while let Some(task) = self.tasks.pop() {
let task_koid = task.lock().await.koid();
if !remove.contains(&task_koid) {
final_tasks.push(task)
}
}
self.tasks = final_tasks;
}
pub async fn gather_dead_tasks(&self) -> Vec<(zx::BootInstant, Arc<Mutex<TaskInfo<T>>>)> {
let mut dead_tasks = vec![];
for task in &self.tasks {
if let Some(t) = task.lock().await.most_recent_measurement().await {
dead_tasks.push((t, task.clone()));
}
}
dead_tasks
}
pub async fn record_to_node(&self, node: &inspect::Node) -> u64 {
for task in &self.tasks {
task.lock().await.record_to_node(&node);
}
self.tasks.len() as u64
}
#[cfg(test)]
pub async fn total_measurements(&self) -> usize {
let mut sum = 0;
for task in &self.tasks {
sum += task.lock().await.total_measurements();
}
sum
}
#[cfg(test)]
pub fn tasks_mut(&mut self) -> &mut [Arc<Mutex<TaskInfo<T>>>] {
&mut self.tasks
}
}