scx_rustland/
stats.rs

1use std::io::Write;
2use std::time::Duration;
3
4use anyhow::Result;
5use scx_stats::prelude::*;
6use scx_stats_derive::Stats;
7use scx_stats_derive::stat_doc;
8use serde::Deserialize;
9use serde::Serialize;
10
11#[stat_doc]
12#[derive(Clone, Debug, Default, Serialize, Deserialize, Stats)]
13#[stat(top)]
14pub struct Metrics {
15    #[stat(desc = "Number of online CPUs")]
16    pub nr_cpus: u64,
17    #[stat(desc = "Amount of tasks currently running")]
18    pub nr_running: u64,
19    #[stat(desc = "Amount of tasks queued to the user-space scheduler")]
20    pub nr_queued: u64,
21    #[stat(desc = "Amount of tasks in the user-space scheduler waiting to be dispatched")]
22    pub nr_scheduled: u64,
23    #[stat(desc = "Amount of user-space scheduler's page faults (should be always 0)")]
24    pub nr_page_faults: u64,
25    #[stat(desc = "Number of task dispatched by the user-space scheduler")]
26    pub nr_user_dispatches: u64,
27    #[stat(desc = "Number of task dispatched directly by the kernel")]
28    pub nr_kernel_dispatches: u64,
29    #[stat(desc = "Number of cancelled dispatches")]
30    pub nr_cancel_dispatches: u64,
31    #[stat(desc = "Number of dispatches bounced to another DSQ")]
32    pub nr_bounce_dispatches: u64,
33    #[stat(desc = "Number of failed dispatches")]
34    pub nr_failed_dispatches: u64,
35    #[stat(desc = "Number of scheduler congestion events")]
36    pub nr_sched_congested: u64,
37}
38
39impl Metrics {
40    fn format<W: Write>(&self, w: &mut W) -> Result<()> {
41        writeln!(
42            w,
43            "[{}] tasks -> r: {:>2}/{:<2} w: {:<2}/{:<2} | pf: {:<5} | dispatch -> u: {:<5} k: {:<5} c: {:<5} b: {:<5} f: {:<5} | cg: {:<5}",
44            crate::SCHEDULER_NAME,
45            self.nr_running,
46            self.nr_cpus,
47            self.nr_queued,
48            self.nr_scheduled,
49            self.nr_page_faults,
50            self.nr_user_dispatches,
51            self.nr_kernel_dispatches,
52            self.nr_cancel_dispatches,
53            self.nr_bounce_dispatches,
54            self.nr_failed_dispatches,
55            self.nr_sched_congested,
56        )?;
57        Ok(())
58    }
59
60    fn delta(&self, rhs: &Self) -> Self {
61        Self {
62            nr_user_dispatches: self.nr_user_dispatches - rhs.nr_user_dispatches,
63            nr_kernel_dispatches: self.nr_kernel_dispatches - rhs.nr_kernel_dispatches,
64            nr_cancel_dispatches: self.nr_cancel_dispatches - rhs.nr_cancel_dispatches,
65            nr_bounce_dispatches: self.nr_bounce_dispatches - rhs.nr_bounce_dispatches,
66            nr_failed_dispatches: self.nr_failed_dispatches - rhs.nr_failed_dispatches,
67            nr_sched_congested: self.nr_sched_congested - rhs.nr_sched_congested,
68            ..self.clone()
69        }
70    }
71}
72
73pub fn server_data() -> StatsServerData<(), Metrics> {
74    let open: Box<dyn StatsOpener<(), Metrics>> = Box::new(move |(req_ch, res_ch)| {
75        req_ch.send(())?;
76        let mut prev = res_ch.recv()?;
77
78        let read: Box<dyn StatsReader<(), Metrics>> = Box::new(move |_args, (req_ch, res_ch)| {
79            req_ch.send(())?;
80            let cur = res_ch.recv()?;
81            let delta = cur.delta(&prev);
82            prev = cur;
83            delta.to_json()
84        });
85
86        Ok(read)
87    });
88
89    StatsServerData::new()
90        .add_meta(Metrics::meta())
91        .add_ops("top", StatsOps { open, close: None })
92}
93
94pub fn monitor(intv: Duration) -> Result<()> {
95    scx_utils::monitor_stats::<Metrics>(
96        &vec![],
97        intv,
98        || false,
99        |metrics| metrics.format(&mut std::io::stdout()),
100    )
101}