1use std::io::Write;
9use std::sync::Arc;
10use std::sync::atomic::AtomicBool;
11use std::sync::atomic::Ordering;
12use std::time::Duration;
13
14use anyhow::Result;
15use scx_stats::prelude::*;
16use scx_stats_derive::Stats;
17use scx_stats_derive::stat_doc;
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 ticks")]
26 pub nr_ticks: u64,
27 #[stat(desc = "Number of preemption events")]
28 pub nr_preemptions: u64,
29 #[stat(desc = "Number of dispatches directly consumed from the shared queue")]
30 pub nr_direct_dispatches: u64,
31 #[stat(desc = "Number of dispatches routed by the primary CPUs")]
32 pub nr_primary_dispatches: u64,
33 #[stat(desc = "Number of dispatches routed by the primary CPU timers")]
34 pub nr_timer_dispatches: u64,
35}
36
37impl Metrics {
38 fn format<W: Write>(&self, w: &mut W) -> Result<()> {
39 writeln!(
40 w,
41 "[{}] ticks -> {:<5} preempts -> {:<5} dispatch -> d: {:<5} p: {:<5} t: {:<5}",
42 crate::SCHEDULER_NAME,
43 self.nr_ticks,
44 self.nr_preemptions,
45 self.nr_direct_dispatches,
46 self.nr_primary_dispatches,
47 self.nr_timer_dispatches
48 )?;
49 Ok(())
50 }
51
52 fn delta(&self, rhs: &Self) -> Self {
53 Self {
54 nr_ticks: self.nr_ticks - rhs.nr_ticks,
55 nr_preemptions: self.nr_preemptions - rhs.nr_preemptions,
56 nr_direct_dispatches: self.nr_direct_dispatches - rhs.nr_direct_dispatches,
57 nr_primary_dispatches: self.nr_primary_dispatches - rhs.nr_primary_dispatches,
58 nr_timer_dispatches: self.nr_timer_dispatches - rhs.nr_timer_dispatches,
59 ..self.clone()
60 }
61 }
62}
63
64pub fn server_data() -> StatsServerData<(), Metrics> {
65 let open: Box<dyn StatsOpener<(), Metrics>> = Box::new(move |(req_ch, res_ch)| {
66 req_ch.send(())?;
67 let mut prev = res_ch.recv()?;
68
69 let read: Box<dyn StatsReader<(), Metrics>> = Box::new(move |_args, (req_ch, res_ch)| {
70 req_ch.send(())?;
71 let cur = res_ch.recv()?;
72 let delta = cur.delta(&prev);
73 prev = cur;
74 delta.to_json()
75 });
76
77 Ok(read)
78 });
79
80 StatsServerData::new()
81 .add_meta(Metrics::meta())
82 .add_ops("top", StatsOps { open, close: None })
83}
84
85pub fn monitor(intv: Duration, shutdown: Arc<AtomicBool>) -> Result<()> {
86 scx_utils::monitor_stats::<Metrics>(
87 &[],
88 intv,
89 || shutdown.load(Ordering::Relaxed),
90 |metrics| metrics.format(&mut std::io::stdout()),
91 )
92}