mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-25 13:40:20 +00:00
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.
This commit is contained in:
parent
e014d6fb78
commit
837c382ee9
5 changed files with 265 additions and 27 deletions
27
Cargo.lock
generated
27
Cargo.lock
generated
|
@ -249,6 +249,7 @@ dependencies = [
|
|||
"fern",
|
||||
"fnv",
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"heim",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
|
@ -671,6 +672,12 @@ version = "0.23.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.9.1"
|
||||
|
@ -684,6 +691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b8a653442b9bdd11a77d3753a60443c60c4437d3acac8e6c3d4a6a9acd7cceed"
|
||||
dependencies = [
|
||||
"heim-common",
|
||||
"heim-cpu",
|
||||
"heim-disk",
|
||||
"heim-memory",
|
||||
"heim-net",
|
||||
|
@ -710,6 +718,25 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heim-cpu"
|
||||
version = "0.1.0-rc.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ba5fb13a3b90581d22b4edf99e87c54316444622ae123d36816a227a7caa6df"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"futures",
|
||||
"glob",
|
||||
"heim-common",
|
||||
"heim-runtime",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"mach",
|
||||
"ntapi",
|
||||
"smol",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heim-disk"
|
||||
version = "0.1.0-rc.1"
|
||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -42,7 +42,6 @@ fnv = "1.0.7"
|
|||
futures = "0.3.8"
|
||||
indexmap = "~1.6"
|
||||
itertools = "0.9.0"
|
||||
libc = "~0.2"
|
||||
once_cell = "1.5.2"
|
||||
regex = "1.4.2"
|
||||
serde = { version = "~1.0", features = ["derive"] }
|
||||
|
@ -54,13 +53,22 @@ typed-builder = "0.8.0"
|
|||
unicode-segmentation = "1.7.1"
|
||||
unicode-width = "0.1"
|
||||
|
||||
# For debugging only...
|
||||
# For debugging only... disable on release builds with --no-default-target for no? TODO: Redo this.
|
||||
fern = { version = "0.6.0", optional=true }
|
||||
log = { version="0.4.11", optional=true }
|
||||
log = { version = "0.4.11", optional=true }
|
||||
|
||||
heim = { version = "0.1.0-rc.1", features = ["disk", "memory", "net", "sensors"] }
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "~0.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
heim = { version = "0.1.0-rc.1", features = ["cpu", "disk", "memory", "net", "sensors"] }
|
||||
futures-timer = "3.0.2"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
heim = { version = "0.1.0-rc.1", features = ["disk", "memory", "net"] }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
heim = { version = "0.1.0-rc.1", features = ["disk", "memory"] }
|
||||
winapi = "0.3.9"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -65,10 +65,10 @@ A cross-platform graphical process/system monitor with a customizable interface
|
|||
Note that bottom is:
|
||||
|
||||
- Built on the stable version of Rust
|
||||
- Officially tested and released for only `x86_64` (and `i686` for Windows)
|
||||
- Officially tested and released for only `x86_64` (and `i686` for Windows and Linux)
|
||||
- Developed mainly for macOS, Windows, and Linux
|
||||
|
||||
Anything outside of this (i.e: ARM builds, building on Nightly, building on another OS) is currently not guaranteed, even if it does happen to work. For example, ARM is compiled on the CI pipeline and release builds will be provided, but not all features may work (such as R/s and W/s for disks).
|
||||
Anything outside of this (i.e: ARM builds, building on Nightly, building on another OS) is currently not guaranteed, even if it does happen to work. For example, ARM is compiled on the CI pipeline and release builds will be provided, but not all features may necessarily work. Feel free to file any ARM-related bugs, but know I might not be able to fix them.
|
||||
|
||||
### Manually
|
||||
|
||||
|
|
|
@ -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 network list once...
|
||||
if cfg!(target_os = "windows") && self.widgets_to_harvest.use_net {
|
||||
self.sys.refresh_networks_list();
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue