Skip to main content

scx_cidland/
stats.rs

1// SPDX-License-Identifier: GPL-2.0
2//
3// Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
4//
5// This software may be used and distributed according to the terms of the
6// GNU General Public License version 2.
7
8use std::io::Write;
9use std::sync::atomic::AtomicBool;
10use std::sync::atomic::Ordering;
11use std::sync::Arc;
12use std::time::Duration;
13
14use anyhow::Result;
15use scx_stats::prelude::*;
16use scx_stats_derive::stat_doc;
17use scx_stats_derive::Stats;
18use serde::Deserialize;
19use serde::Serialize;
20
21#[stat_doc]
22#[derive(Clone, Debug, Default, Serialize, Deserialize, Stats)]
23#[stat(top)]
24pub struct Metrics {
25    #[stat(desc = "Number of tasks dispatched directly to an idle cid")]
26    pub nr_direct_dispatches: u64,
27    #[stat(desc = "Number of tasks queued to the shared FIFO")]
28    pub nr_shared_enqueues: u64,
29    #[stat(desc = "Number of idle cids kicked to consume the shared FIFO")]
30    pub nr_idle_kicks: u64,
31    #[stat(desc = "Number of idle cids picked in the previous LLC")]
32    pub nr_local_llc: u64,
33    #[stat(desc = "Number of idle cids picked outside of the previous LLC")]
34    pub nr_remote_llc: u64,
35}
36
37impl Metrics {
38    fn format<W: Write>(&self, w: &mut W) -> Result<()> {
39        writeln!(
40            w,
41            "[{}] dispatch -> direct: {:<7} shared: {:<7} kicks: {:<7} | idle cid -> local llc: {:<7} remote llc: {:<7}",
42            crate::SCHEDULER_NAME,
43            self.nr_direct_dispatches,
44            self.nr_shared_enqueues,
45            self.nr_idle_kicks,
46            self.nr_local_llc,
47            self.nr_remote_llc,
48        )?;
49        Ok(())
50    }
51
52    fn delta(&self, rhs: &Self) -> Self {
53        Self {
54            nr_direct_dispatches: self.nr_direct_dispatches - rhs.nr_direct_dispatches,
55            nr_shared_enqueues: self.nr_shared_enqueues - rhs.nr_shared_enqueues,
56            nr_idle_kicks: self.nr_idle_kicks - rhs.nr_idle_kicks,
57            nr_local_llc: self.nr_local_llc - rhs.nr_local_llc,
58            nr_remote_llc: self.nr_remote_llc - rhs.nr_remote_llc,
59        }
60    }
61}
62
63pub fn server_data() -> StatsServerData<(), Metrics> {
64    let open: Box<dyn StatsOpener<(), Metrics>> = Box::new(move |(req_ch, res_ch)| {
65        req_ch.send(())?;
66        let mut prev = res_ch.recv()?;
67
68        let read: Box<dyn StatsReader<(), Metrics>> = Box::new(move |_args, (req_ch, res_ch)| {
69            req_ch.send(())?;
70            let cur = res_ch.recv()?;
71            let delta = cur.delta(&prev);
72            prev = cur;
73            delta.to_json()
74        });
75
76        Ok(read)
77    });
78
79    StatsServerData::new()
80        .add_meta(Metrics::meta())
81        .add_ops("top", StatsOps { open, close: None })
82}
83
84pub fn monitor(intv: Duration, shutdown: Arc<AtomicBool>) -> Result<()> {
85    scx_utils::monitor_stats::<Metrics>(
86        &[],
87        intv,
88        || shutdown.load(Ordering::Relaxed),
89        |metrics| metrics.format(&mut std::io::stdout()),
90    )
91}