scx_bpfland/
stats.rs

1use std::io::Write;
2use std::sync::Arc;
3use std::sync::atomic::AtomicBool;
4use std::sync::atomic::Ordering;
5use std::time::Duration;
6
7use anyhow::Result;
8use scx_stats::prelude::*;
9use scx_stats_derive::Stats;
10use scx_stats_derive::stat_doc;
11use serde::Deserialize;
12use serde::Serialize;
13
14#[stat_doc]
15#[derive(Clone, Debug, Default, Serialize, Deserialize, Stats)]
16#[stat(top)]
17pub struct Metrics {
18    #[stat(desc = "Number of running tasks")]
19    pub nr_running: u64,
20    #[stat(desc = "Number of online CPUs")]
21    pub nr_cpus: u64,
22    #[stat(desc = "Number of kthread direct dispatches")]
23    pub nr_kthread_dispatches: u64,
24    #[stat(desc = "Number of task direct dispatches")]
25    pub nr_direct_dispatches: u64,
26    #[stat(desc = "Number of regular task dispatches")]
27    pub nr_shared_dispatches: u64,
28}
29
30impl Metrics {
31    fn format<W: Write>(&self, w: &mut W) -> Result<()> {
32        writeln!(
33            w,
34            "[{}] tasks -> r: {:>2}/{:<2} | dispatch -> k: {:<5} d: {:<5} s: {:<5}",
35            crate::SCHEDULER_NAME,
36            self.nr_running,
37            self.nr_cpus,
38            self.nr_kthread_dispatches,
39            self.nr_direct_dispatches,
40            self.nr_shared_dispatches
41        )?;
42        Ok(())
43    }
44
45    fn delta(&self, rhs: &Self) -> Self {
46        Self {
47            nr_kthread_dispatches: self.nr_kthread_dispatches - rhs.nr_kthread_dispatches,
48            nr_direct_dispatches: self.nr_direct_dispatches - rhs.nr_direct_dispatches,
49            nr_shared_dispatches: self.nr_shared_dispatches - rhs.nr_shared_dispatches,
50            ..self.clone()
51        }
52    }
53}
54
55pub fn server_data() -> StatsServerData<(), Metrics> {
56    let open: Box<dyn StatsOpener<(), Metrics>> = Box::new(move |(req_ch, res_ch)| {
57        req_ch.send(())?;
58        let mut prev = res_ch.recv()?;
59
60        let read: Box<dyn StatsReader<(), Metrics>> = Box::new(move |_args, (req_ch, res_ch)| {
61            req_ch.send(())?;
62            let cur = res_ch.recv()?;
63            let delta = cur.delta(&prev);
64            prev = cur;
65            delta.to_json()
66        });
67
68        Ok(read)
69    });
70
71    StatsServerData::new()
72        .add_meta(Metrics::meta())
73        .add_ops("top", StatsOps { open, close: None })
74}
75
76pub fn monitor(intv: Duration, shutdown: Arc<AtomicBool>) -> Result<()> {
77    scx_utils::monitor_stats::<Metrics>(
78        &[],
79        intv,
80        || shutdown.load(Ordering::Relaxed),
81        |metrics| metrics.format(&mut std::io::stdout()),
82    )
83}