1use 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}