summaryrefslogtreecommitdiffstats
path: root/src/app/data_harvester/memory/general.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/data_harvester/memory/general.rs')
-rw-r--r--src/app/data_harvester/memory/general.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/app/data_harvester/memory/general.rs b/src/app/data_harvester/memory/general.rs
new file mode 100644
index 00000000..4af287d7
--- /dev/null
+++ b/src/app/data_harvester/memory/general.rs
@@ -0,0 +1,121 @@
+//! Data collection for memory via heim.
+
+#[derive(Debug, Clone, Default)]
+pub struct MemHarvest {
+ pub mem_total_in_kib: u64,
+ pub mem_used_in_kib: u64,
+ pub use_percent: Option<f64>,
+}
+
+pub async fn get_mem_data(
+ actually_get: bool,
+) -> (
+ crate::utils::error::Result<Option<MemHarvest>>,
+ crate::utils::error::Result<Option<MemHarvest>>,
+) {
+ use futures::join;
+
+ if !actually_get {
+ (Ok(None), Ok(None))
+ } else {
+ join!(get_ram_data(), get_swap_data())
+ }
+}
+
+pub async fn get_ram_data() -> crate::utils::error::Result<Option<MemHarvest>> {
+ let (mem_total_in_kib, mem_used_in_kib) = {
+ #[cfg(target_os = "linux")]
+ {
+ let mem_info = procfs::Meminfo::new()?;
+
+ // Let's preface this by saying that memory usage calculations are... not straightforward.
+ // There are conflicting implementations everywhere.
+ //
+ // Now that we've added this preface (mainly for future reference), the current implementation below for usage
+ // is based on htop's calculation formula. See
+ // https://github.com/htop-dev/htop/blob/976c6123f41492aaf613b9d172eef1842fb7b0a3/linux/LinuxProcessList.c#L1584
+ // for implementation details as of writing.
+ //
+ // Another implementation, commonly used in other things, is to skip the shmem part of the calculation,
+ // which matches gopsutil and stuff like free.
+
+ let total = mem_info.mem_total / 1024;
+ let cached_mem =
+ mem_info.cached + mem_info.s_reclaimable.unwrap_or(0) - mem_info.shmem.unwrap_or(0);
+ let used_diff = (mem_info.mem_free + cached_mem + mem_info.buffers) / 1024;
+ let used = if total >= used_diff {
+ total - used_diff
+ } else {
+ total - mem_info.mem_free
+ };
+
+ (total, used)
+ }
+ #[cfg(target_os = "macos")]
+ {
+ let memory = heim::memory::memory().await?;
+
+ use heim::memory::os::macos::MemoryExt;
+ use heim::units::information::kibibyte;
+ (
+ memory.total().get::<kibibyte>(),
+ memory.active().get::<kibibyte>() + memory.wire().get::<kibibyte>(),
+ )
+ }
+ #[cfg(target_os = "windows")]
+ {
+ let memory = heim::memory::memory().await?;
+
+ use heim::units::information::kibibyte;
+ let mem_total_in_kib = memory.total().get::<kibibyte>();
+ (
+ mem_total_in_kib,
+ mem_total_in_kib - memory.available().get::<kibibyte>(),
+ )
+ }
+ };
+
+ Ok(Some(MemHarvest {
+ mem_total_in_kib,
+ mem_used_in_kib,
+ use_percent: if mem_total_in_kib == 0 {
+ None
+ } else {
+ Some(mem_used_in_kib as f64 / mem_total_in_kib as f64 * 100.0)
+ },
+ }))
+}
+
+pub async fn get_swap_data() -> crate::utils::error::Result<Option<MemHarvest>> {
+ let memory = heim::memory::swap().await?;
+
+ let (mem_total_in_kib, mem_used_in_kib) = {
+ #[cfg(target_os = "linux")]
+ {
+ // Similar story to above - heim parses this information incorrectly as far as I can tell, so kilobytes = kibibytes here.
+ use heim::units::information::kilobyte;
+ (
+ memory.total().get::<kilobyte>(),
+ memory.used().get::<kilobyte>(),
+ )
+ }
+ #[cfg(any(target_os = "windows", target_os = "macos"))]
+ {
+ use heim::units::information::kibibyte;
+ (
+ memory.total().get::<kibibyte>(),
+ memory.used().get::<kibibyte>(),
+ )
+ }
+ };
+
+ Ok(Some(MemHarvest {
+ mem_total_in_kib,
+ mem_used_in_kib,
+ use_percent: if mem_total_in_kib == 0 {
+ None
+ } else {
+ Some(mem_used_in_kib as f64 / mem_total_in_kib as f64 * 100.0)
+ },
+ }))
+}