Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_sys/src/snapshot.rs

3.7 KiB, 1 run

created by r1870400018:10594, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! Aggregate [`Snapshot`] grouping every metric module.
2//!
3//! Producers call [`Snapshot::sample`] on a regular cadence; two
4//! consecutive snapshots can be compared via [`Snapshot::delta`]
5//! to derive rate-based figures (CPU busy percentage, disk
6//! throughput, network throughput) without each consumer having
7//! to juggle separate prev/curr pairs.
8
9use crate::{
10 cpu::CpuTimes,
11 disk::{
12 DiskDelta,
13 DiskStats,
14 },
15 load::LoadAvg,
16 mem::MemInfo,
17 net::{
18 NetDelta,
19 NetStats,
20 },
21 proc_self::ProcSelf,
22 uptime::Uptime,
23};
24
25use oxedyne_fe2o3_core::prelude::*;
26
27/// One host-stats reading. Fields are captured independently, so
28/// a failure in any single `/proc` file surfaces as the crate
29/// error for that file; no partial snapshots.
30#[derive(Clone, Debug, Default)]
31pub struct Snapshot {
32 /// Monotonic timestamp, nanoseconds since an arbitrary epoch
33 /// (typically Instant::now() mapped to an integer). Stored as
34 /// plain `u64` so [`Snapshot`] remains `Default`-able and
35 /// trivially serialisable.
36 pub monotonic_ns: u64,
37 /// Aggregate CPU time counters.
38 pub cpu: CpuTimes,
39 /// Memory figures.
40 pub mem: MemInfo,
41 /// Load averages.
42 pub load: LoadAvg,
43 /// Per-device block I/O counters.
44 pub disk: DiskStats,
45 /// Per-interface network counters.
46 pub net: NetStats,
47 /// Uptime counters.
48 pub uptime: Uptime,
49 /// Current process footprint.
50 pub proc_self:ProcSelf,
51}
52
53impl Snapshot {
54 /// Take a fresh reading. Any `/proc` read failure aborts the
55 /// snapshot and is returned; callers deciding whether to
56 /// retry should inspect the error kind.
57 pub fn sample() -> Outcome<Self> {
58 Ok(Self {
59 monotonic_ns: now_ns(),
60 cpu: res!(CpuTimes::sample()),
61 mem: res!(MemInfo::sample()),
62 load: res!(LoadAvg::sample()),
63 disk: res!(DiskStats::sample()),
64 net: res!(NetStats::sample()),
65 uptime: res!(Uptime::sample()),
66 proc_self: res!(ProcSelf::sample()),
67 })
68 }
69
70 /// Elapsed wall-clock seconds between `prev` and `self`,
71 /// derived from the `monotonic_ns` fields.
72 pub fn elapsed_since(&self, prev: &Self) -> f64 {
73 if self.monotonic_ns <= prev.monotonic_ns {
74 return 0.0;
75 }
76 (self.monotonic_ns - prev.monotonic_ns) as f64 / 1_000_000_000.0
77 }
78
79 /// Derive rate-based figures from the difference between
80 /// this snapshot and `prev`.
81 pub fn delta(&self, prev: &Self) -> SnapshotDelta {
82 let elapsed = self.elapsed_since(prev);
83 SnapshotDelta {
84 elapsed_s: elapsed,
85 cpu_busy: self.cpu.busy_fraction(&prev.cpu),
86 disk: self.disk.deltas(&prev.disk, elapsed),
87 net: self.net.deltas(&prev.net, elapsed),
88 }
89 }
90}
91
92/// Rate-based figures computed between two snapshots.
93#[derive(Clone, Debug, Default)]
94pub struct SnapshotDelta {
95 /// Elapsed wall-clock seconds between samples.
96 pub elapsed_s: f64,
97 /// CPU busy fraction (0..=1) over the interval.
98 pub cpu_busy: f64,
99 /// Per-device I/O rates.
100 pub disk: Vec<DiskDelta>,
101 /// Per-interface network rates.
102 pub net: Vec<NetDelta>,
103}
104
105/// Nanoseconds since an arbitrary monotonic epoch. Uses
106/// `std::time::Instant::now()` elapsed against a process-lifetime
107/// base captured on first call.
108fn now_ns() -> u64 {
109 use std::{
110 sync::OnceLock,
111 time::Instant,
112 };
113 static START: OnceLock<Instant> = OnceLock::new();
114 let start = START.get_or_init(Instant::now);
115 start.elapsed().as_nanos() as u64
116}