about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorgennyble <gen@nyble.dev>2025-02-25 17:07:24 -0600
committergennyble <gen@nyble.dev>2025-02-25 17:07:24 -0600
commitf0595846660239fc6ac7aadca5d6b9d153f8d6c5 (patch)
treeb46e03946e15c7bdc21daff824021f8b957d10ba /src
parente60e9fae45915a4ca4457dfdc9794980e373b1f1 (diff)
downloadawake-f0595846660239fc6ac7aadca5d6b9d153f8d6c5.tar.gz
awake-f0595846660239fc6ac7aadca5d6b9d153f8d6c5.zip
Teach statistics graphs about time
Diffstat (limited to 'src')
-rw-r--r--src/db.rs1
-rw-r--r--src/gatherer.rs72
-rw-r--r--src/griph/mod.rs51
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;
 	}
 }