diff options
author | gennyble <gen@nyble.dev> | 2025-02-25 17:07:24 -0600 |
---|---|---|
committer | gennyble <gen@nyble.dev> | 2025-02-25 17:07:24 -0600 |
commit | f0595846660239fc6ac7aadca5d6b9d153f8d6c5 (patch) | |
tree | b46e03946e15c7bdc21daff824021f8b957d10ba /src | |
parent | e60e9fae45915a4ca4457dfdc9794980e373b1f1 (diff) | |
download | awake-f0595846660239fc6ac7aadca5d6b9d153f8d6c5.tar.gz awake-f0595846660239fc6ac7aadca5d6b9d153f8d6c5.zip |
Teach statistics graphs about time
Diffstat (limited to 'src')
-rw-r--r-- | src/db.rs | 1 | ||||
-rw-r--r-- | src/gatherer.rs | 72 | ||||
-rw-r--r-- | src/griph/mod.rs | 51 |
3 files changed, 91 insertions, 33 deletions
diff --git a/src/db.rs b/src/db.rs index d0a2c7d..f10f9ee 100644 --- a/src/db.rs +++ b/src/db.rs @@ -142,6 +142,7 @@ pub const CREATE_TABLE_HOSTNET: &'static str = "\ tx_delta INTEGER NOT NULL );"; +#[derive(Clone, Copy, Debug)] pub struct DbMeminfo { pub stamp: OffsetDateTime, pub total_kb: usize, diff --git a/src/gatherer.rs b/src/gatherer.rs index 9b2a80a..163d84b 100644 --- a/src/gatherer.rs +++ b/src/gatherer.rs @@ -1,4 +1,5 @@ use std::{ + array, fs::File, io::{BufRead, BufReader}, sync::{atomic::Ordering, mpsc::Sender}, @@ -9,7 +10,7 @@ use std::{ use regex_lite::Regex; use time::OffsetDateTime; -use crate::{griph, AwakeState}; +use crate::{db::DbMeminfo, griph, AwakeState}; pub struct Gatherer { state: AwakeState, @@ -97,7 +98,13 @@ pub fn make_mem_graph(state: &AwakeState) { let infos = state.database.get_last_n_host_meminfo(256); let max = infos[0].total_kb; - let mut usages: Vec<usize> = infos.into_iter().map(|mi| mi.usage()).collect(); + + let now = OffsetDateTime::now_utc(); + let cleaned = clean_series(&infos, |mem| mem.stamp, now); + let mut usages: Vec<Option<usize>> = cleaned + .into_iter() + .map(|mi| mi.map(|mi| mi.usage())) + .collect(); // Reversing here because we want latest valeus on on the // right side, so last in the array @@ -112,25 +119,32 @@ pub fn make_mem_graph(state: &AwakeState) { pub fn make_net_graph(state: &AwakeState) { tracing::debug!("generating netinfo graph"); + let now = OffsetDateTime::now_utc(); let infos = state.database.get_last_n_hostnet(256); + let cleaned = clean_series(&infos, |net| net.stamp, now); + // 125 is (1000 / 8) so it converst Bytes to kiloBITS - let mut rx_deltas: Vec<usize> = infos - .iter() - .map(|ni| ni.rx_bytes_per_sec() as usize / 124) - .collect(); - let mut tx_deltas: Vec<usize> = infos - .iter() - .map(|ni| ni.tx_bytes_per_sec() as usize / 125) - .collect(); + let mut rx_deltas = extract(&cleaned, |ni| ni.rx_bytes_per_sec() as usize / 125); + let mut tx_deltas = extract(&cleaned, |ni| ni.tx_bytes_per_sec() as usize / 125); // Reversing to put latest values on the right side rx_deltas.reverse(); tx_deltas.reverse(); + let rx_zeroed: Vec<usize> = cleaned + .iter() + .map(|m| m.map(|n| n.rx_bytes_per_sec() as usize / 125).unwrap_or(0)) + .collect(); + + let tx_zeroed: Vec<usize> = cleaned + .iter() + .map(|m| m.map(|n| n.tx_bytes_per_sec() as usize / 125).unwrap_or(0)) + .collect(); + // Mixing the TX/RX delta so we can pick a range. let mut mixed = vec![0; 512]; - mixed[..256].copy_from_slice(&rx_deltas); - mixed[256..].copy_from_slice(&tx_deltas); + mixed[..256].copy_from_slice(&rx_zeroed); + mixed[256..].copy_from_slice(&tx_zeroed); mixed.sort(); let kinda_highest = mixed[511 - 32]; @@ -145,6 +159,40 @@ pub fn make_net_graph(state: &AwakeState) { gif.save(path).unwrap(); } +fn clean_series<T, F>(series: &[T], time_extractor: F, end_time: OffsetDateTime) -> [Option<T>; 256] +where + F: Fn(&T) -> OffsetDateTime, + T: Clone, +{ + let mut res = [const { None }; 256]; + + for value in series { + let time = time_extractor(value); + let delta = end_time - time; + let mins = delta.whole_minutes(); + + if mins > 0 && mins < 256 { + res[mins as usize] = Some(value.clone()); + } + } + + res +} + +fn extract<T, F, V>(series: &[Option<T>], extractor: F) -> [Option<V>; 256] +where + F: Fn(&T) -> V, +{ + let mut res = [const { None }; 256]; + for (idx, maybe) in series.iter().enumerate() { + if let Some(value) = maybe { + res[idx] = Some(extractor(value)); + } + } + + res +} + pub struct Meminfo { pub total: usize, pub free: usize, diff --git a/src/griph/mod.rs b/src/griph/mod.rs index 6b84233..b1449f5 100644 --- a/src/griph/mod.rs +++ b/src/griph/mod.rs @@ -25,7 +25,7 @@ const WIDTH: usize = 256; const HEIGHT: usize = 160; const SIZE: usize = WIDTH * HEIGHT; -pub fn make_1line(min: usize, max: usize, values: &[usize]) -> Gif { +pub fn make_1line(min: usize, max: usize, values: &[Option<usize>]) -> Gif { let range = max - min; // this assumes a range of values that is >1 per pixel let vpp = range / HEIGHT; @@ -45,7 +45,12 @@ pub fn make_1line(min: usize, max: usize, values: &[usize]) -> Gif { standard } -pub fn make_2line(min: usize, max: usize, values1: &[usize], values2: &[usize]) -> Gif { +pub fn make_2line( + min: usize, + max: usize, + values1: &[Option<usize>], + values2: &[Option<usize>], +) -> Gif { let range = max - min; // this assumes a range of values that is >1 per pixel let vpp = range / HEIGHT; @@ -85,39 +90,43 @@ fn draw_grid(raster: &mut [u8]) { } } -fn draw_line(raster: &mut [u8], values: &[usize], vpp: usize, colour: u8) { +fn draw_line(raster: &mut [u8], values: &[Option<usize>], vpp: usize, colour: u8) { // Draw Line // this will be discontinuous and i think that's okay. we // could make it a proper line by keeping track what value // was last and drawing the whole vertical there - for (x, value) in values.iter().enumerate() { - let value_height = value / vpp; - if value_height > (HEIGHT - 1) { - continue; + for (x, maybe) in values.iter().enumerate() { + if let Some(value) = maybe { + let value_height = value / vpp; + if value_height > (HEIGHT - 1) { + continue; + } + let y_val = (HEIGHT - 1) - value_height; + + raster[y_val * WIDTH + x] = colour; } - let y_val = (HEIGHT - 1) - value_height; - - raster[y_val * WIDTH + x] = colour; } } fn draw_line_underfill( raster: &mut [u8], - values: &[usize], + values: &[Option<usize>], vpp: usize, colour: u8, colour_fill: u8, ) { - for (x, value) in values.iter().enumerate() { - let value_height = value / vpp; - if value_height > (HEIGHT - 1) { - continue; - } - let y_val = (HEIGHT - 1) - value_height; - - for y in y_val + 1..HEIGHT { - raster[y * WIDTH + x] = colour_fill; + for (x, maybe) in values.iter().enumerate() { + if let Some(value) = maybe { + let value_height = value / vpp; + if value_height > (HEIGHT - 1) { + continue; + } + let y_val = (HEIGHT - 1) - value_height; + + for y in y_val + 1..HEIGHT { + raster[y * WIDTH + x] = colour_fill; + } + raster[y_val * WIDTH + x] = colour; } - raster[y_val * WIDTH + x] = colour; } } |