summaryrefslogtreecommitdiffstats
path: root/src/app
diff options
context:
space:
mode:
authorClement Tsang <34804052+ClementTsang@users.noreply.github.com>2020-12-21 20:24:27 -0500
committerGitHub <noreply@github.com>2020-12-21 20:24:27 -0500
commit837c382ee9461dfd7b80fecf8871bb762ae1e639 (patch)
treebbd8cf79e65ccdea916dbfdec7e89d68e7e31c4b /src/app
parente014d6fb783f9fc1c76f930ca4263ad6272a248b (diff)
refactor: Cut out sysinfo from Linux builds (#368)
Refactors to use only heim for Linux builds. This is now much easier to do since the 0.1 version of heim works fine for ARM. This is ideal since having to rely on two separate sources of data isn't the greatest if we can avoid it. Sysinfo is still required for macOS and Windows, though. Temperature sensors do not work for those from heim, and for some reason, networks also don't work on Windows with heim...? My personal CPU core calculation is also currently Linux-only, and as such, I'll still rely on sysinfo for Windows and macOS for now. This isn't really a big optimization or anything btw. Just something I wanted to try.
Diffstat (limited to 'src/app')
-rw-r--r--src/app/data_harvester.rs80
-rw-r--r--src/app/data_harvester/cpu.rs163
2 files changed, 223 insertions, 20 deletions
diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs
index cff9bc2e..63d9a07c 100644
--- a/src/app/data_harvester.rs
+++ b/src/app/data_harvester.rs
@@ -5,6 +5,7 @@ use std::time::Instant;
#[cfg(target_os = "linux")]
use fnv::FnvHashMap;
+#[cfg(not(target_os = "linux"))]
use sysinfo::{System, SystemExt};
use battery::{Battery, Manager};
@@ -71,8 +72,13 @@ impl Data {
#[derive(Debug)]
pub struct DataCollector {
pub data: Data,
+ #[cfg(not(target_os = "linux"))]
sys: System,
#[cfg(target_os = "linux")]
+ previous_cpu_times: Vec<(cpu::PastCpuWork, cpu::PastCpuTotal)>,
+ #[cfg(target_os = "linux")]
+ previous_average_cpu_time: Option<(cpu::PastCpuWork, cpu::PastCpuTotal)>,
+ #[cfg(target_os = "linux")]
pid_mapping: FnvHashMap<crate::Pid, processes::PrevProcDetails>,
#[cfg(target_os = "linux")]
prev_idle: f64,
@@ -97,8 +103,13 @@ impl Default for DataCollector {
// trace!("Creating default data collector...");
DataCollector {
data: Data::default(),
+ #[cfg(not(target_os = "linux"))]
sys: System::new_with_specifics(sysinfo::RefreshKind::new()), // FIXME: Make this run on only macOS and Windows.
#[cfg(target_os = "linux")]
+ previous_cpu_times: vec![],
+ #[cfg(target_os = "linux")]
+ previous_average_cpu_time: None,
+ #[cfg(target_os = "linux")]
pid_mapping: FnvHashMap::default(),
#[cfg(target_os = "linux")]
prev_idle: 0_f64,
@@ -127,17 +138,24 @@ impl Default for DataCollector {
impl DataCollector {
pub fn init(&mut self) {
- self.sys.refresh_memory();
- self.mem_total_kb = self.sys.get_total_memory();
-
- // Refresh components list once...
- if self.widgets_to_harvest.use_temp {
- self.sys.refresh_components_list();
+ #[cfg(target_os = "linux")]
+ {
+ futures::executor::block_on(self.initialize_memory_size());
}
+ #[cfg(not(target_os = "linux"))]
+ {
+ self.sys.refresh_memory();
+ self.mem_total_kb = self.sys.get_total_memory();
+
+ // Refresh components list once...
+ if self.widgets_to_harvest.use_temp {
+ self.sys.refresh_components_list();
+ }
- // Refresh network list once...
- if cfg!(target_os = "windows") && self.widgets_to_harvest.use_net {
- self.sys.refresh_networks_list();
+ // Refresh network list once...
+ if cfg!(target_os = "windows") && self.widgets_to_harvest.use_net {
+ self.sys.refresh_networks_list();
+ }
}
if self.widgets_to_harvest.use_battery {
@@ -164,6 +182,15 @@ impl DataCollector {
// trace!("Enabled widgets to harvest: {:#?}", self.widgets_to_harvest);
}
+ #[cfg(target_os = "linux")]
+ async fn initialize_memory_size(&mut self) {
+ self.mem_total_kb = if let Ok(mem) = heim::memory::memory().await {
+ mem.total().get::<heim::units::information::kilobyte>()
+ } else {
+ 1
+ };
+ }
+
pub fn set_collected_data(&mut self, used_widgets: UsedWidgets) {
self.widgets_to_harvest = used_widgets;
}
@@ -181,27 +208,44 @@ impl DataCollector {
}
pub async fn update_data(&mut self) {
- if self.widgets_to_harvest.use_cpu {
- self.sys.refresh_cpu();
- }
-
- if cfg!(not(target_os = "linux")) {
+ #[cfg(not(target_os = "linux"))]
+ {
+ if self.widgets_to_harvest.use_cpu {
+ self.sys.refresh_cpu();
+ }
if self.widgets_to_harvest.use_proc {
self.sys.refresh_processes();
}
if self.widgets_to_harvest.use_temp {
self.sys.refresh_components();
}
- }
- if cfg!(target_os = "windows") && self.widgets_to_harvest.use_net {
- self.sys.refresh_networks();
+
+ if cfg!(target_os = "windows") && self.widgets_to_harvest.use_net {
+ self.sys.refresh_networks();
+ }
}
let current_instant = std::time::Instant::now();
// CPU
if self.widgets_to_harvest.use_cpu {
- self.data.cpu = Some(cpu::get_cpu_data_list(&self.sys, self.show_average_cpu));
+ #[cfg(not(target_os = "linux"))]
+ {
+ self.data.cpu = Some(cpu::get_cpu_data_list(&self.sys, self.show_average_cpu));
+ }
+
+ #[cfg(target_os = "linux")]
+ {
+ if let Ok(cpu_data) = cpu::get_cpu_data_list(
+ self.show_average_cpu,
+ &mut self.previous_cpu_times,
+ &mut self.previous_average_cpu_time,
+ )
+ .await
+ {
+ self.data.cpu = Some(cpu_data);
+ }
+ }
}
// Batteries
diff --git a/src/app/data_harvester/cpu.rs b/src/app/data_harvester/cpu.rs
index bf6bf6e2..c154cfa1 100644
--- a/src/app/data_harvester/cpu.rs
+++ b/src/app/data_harvester/cpu.rs
@@ -1,5 +1,3 @@
-use sysinfo::{ProcessorExt, System, SystemExt};
-
#[derive(Default, Debug, Clone)]
pub struct CpuData {
pub cpu_prefix: String,
@@ -9,6 +7,13 @@ pub struct CpuData {
pub type CpuHarvest = Vec<CpuData>;
+pub type PastCpuWork = f64;
+pub type PastCpuTotal = f64;
+
+#[cfg(not(target_os = "linux"))]
+use sysinfo::{ProcessorExt, System, SystemExt};
+
+#[cfg(not(target_os = "linux"))]
pub fn get_cpu_data_list(sys: &System, show_average_cpu: bool) -> CpuHarvest {
let cpu_data = sys.get_processors();
let avg_cpu_usage = sys.get_global_processor_info().get_cpu_usage();
@@ -32,3 +37,157 @@ pub fn get_cpu_data_list(sys: &System, show_average_cpu: bool) -> CpuHarvest {
cpu_vec
}
+
+#[cfg(target_os = "linux")]
+pub async fn get_cpu_data_list(
+ show_average_cpu: bool, previous_cpu_times: &mut Vec<(PastCpuWork, PastCpuTotal)>,
+ previous_average_cpu_time: &mut Option<(PastCpuWork, PastCpuTotal)>,
+) -> crate::error::Result<CpuHarvest> {
+ use futures::StreamExt;
+ use heim::cpu::os::linux::CpuTimeExt;
+ use std::collections::VecDeque;
+
+ fn convert_cpu_times(cpu_time: &heim::cpu::CpuTime) -> (f64, f64) {
+ let working_time: f64 = (cpu_time.user()
+ + cpu_time.nice()
+ + cpu_time.system()
+ + cpu_time.irq()
+ + cpu_time.soft_irq()
+ + cpu_time.steal())
+ .get::<heim::units::time::second>();
+ (
+ working_time,
+ working_time
+ + (cpu_time.idle() + cpu_time.io_wait()).get::<heim::units::time::second>(),
+ )
+ }
+
+ fn calculate_cpu_usage_percentage(
+ (previous_working_time, previous_total_time): (f64, f64),
+ (current_working_time, current_total_time): (f64, f64),
+ ) -> f64 {
+ ((if current_working_time > previous_working_time {
+ current_working_time - previous_working_time
+ } else {
+ 0.0
+ }) * 100.0)
+ / (if current_total_time > previous_total_time {
+ current_total_time - previous_total_time
+ } else {
+ 1.0
+ })
+ }
+
+ // Get all CPU times...
+ let cpu_times = heim::cpu::times().await?;
+ futures::pin_mut!(cpu_times);
+
+ let mut cpu_deque: VecDeque<CpuData> = if previous_cpu_times.is_empty() {
+ // Must initialize ourselves. Use a very quick timeout to calculate an initial.
+ futures_timer::Delay::new(std::time::Duration::from_millis(100)).await;
+
+ let second_cpu_times = heim::cpu::times().await?;
+ futures::pin_mut!(second_cpu_times);
+
+ let mut new_cpu_times: Vec<(PastCpuWork, PastCpuTotal)> = Vec::new();
+ let mut cpu_deque: VecDeque<CpuData> = VecDeque::new();
+ let mut collected_zip = cpu_times.zip(second_cpu_times).enumerate(); // Gotta move it here, can't on while line.
+
+ while let Some((itx, (past, present))) = collected_zip.next().await {
+ if let (Ok(past), Ok(present)) = (past, present) {
+ let present_times = convert_cpu_times(&present);
+ new_cpu_times.push(present_times);
+ cpu_deque.push_back(CpuData {
+ cpu_prefix: "CPU".to_string(),
+ cpu_count: Some(itx),
+ cpu_usage: calculate_cpu_usage_percentage(
+ convert_cpu_times(&past),
+ present_times,
+ ),
+ });
+ } else {
+ new_cpu_times.push((0.0, 0.0));
+ cpu_deque.push_back(CpuData {
+ cpu_prefix: "CPU".to_string(),
+ cpu_count: Some(itx),
+ cpu_usage: 0.0,
+ });
+ }
+ }
+
+ *previous_cpu_times = new_cpu_times;
+ cpu_deque
+ } else {
+ let (new_cpu_times, cpu_deque): (Vec<(PastCpuWork, PastCpuTotal)>, VecDeque<CpuData>) =
+ cpu_times
+ .collect::<Vec<_>>()
+ .await
+ .iter()
+ .zip(&*previous_cpu_times)
+ .enumerate()
+ .map(|(itx, (current_cpu, (past_cpu_work, past_cpu_total)))| {
+ if let Ok(cpu_time) = current_cpu {
+ let present_times = convert_cpu_times(&cpu_time);
+
+ (
+ present_times,
+ CpuData {
+ cpu_prefix: "CPU".to_string(),
+ cpu_count: Some(itx),
+ cpu_usage: calculate_cpu_usage_percentage(
+ (*past_cpu_work, *past_cpu_total),
+ present_times,
+ ),
+ },
+ )
+ } else {
+ (
+ (*past_cpu_work, *past_cpu_total),
+ CpuData {
+ cpu_prefix: "CPU".to_string(),
+ cpu_count: Some(itx),
+ cpu_usage: 0.0,
+ },
+ )
+ }
+ })
+ .unzip();
+
+ *previous_cpu_times = new_cpu_times;
+ cpu_deque
+ };
+
+ // Get average CPU if needed... and slap it at the top
+ if show_average_cpu {
+ let cpu_time = heim::cpu::time().await?;
+
+ let (cpu_usage, new_average_cpu_time) = if let Some((past_cpu_work, past_cpu_total)) =
+ previous_average_cpu_time
+ {
+ let present_times = convert_cpu_times(&cpu_time);
+ (
+ calculate_cpu_usage_percentage((*past_cpu_work, *past_cpu_total), present_times),
+ present_times,
+ )
+ } else {
+ // Again, we need to do a quick timeout...
+ futures_timer::Delay::new(std::time::Duration::from_millis(100)).await;
+ let second_cpu_time = heim::cpu::time().await?;
+
+ let present_times = convert_cpu_times(&second_cpu_time);
+ (
+ calculate_cpu_usage_percentage(convert_cpu_times(&cpu_time), present_times),
+ present_times,
+ )
+ };
+
+ *previous_average_cpu_time = Some(new_average_cpu_time);
+ cpu_deque.push_front(CpuData {
+ cpu_prefix: "AVG".to_string(),
+ cpu_count: None,
+ cpu_usage,
+ })
+ }
+
+ Ok(Vec::from(cpu_deque))
+}