mz_metrics/
rusage.rs
1use std::time::Duration;
9
10use mz_ore::cast::CastFrom;
11use mz_ore::metrics::MetricsRegistry;
12use prometheus::{Gauge, IntGauge};
13
14use crate::MetricsUpdate;
15
16macro_rules! metrics {
17 ($namespace:ident $(($name:ident, $desc:expr, $suffix:expr, $type:ident)),*) => {
18 metrics! { @define $namespace $(($name, $desc, $suffix, $type)),*}
19 };
20 (@define $namespace:ident $(($name:ident, $desc:expr, $suffix:expr, $type:ident)),*) => {
21 pub(crate) struct RuMetrics {
22 $($name: <$type as Unit>::Gauge,)*
23 }
24 impl RuMetrics {
25 fn new(registry: &MetricsRegistry) -> Self {
26 Self {
27 $($name: registry.register(mz_ore::metric!(
28 name: concat!(stringify!($namespace), "_", stringify!($name), $suffix),
29 help: $desc,
30 )),)*
31 }
32 }
33 fn update_internal(&self) -> Result<(), std::io::Error> {
34 let rusage = unsafe {
35 let mut rusage = std::mem::zeroed();
36 let ret = libc::getrusage(libc::RUSAGE_SELF, &mut rusage);
37 if ret < 0 {
38 return Err(std::io::Error::last_os_error());
39 }
40 rusage
41 };
42 $(self.$name.set(<$type as Unit>::from(rusage.$name));)*
43 Ok(())
44 }
45 }
46 };
47}
48
49trait Unit {
51 type Gauge;
53 type From;
55 type To;
57 fn from(value: Self::From) -> Self::To;
59}
60
61struct Timeval;
63impl Unit for Timeval {
64 type Gauge = Gauge;
65 type From = libc::timeval;
66 type To = f64;
67 fn from(Self::From { tv_sec, tv_usec }: Self::From) -> Self::To {
68 (Duration::from_secs(u64::cast_from(tv_sec.abs_diff(0)))
70 + Duration::from_micros(u64::cast_from(tv_usec.abs_diff(0))))
71 .as_secs_f64()
72 }
73}
74
75struct Unitless;
77impl Unit for Unitless {
78 type Gauge = IntGauge;
79 type From = libc::c_long;
80 type To = i64;
81 fn from(value: Self::From) -> Self::To {
82 value
83 }
84}
85
86struct MaxrssToBytes;
92impl Unit for MaxrssToBytes {
93 type Gauge = IntGauge;
94 type From = libc::c_long;
95 type To = i64;
96
97 #[cfg(not(target_os = "macos"))]
98 fn from(value: Self::From) -> Self::To {
99 value.saturating_mul(1024)
100 }
101
102 #[cfg(target_os = "macos")]
103 fn from(value: Self::From) -> Self::To {
104 value
105 }
106}
107
108metrics! {
109 mz_metrics_libc
110 (ru_utime, "user CPU time used", "_seconds_total", Timeval),
111 (ru_stime, "system CPU time used", "_seconds_total", Timeval),
112 (ru_maxrss, "maximum resident set size", "_bytes", MaxrssToBytes),
113 (ru_minflt, "page reclaims (soft page faults)", "_total", Unitless),
114 (ru_majflt, "page faults (hard page faults)", "_total", Unitless),
115 (ru_inblock, "block input operations", "_total", Unitless),
116 (ru_oublock, "block output operations", "_total", Unitless),
117 (ru_nvcsw, "voluntary context switches", "_total", Unitless),
118 (ru_nivcsw, "involuntary context switches", "_total", Unitless)
119}
120
121pub(crate) fn register_metrics_into(metrics_registry: &MetricsRegistry) -> RuMetrics {
123 RuMetrics::new(metrics_registry)
124}
125
126impl MetricsUpdate for RuMetrics {
127 type Error = std::io::Error;
128 const NAME: &'static str = "rusage";
129 fn update(&mut self) -> Result<(), Self::Error> {
130 self.update_internal()
131 }
132}