1use std::io::Write;
2use std::sync::atomic::AtomicBool;
3use std::sync::atomic::Ordering;
4use std::sync::Arc;
5use std::time::Duration;
6
7use anyhow::Result;
8use scx_stats::prelude::*;
9use scx_stats_derive::stat_doc;
10use scx_stats_derive::Stats;
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 = "Direct dispatch due to high perf events (migration)")]
19 pub nr_event_dispatches: u64,
20 #[stat(desc = "Kept on same CPU due to perf sticky threshold")]
21 pub nr_ev_sticky_dispatches: u64,
22 #[stat(desc = "Direct dispatch due to GPU affinity")]
23 pub nr_gpu_dispatches: u64,
24}
25
26impl Metrics {
27 fn format<W: Write>(&self, w: &mut W) -> Result<()> {
28 writeln!(
29 w,
30 "[{}] ev_dispatches={} ev_sticky_dispatches={} gpu_dispatches={}",
31 crate::SCHEDULER_NAME,
32 self.nr_event_dispatches,
33 self.nr_ev_sticky_dispatches,
34 self.nr_gpu_dispatches,
35 )?;
36 Ok(())
37 }
38
39 fn delta(&self, rhs: &Self) -> Self {
40 Self {
41 nr_event_dispatches: self.nr_event_dispatches - rhs.nr_event_dispatches,
42 nr_ev_sticky_dispatches: self.nr_ev_sticky_dispatches - rhs.nr_ev_sticky_dispatches,
43 nr_gpu_dispatches: self.nr_gpu_dispatches - rhs.nr_gpu_dispatches,
44 }
45 }
46}
47
48pub fn server_data() -> StatsServerData<(), Metrics> {
49 let open: Box<dyn StatsOpener<(), Metrics>> = Box::new(move |(req_ch, res_ch)| {
50 req_ch.send(())?;
51 let mut prev = res_ch.recv()?;
52
53 let read: Box<dyn StatsReader<(), Metrics>> = Box::new(move |_args, (req_ch, res_ch)| {
54 req_ch.send(())?;
55 let cur = res_ch.recv()?;
56 let delta = cur.delta(&prev);
57 prev = cur;
58 delta.to_json()
59 });
60
61 Ok(read)
62 });
63
64 StatsServerData::new()
65 .add_meta(Metrics::meta())
66 .add_ops("top", StatsOps { open, close: None })
67}
68
69pub fn monitor(intv: Duration, shutdown: Arc<AtomicBool>) -> Result<()> {
70 scx_utils::monitor_stats::<Metrics>(
71 &[],
72 intv,
73 || shutdown.load(Ordering::Relaxed),
74 |metrics| metrics.format(&mut std::io::stdout()),
75 )
76}