mirror of
https://github.com/ClementTsang/bottom
synced 2025-02-17 05:38:27 +00:00
feature: Add support for displaying load average (#392)
This commit is contained in:
parent
fd41c1367c
commit
d8f8a92b55
7 changed files with 79 additions and 3 deletions
|
@ -16,8 +16,9 @@ use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use std::{time::Instant, vec::Vec};
|
use std::{time::Instant, vec::Vec};
|
||||||
|
|
||||||
|
use crate::app::data_harvester::load_avg::LoadAvgHarvest;
|
||||||
use crate::{
|
use crate::{
|
||||||
data_harvester::{batteries, cpu, disks, mem, network, processes, temperature, Data},
|
data_harvester::{batteries, cpu, disks, load_avg, mem, network, processes, temperature, Data},
|
||||||
utils::gen_util::get_simple_byte_values,
|
utils::gen_util::get_simple_byte_values,
|
||||||
};
|
};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -30,6 +31,7 @@ pub struct TimedData {
|
||||||
pub rx_data: Value,
|
pub rx_data: Value,
|
||||||
pub tx_data: Value,
|
pub tx_data: Value,
|
||||||
pub cpu_data: Vec<Value>,
|
pub cpu_data: Vec<Value>,
|
||||||
|
pub load_avg_data: [f32; 3],
|
||||||
pub mem_data: Option<Value>,
|
pub mem_data: Option<Value>,
|
||||||
pub swap_data: Option<Value>,
|
pub swap_data: Option<Value>,
|
||||||
}
|
}
|
||||||
|
@ -52,6 +54,7 @@ pub struct DataCollection {
|
||||||
pub memory_harvest: mem::MemHarvest,
|
pub memory_harvest: mem::MemHarvest,
|
||||||
pub swap_harvest: mem::MemHarvest,
|
pub swap_harvest: mem::MemHarvest,
|
||||||
pub cpu_harvest: cpu::CpuHarvest,
|
pub cpu_harvest: cpu::CpuHarvest,
|
||||||
|
pub load_avg_harvest: load_avg::LoadAvgHarvest,
|
||||||
pub process_harvest: Vec<processes::ProcessHarvest>,
|
pub process_harvest: Vec<processes::ProcessHarvest>,
|
||||||
pub disk_harvest: Vec<disks::DiskHarvest>,
|
pub disk_harvest: Vec<disks::DiskHarvest>,
|
||||||
pub io_harvest: disks::IOHarvest,
|
pub io_harvest: disks::IOHarvest,
|
||||||
|
@ -71,6 +74,7 @@ impl Default for DataCollection {
|
||||||
memory_harvest: mem::MemHarvest::default(),
|
memory_harvest: mem::MemHarvest::default(),
|
||||||
swap_harvest: mem::MemHarvest::default(),
|
swap_harvest: mem::MemHarvest::default(),
|
||||||
cpu_harvest: cpu::CpuHarvest::default(),
|
cpu_harvest: cpu::CpuHarvest::default(),
|
||||||
|
load_avg_harvest: load_avg::LoadAvgHarvest::default(),
|
||||||
process_harvest: Vec::default(),
|
process_harvest: Vec::default(),
|
||||||
disk_harvest: Vec::default(),
|
disk_harvest: Vec::default(),
|
||||||
io_harvest: disks::IOHarvest::default(),
|
io_harvest: disks::IOHarvest::default(),
|
||||||
|
@ -143,6 +147,11 @@ impl DataCollection {
|
||||||
self.eat_cpu(cpu, &mut new_entry);
|
self.eat_cpu(cpu, &mut new_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load Average
|
||||||
|
if let Some(load_avg) = harvested_data.load_avg {
|
||||||
|
self.eat_load_avg(load_avg, &mut new_entry);
|
||||||
|
}
|
||||||
|
|
||||||
// Temp
|
// Temp
|
||||||
if let Some(temperature_sensors) = harvested_data.temperature_sensors {
|
if let Some(temperature_sensors) = harvested_data.temperature_sensors {
|
||||||
self.eat_temp(temperature_sensors);
|
self.eat_temp(temperature_sensors);
|
||||||
|
@ -228,6 +237,12 @@ impl DataCollection {
|
||||||
self.cpu_harvest = cpu.to_vec();
|
self.cpu_harvest = cpu.to_vec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eat_load_avg(&mut self, load_avg: LoadAvgHarvest, new_entry: &mut TimedData) {
|
||||||
|
new_entry.load_avg_data = load_avg;
|
||||||
|
|
||||||
|
self.load_avg_harvest = load_avg;
|
||||||
|
}
|
||||||
|
|
||||||
fn eat_temp(&mut self, temperature_sensors: Vec<temperature::TempHarvest>) {
|
fn eat_temp(&mut self, temperature_sensors: Vec<temperature::TempHarvest>) {
|
||||||
// trace!("Eating temps.");
|
// trace!("Eating temps.");
|
||||||
// TODO: [PO] To implement
|
// TODO: [PO] To implement
|
||||||
|
|
|
@ -19,6 +19,7 @@ use super::DataFilters;
|
||||||
pub mod batteries;
|
pub mod batteries;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod disks;
|
pub mod disks;
|
||||||
|
pub mod load_avg;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod processes;
|
pub mod processes;
|
||||||
|
@ -28,6 +29,7 @@ pub mod temperature;
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
pub last_collection_time: Instant,
|
pub last_collection_time: Instant,
|
||||||
pub cpu: Option<cpu::CpuHarvest>,
|
pub cpu: Option<cpu::CpuHarvest>,
|
||||||
|
pub load_avg: Option<load_avg::LoadAvgHarvest>,
|
||||||
pub memory: Option<mem::MemHarvest>,
|
pub memory: Option<mem::MemHarvest>,
|
||||||
pub swap: Option<mem::MemHarvest>,
|
pub swap: Option<mem::MemHarvest>,
|
||||||
pub temperature_sensors: Option<Vec<temperature::TempHarvest>>,
|
pub temperature_sensors: Option<Vec<temperature::TempHarvest>>,
|
||||||
|
@ -43,6 +45,7 @@ impl Default for Data {
|
||||||
Data {
|
Data {
|
||||||
last_collection_time: Instant::now(),
|
last_collection_time: Instant::now(),
|
||||||
cpu: None,
|
cpu: None,
|
||||||
|
load_avg: None,
|
||||||
memory: None,
|
memory: None,
|
||||||
swap: None,
|
swap: None,
|
||||||
temperature_sensors: None,
|
temperature_sensors: None,
|
||||||
|
@ -64,6 +67,7 @@ impl Data {
|
||||||
self.memory = None;
|
self.memory = None;
|
||||||
self.swap = None;
|
self.swap = None;
|
||||||
self.cpu = None;
|
self.cpu = None;
|
||||||
|
self.load_avg = None;
|
||||||
|
|
||||||
if let Some(network) = &mut self.network {
|
if let Some(network) = &mut self.network {
|
||||||
network.first_run_cleanup();
|
network.first_run_cleanup();
|
||||||
|
@ -248,6 +252,14 @@ impl DataCollector {
|
||||||
self.data.cpu = Some(cpu_data);
|
self.data.cpu = Some(cpu_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
{
|
||||||
|
// Load Average
|
||||||
|
if let Ok(load_avg_data) = load_avg::get_load_avg().await {
|
||||||
|
self.data.load_avg = Some(load_avg_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Batteries
|
// Batteries
|
||||||
|
|
12
src/app/data_harvester/load_avg.rs
Normal file
12
src/app/data_harvester/load_avg.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
pub type LoadAvgHarvest = [f32; 3];
|
||||||
|
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
pub async fn get_load_avg() -> crate::error::Result<LoadAvgHarvest> {
|
||||||
|
let (one, five, fifteen) = heim::cpu::os::unix::loadavg().await?;
|
||||||
|
|
||||||
|
Ok([
|
||||||
|
one.get::<heim::units::ratio::ratio>(),
|
||||||
|
five.get::<heim::units::ratio::ratio>(),
|
||||||
|
fifteen.get::<heim::units::ratio::ratio>(),
|
||||||
|
])
|
||||||
|
}
|
|
@ -222,6 +222,7 @@ fn main() -> Result<()> {
|
||||||
&mut app.canvas_data.cpu_data,
|
&mut app.canvas_data.cpu_data,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
app.canvas_data.load_avg_data = app.data_collection.load_avg_harvest;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processes
|
// Processes
|
||||||
|
|
|
@ -56,6 +56,7 @@ pub struct DisplayableData {
|
||||||
|
|
||||||
pub mem_data: Vec<Point>,
|
pub mem_data: Vec<Point>,
|
||||||
pub swap_data: Vec<Point>,
|
pub swap_data: Vec<Point>,
|
||||||
|
pub load_avg_data: [f32; 3],
|
||||||
pub cpu_data: Vec<ConvertedCpuData>,
|
pub cpu_data: Vec<ConvertedCpuData>,
|
||||||
pub battery_data: Vec<ConvertedBatteryData>,
|
pub battery_data: Vec<ConvertedBatteryData>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,8 +247,42 @@ impl CpuGraphWidget for Painter {
|
||||||
self.colours.border_style
|
self.colours.border_style
|
||||||
};
|
};
|
||||||
|
|
||||||
let title = if app_state.is_expanded {
|
let title = if cfg!(target_family = "unix") {
|
||||||
|
let load_avg = app_state.canvas_data.load_avg_data;
|
||||||
|
let load_avg_str = format!(
|
||||||
|
"─ {:.2} {:.2} {:.2} ",
|
||||||
|
load_avg[0], load_avg[1], load_avg[2]
|
||||||
|
);
|
||||||
|
let load_avg_str_size =
|
||||||
|
UnicodeSegmentation::graphemes(load_avg_str.as_str(), true).count();
|
||||||
|
|
||||||
|
if app_state.is_expanded {
|
||||||
const TITLE_BASE: &str = " CPU ── Esc to go back ";
|
const TITLE_BASE: &str = " CPU ── Esc to go back ";
|
||||||
|
|
||||||
|
Spans::from(vec![
|
||||||
|
Span::styled(" CPU ", self.colours.widget_title_style),
|
||||||
|
Span::styled(load_avg_str, self.colours.widget_title_style),
|
||||||
|
Span::styled(
|
||||||
|
format!(
|
||||||
|
"─{}─ Esc to go back ",
|
||||||
|
"─".repeat(usize::from(draw_loc.width).saturating_sub(
|
||||||
|
load_avg_str_size
|
||||||
|
+ UnicodeSegmentation::graphemes(TITLE_BASE, true).count()
|
||||||
|
+ 2
|
||||||
|
))
|
||||||
|
),
|
||||||
|
border_style,
|
||||||
|
),
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
Spans::from(vec![
|
||||||
|
Span::styled(" CPU ", self.colours.widget_title_style),
|
||||||
|
Span::styled(load_avg_str, self.colours.widget_title_style),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
} else if app_state.is_expanded {
|
||||||
|
const TITLE_BASE: &str = " CPU ── Esc to go back ";
|
||||||
|
|
||||||
Spans::from(vec![
|
Spans::from(vec![
|
||||||
Span::styled(" CPU ", self.colours.widget_title_style),
|
Span::styled(" CPU ", self.colours.widget_title_style),
|
||||||
Span::styled(
|
Span::styled(
|
||||||
|
@ -262,7 +296,7 @@ impl CpuGraphWidget for Painter {
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
Spans::from(Span::styled(" CPU ", self.colours.widget_title_style))
|
Spans::from(vec![Span::styled(" CPU ", self.colours.widget_title_style)])
|
||||||
};
|
};
|
||||||
|
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
|
|
|
@ -315,6 +315,7 @@ pub fn handle_force_redraws(app: &mut App) {
|
||||||
&mut app.canvas_data.cpu_data,
|
&mut app.canvas_data.cpu_data,
|
||||||
app.is_frozen,
|
app.is_frozen,
|
||||||
);
|
);
|
||||||
|
app.canvas_data.load_avg_data = app.data_collection.load_avg_harvest;
|
||||||
app.cpu_state.force_update = None;
|
app.cpu_state.force_update = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue