feature: add gpu ram collector for nvidia feature flag (#794)
* add gpu ram collector for nvidia feature flag * add row for TX in basic layout * size gpu point_vec * use vec for mem basic widget drawing * remove to_owned * code review: change mem tuple to struct with cfg fields, rename mem_basic ratio and use vec macro for layout * build on freebsd
This commit is contained in:
parent
41970d9c64
commit
bd35bbdc9c
|
@ -43,6 +43,8 @@ pub struct TimedData {
|
|||
pub swap_data: Option<Value>,
|
||||
#[cfg(feature = "zfs")]
|
||||
pub arc_data: Option<Value>,
|
||||
#[cfg(feature = "gpu")]
|
||||
pub gpu_data: Vec<Option<Value>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -133,6 +135,8 @@ pub struct DataCollection {
|
|||
pub battery_harvest: Vec<batteries::BatteryHarvest>,
|
||||
#[cfg(feature = "zfs")]
|
||||
pub arc_harvest: memory::MemHarvest,
|
||||
#[cfg(feature = "gpu")]
|
||||
pub gpu_harvest: Vec<(String, memory::MemHarvest)>,
|
||||
}
|
||||
|
||||
impl Default for DataCollection {
|
||||
|
@ -155,6 +159,8 @@ impl Default for DataCollection {
|
|||
battery_harvest: Vec::default(),
|
||||
#[cfg(feature = "zfs")]
|
||||
arc_harvest: memory::MemHarvest::default(),
|
||||
#[cfg(feature = "gpu")]
|
||||
gpu_harvest: Vec::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +185,10 @@ impl DataCollection {
|
|||
{
|
||||
self.arc_harvest = memory::MemHarvest::default();
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
{
|
||||
self.gpu_harvest = Vec::default();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clean_data(&mut self, max_time_millis: u64) {
|
||||
|
@ -222,6 +232,14 @@ impl DataCollection {
|
|||
self.eat_arc(arc, &mut new_entry);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
{
|
||||
if let Some(gpu) = harvested_data.gpu {
|
||||
self.eat_gpu(gpu, &mut new_entry);
|
||||
}
|
||||
}
|
||||
|
||||
// CPU
|
||||
if let Some(cpu) = harvested_data.cpu {
|
||||
self.eat_cpu(cpu, &mut new_entry);
|
||||
|
@ -405,8 +423,18 @@ impl DataCollection {
|
|||
|
||||
#[cfg(feature = "zfs")]
|
||||
fn eat_arc(&mut self, arc: memory::MemHarvest, new_entry: &mut TimedData) {
|
||||
// Arc
|
||||
new_entry.arc_data = arc.use_percent;
|
||||
self.arc_harvest = arc;
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
fn eat_gpu(&mut self, gpu: Vec<(String, memory::MemHarvest)>, new_entry: &mut TimedData) {
|
||||
// Note this only pre-calculates the data points - the names will be
|
||||
// within the local copy of gpu_harvest. Since it's all sequential
|
||||
// it probably doesn't matter anyways.
|
||||
gpu.iter().for_each(|data| {
|
||||
new_entry.gpu_data.push(data.1.use_percent);
|
||||
});
|
||||
self.gpu_harvest = gpu.to_vec();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@ use futures::join;
|
|||
|
||||
use super::DataFilters;
|
||||
|
||||
#[cfg(feature = "nvidia")]
|
||||
pub mod nvidia;
|
||||
|
||||
#[cfg(feature = "battery")]
|
||||
pub mod batteries;
|
||||
pub mod cpu;
|
||||
|
@ -42,6 +45,8 @@ pub struct Data {
|
|||
pub list_of_batteries: Option<Vec<batteries::BatteryHarvest>>,
|
||||
#[cfg(feature = "zfs")]
|
||||
pub arc: Option<memory::MemHarvest>,
|
||||
#[cfg(feature = "gpu")]
|
||||
pub gpu: Option<Vec<(String, memory::MemHarvest)>>,
|
||||
}
|
||||
|
||||
impl Default for Data {
|
||||
|
@ -61,6 +66,8 @@ impl Default for Data {
|
|||
list_of_batteries: None,
|
||||
#[cfg(feature = "zfs")]
|
||||
arc: None,
|
||||
#[cfg(feature = "gpu")]
|
||||
gpu: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +90,10 @@ impl Data {
|
|||
{
|
||||
self.arc = None;
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
{
|
||||
self.gpu = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,19 +434,24 @@ impl DataCollector {
|
|||
self.data.network = net_data;
|
||||
}
|
||||
|
||||
if let Ok(memory) = mem_res.0 {
|
||||
if let Ok(memory) = mem_res.ram {
|
||||
self.data.memory = memory;
|
||||
}
|
||||
|
||||
if let Ok(swap) = mem_res.1 {
|
||||
if let Ok(swap) = mem_res.swap {
|
||||
self.data.swap = swap;
|
||||
}
|
||||
|
||||
#[cfg(feature = "zfs")]
|
||||
if let Ok(arc) = mem_res.2 {
|
||||
if let Ok(arc) = mem_res.arc {
|
||||
self.data.arc = arc;
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
if let Ok(gpu) = mem_res.gpus {
|
||||
self.data.gpu = gpu;
|
||||
}
|
||||
|
||||
if let Ok(disks) = disk_res {
|
||||
self.data.disks = disks;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use sysinfo::{LoadAvg, System, SystemExt};
|
||||
use sysinfo::{CpuExt, LoadAvg, System, SystemExt};
|
||||
|
||||
use super::{CpuData, CpuHarvest, PastCpuTotal, PastCpuWork};
|
||||
use super::{CpuData, CpuDataType, CpuHarvest, PastCpuTotal, PastCpuWork};
|
||||
use crate::app::data_harvester::cpu::LoadAvgHarvest;
|
||||
|
||||
pub async fn get_cpu_data_list(
|
||||
|
@ -14,12 +14,11 @@ pub async fn get_cpu_data_list(
|
|||
_previous_average_cpu_time: &mut Option<(PastCpuWork, PastCpuTotal)>,
|
||||
) -> crate::error::Result<CpuHarvest> {
|
||||
let mut cpu_deque: VecDeque<_> = sys
|
||||
.processors()
|
||||
.cpus()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, cpu)| CpuData {
|
||||
cpu_prefix: "CPU".to_string(),
|
||||
cpu_count: Some(i),
|
||||
data_type: CpuDataType::Cpu(i),
|
||||
cpu_usage: cpu.cpu_usage() as f64,
|
||||
})
|
||||
.collect();
|
||||
|
@ -28,8 +27,7 @@ pub async fn get_cpu_data_list(
|
|||
let cpu = sys.global_cpu_info();
|
||||
|
||||
cpu_deque.push_front(CpuData {
|
||||
cpu_prefix: "AVG".to_string(),
|
||||
cpu_count: None,
|
||||
data_type: CpuDataType::Avg,
|
||||
cpu_usage: cpu.cpu_usage() as f64,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,3 +14,13 @@ pub struct MemHarvest {
|
|||
pub mem_used_in_kib: u64,
|
||||
pub use_percent: Option<f64>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MemCollect {
|
||||
pub ram: crate::utils::error::Result<Option<MemHarvest>>,
|
||||
pub swap: crate::utils::error::Result<Option<MemHarvest>>,
|
||||
#[cfg(feature = "zfs")]
|
||||
pub arc: crate::utils::error::Result<Option<MemHarvest>>,
|
||||
#[cfg(feature = "gpu")]
|
||||
pub gpus: crate::utils::error::Result<Option<Vec<(String, MemHarvest)>>>,
|
||||
}
|
||||
|
|
|
@ -1,20 +1,26 @@
|
|||
//! Data collection for memory via heim.
|
||||
|
||||
use crate::data_harvester::memory::MemHarvest;
|
||||
|
||||
pub async fn get_mem_data(
|
||||
actually_get: bool,
|
||||
) -> (
|
||||
crate::utils::error::Result<Option<MemHarvest>>,
|
||||
crate::utils::error::Result<Option<MemHarvest>>,
|
||||
crate::utils::error::Result<Option<MemHarvest>>,
|
||||
) {
|
||||
use futures::join;
|
||||
use crate::data_harvester::memory::{MemCollect, MemHarvest};
|
||||
|
||||
pub async fn get_mem_data(actually_get: bool) -> MemCollect {
|
||||
if !actually_get {
|
||||
(Ok(None), Ok(None), Ok(None))
|
||||
MemCollect {
|
||||
ram: Ok(None),
|
||||
swap: Ok(None),
|
||||
#[cfg(feature = "zfs")]
|
||||
arc: Ok(None),
|
||||
#[cfg(feature = "gpu")]
|
||||
gpus: Ok(None),
|
||||
}
|
||||
} else {
|
||||
join!(get_ram_data(), get_swap_data(), get_arc_data())
|
||||
MemCollect {
|
||||
ram: get_ram_data().await,
|
||||
swap: get_swap_data().await,
|
||||
#[cfg(feature = "zfs")]
|
||||
arc: get_arc_data().await,
|
||||
#[cfg(feature = "gpu")]
|
||||
gpus: get_gpu_data().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,16 +176,15 @@ pub async fn get_swap_data() -> crate::utils::error::Result<Option<MemHarvest>>
|
|||
}))
|
||||
}
|
||||
|
||||
#[cfg(feature = "zfs")]
|
||||
pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> {
|
||||
#[cfg(not(feature = "zfs"))]
|
||||
let (mem_total_in_kib, mem_used_in_kib) = (0, 0);
|
||||
|
||||
#[cfg(feature = "zfs")]
|
||||
let (mem_total_in_kib, mem_used_in_kib) = {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let mut mem_arc = 0;
|
||||
let mut mem_total = 0;
|
||||
let mut zfs_keys_read: u8 = 0;
|
||||
const ZFS_KEYS_NEEDED: u8 = 2;
|
||||
use smol::fs::read_to_string;
|
||||
let arcinfo = read_to_string("/proc/spl/kstat/zfs/arcstats").await?;
|
||||
for line in arcinfo.lines() {
|
||||
|
@ -191,8 +196,7 @@ pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> {
|
|||
continue;
|
||||
}
|
||||
};
|
||||
let mut zfs_keys_read: u8 = 0;
|
||||
const ZFS_KEYS_NEEDED: u8 = 2;
|
||||
|
||||
if let Some((_type, number)) = value.trim_start().rsplit_once(' ') {
|
||||
// Parse the value, remember it's in bytes!
|
||||
if let Ok(number) = number.parse::<u64>() {
|
||||
|
@ -247,3 +251,39 @@ pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> {
|
|||
},
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(feature = "nvidia")]
|
||||
pub async fn get_gpu_data() -> crate::utils::error::Result<Option<Vec<(String, MemHarvest)>>> {
|
||||
use crate::data_harvester::nvidia::NVML_DATA;
|
||||
if let Ok(nvml) = &*NVML_DATA {
|
||||
if let Ok(ngpu) = nvml.device_count() {
|
||||
let mut results = Vec::with_capacity(ngpu as usize);
|
||||
for i in 0..ngpu {
|
||||
if let Ok(device) = nvml.device_by_index(i) {
|
||||
if let (Ok(name), Ok(mem)) = (device.name(), device.memory_info()) {
|
||||
// add device memory in bytes
|
||||
let mem_total_in_kib = mem.total / 1024;
|
||||
let mem_used_in_kib = mem.used / 1024;
|
||||
results.push((
|
||||
name,
|
||||
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)
|
||||
},
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(results))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,32 @@
|
|||
//! Data collection for memory via sysinfo.
|
||||
|
||||
use crate::data_harvester::memory::MemHarvest;
|
||||
use crate::data_harvester::memory::{MemCollect, MemHarvest};
|
||||
use sysinfo::{System, SystemExt};
|
||||
|
||||
pub async fn get_mem_data(
|
||||
sys: &System, actually_get: bool,
|
||||
) -> (
|
||||
crate::utils::error::Result<Option<MemHarvest>>,
|
||||
crate::utils::error::Result<Option<MemHarvest>>,
|
||||
crate::utils::error::Result<Option<MemHarvest>>,
|
||||
) {
|
||||
use futures::join;
|
||||
|
||||
pub async fn get_mem_data(sys: &System, actually_get: bool) -> MemCollect {
|
||||
if !actually_get {
|
||||
(Ok(None), Ok(None), Ok(None))
|
||||
MemCollect {
|
||||
ram: Ok(None),
|
||||
swap: Ok(None),
|
||||
#[cfg(feature = "zfs")]
|
||||
arc: Ok(None),
|
||||
#[cfg(feature = "gpu")]
|
||||
gpus: Ok(None),
|
||||
}
|
||||
} else {
|
||||
join!(get_ram_data(sys), get_swap_data(sys), get_arc_data())
|
||||
MemCollect {
|
||||
ram: get_ram_data(sys).await,
|
||||
swap: get_swap_data(sys).await,
|
||||
#[cfg(feature = "zfs")]
|
||||
arc: get_arc_data().await,
|
||||
#[cfg(feature = "gpu")]
|
||||
gpus: get_gpu_data().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_ram_data(sys: &System) -> crate::utils::error::Result<Option<MemHarvest>> {
|
||||
let (mem_total_in_kib, mem_used_in_kib) = (sys.total_memory() / 1024, sys.used_memory()) / 1024;
|
||||
let (mem_total_in_kib, mem_used_in_kib) = (sys.total_memory() / 1024, sys.used_memory() / 1024);
|
||||
|
||||
Ok(Some(MemHarvest {
|
||||
mem_total_in_kib,
|
||||
|
@ -47,11 +53,8 @@ pub async fn get_swap_data(sys: &System) -> crate::utils::error::Result<Option<M
|
|||
}))
|
||||
}
|
||||
|
||||
#[cfg(feature = "zfs")]
|
||||
pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> {
|
||||
#[cfg(not(feature = "zfs"))]
|
||||
let (mem_total_in_kib, mem_used_in_kib) = (0, 0);
|
||||
|
||||
#[cfg(feature = "zfs")]
|
||||
let (mem_total_in_kib, mem_used_in_kib) = {
|
||||
#[cfg(target_os = "freebsd")]
|
||||
{
|
||||
|
@ -82,3 +85,39 @@ pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> {
|
|||
},
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(feature = "nvidia")]
|
||||
pub async fn get_gpu_data() -> crate::utils::error::Result<Option<Vec<(String, MemHarvest)>>> {
|
||||
use crate::data_harvester::nvidia::NVML_DATA;
|
||||
if let Ok(nvml) = &*NVML_DATA {
|
||||
if let Ok(ngpu) = nvml.device_count() {
|
||||
let mut results = Vec::with_capacity(ngpu as usize);
|
||||
for i in 0..ngpu {
|
||||
if let Ok(device) = nvml.device_by_index(i) {
|
||||
if let (Ok(name), Ok(mem)) = (device.name(), device.memory_info()) {
|
||||
// add device memory in bytes
|
||||
let mem_total_in_kib = mem.total / 1024;
|
||||
let mem_used_in_kib = mem.used / 1024;
|
||||
results.push((
|
||||
name,
|
||||
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)
|
||||
},
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(results))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
use nvml_wrapper::{error::NvmlError, NVML};
|
||||
use once_cell::sync::Lazy;
|
||||
pub static NVML_DATA: Lazy<Result<NVML, NvmlError>> = Lazy::new(NVML::init);
|
|
@ -5,12 +5,14 @@ use super::{
|
|||
TemperatureType,
|
||||
};
|
||||
|
||||
use nvml_wrapper::{enum_wrappers::device::TemperatureSensor, NVML};
|
||||
use nvml_wrapper::enum_wrappers::device::TemperatureSensor;
|
||||
|
||||
use crate::data_harvester::nvidia::NVML_DATA;
|
||||
|
||||
pub fn add_nvidia_data(
|
||||
temperature_vec: &mut Vec<TempHarvest>, temp_type: &TemperatureType, filter: &Option<Filter>,
|
||||
) -> crate::utils::error::Result<()> {
|
||||
if let Ok(nvml) = NVML::init() {
|
||||
if let Ok(nvml) = &*NVML_DATA {
|
||||
if let Ok(ngpu) = nvml.device_count() {
|
||||
for i in 0..ngpu {
|
||||
if let Ok(device) = nvml.device_by_index(i) {
|
||||
|
|
|
@ -210,6 +210,11 @@ fn main() -> Result<()> {
|
|||
app.converted_data.arc_data =
|
||||
convert_arc_data_points(&app.data_collection);
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
{
|
||||
app.converted_data.gpu_data =
|
||||
convert_gpu_data(&app.data_collection);
|
||||
}
|
||||
let (memory_labels, swap_labels) =
|
||||
convert_mem_labels(&app.data_collection);
|
||||
|
||||
|
|
|
@ -451,19 +451,29 @@ impl Painter {
|
|||
}
|
||||
};
|
||||
|
||||
let mut mem_rows = 0;
|
||||
let mut mem_rows = 1;
|
||||
|
||||
if app_state.converted_data.swap_labels.is_some() {
|
||||
mem_rows += 1; // add row for swap
|
||||
}
|
||||
|
||||
#[cfg(feature = "zfs")]
|
||||
{
|
||||
let arc_data = &app_state.converted_data.arc_data;
|
||||
if let Some(arc) = arc_data.last() {
|
||||
if arc.1 != 0.0 {
|
||||
mem_rows += 1; // add row for arc
|
||||
}
|
||||
if app_state.converted_data.arc_labels.is_some() {
|
||||
mem_rows += 1; // add row for arc
|
||||
}
|
||||
}
|
||||
|
||||
mem_rows += 2; // add rows for SWAP and MEM
|
||||
#[cfg(feature = "gpu")]
|
||||
{
|
||||
if let Some(gpu_data) = &app_state.converted_data.gpu_data {
|
||||
mem_rows += gpu_data.len() as u16; // add row(s) for gpu
|
||||
}
|
||||
}
|
||||
|
||||
if mem_rows == 1 {
|
||||
mem_rows += 1; // need at least 2 rows for RX and TX
|
||||
}
|
||||
|
||||
let vertical_chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
|
|
|
@ -18,6 +18,7 @@ pub struct CanvasColours {
|
|||
pub ram_style: Style,
|
||||
pub swap_style: Style,
|
||||
pub arc_style: Style,
|
||||
pub gpu_colour_styles: Vec<Style>,
|
||||
pub rx_style: Style,
|
||||
pub tx_style: Style,
|
||||
pub total_rx_style: Style,
|
||||
|
@ -51,6 +52,15 @@ impl Default for CanvasColours {
|
|||
ram_style: Style::default().fg(STANDARD_FIRST_COLOUR),
|
||||
swap_style: Style::default().fg(STANDARD_SECOND_COLOUR),
|
||||
arc_style: Style::default().fg(STANDARD_THIRD_COLOUR),
|
||||
gpu_colour_styles: vec![
|
||||
Style::default().fg(STANDARD_FOURTH_COLOUR),
|
||||
Style::default().fg(Color::LightBlue),
|
||||
Style::default().fg(Color::LightRed),
|
||||
Style::default().fg(Color::Cyan),
|
||||
Style::default().fg(Color::Green),
|
||||
Style::default().fg(Color::Blue),
|
||||
Style::default().fg(Color::Red),
|
||||
],
|
||||
rx_style: Style::default().fg(STANDARD_FIRST_COLOUR),
|
||||
tx_style: Style::default().fg(STANDARD_SECOND_COLOUR),
|
||||
total_rx_style: Style::default().fg(STANDARD_THIRD_COLOUR),
|
||||
|
@ -160,6 +170,11 @@ impl CanvasColours {
|
|||
.context("Update 'arc_color' in your config file..")?;
|
||||
}
|
||||
|
||||
if let Some(gpu_core_colors) = &colours.gpu_core_colors {
|
||||
self.set_gpu_colours(gpu_core_colors)
|
||||
.context("Update 'gpu_core_colors' in your config file..")?;
|
||||
}
|
||||
|
||||
if let Some(rx_color) = &colours.rx_color {
|
||||
self.set_rx_colour(rx_color)
|
||||
.context("Update 'rx_color' in your config file..")?;
|
||||
|
@ -268,6 +283,14 @@ impl CanvasColours {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_gpu_colours(&mut self, colours: &[String]) -> error::Result<()> {
|
||||
self.gpu_colour_styles = colours
|
||||
.iter()
|
||||
.map(|colour| get_style_from_config(colour))
|
||||
.collect::<error::Result<Vec<Style>>>()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_rx_colour(&mut self, colour: &str) -> error::Result<()> {
|
||||
self.rx_style = get_style_from_config(colour)?;
|
||||
Ok(())
|
||||
|
|
|
@ -14,23 +14,7 @@ impl Painter {
|
|||
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
|
||||
) {
|
||||
let mem_data = &app_state.converted_data.mem_data;
|
||||
let swap_data = &app_state.converted_data.swap_data;
|
||||
|
||||
let margined_loc = Layout::default()
|
||||
.constraints({
|
||||
#[cfg(feature = "zfs")]
|
||||
{
|
||||
[Constraint::Length(1); 3]
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "zfs"))]
|
||||
{
|
||||
[Constraint::Length(1); 2]
|
||||
}
|
||||
})
|
||||
.direction(Direction::Vertical)
|
||||
.horizontal_margin(1)
|
||||
.split(draw_loc);
|
||||
let mut draw_widgets: Vec<PipeGauge<'_>> = Vec::new();
|
||||
|
||||
if app_state.current_widget.widget_id == widget_id {
|
||||
f.render_widget(
|
||||
|
@ -41,13 +25,8 @@ impl Painter {
|
|||
);
|
||||
}
|
||||
|
||||
let ram_ratio = if let Some(mem) = mem_data.last() {
|
||||
mem.1 / 100.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let swap_ratio = if let Some(swap) = swap_data.last() {
|
||||
swap.1 / 100.0
|
||||
let ram_percentage = if let Some(mem) = mem_data.last() {
|
||||
mem.1
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
@ -56,64 +35,129 @@ impl Painter {
|
|||
|
||||
let memory_fraction_label =
|
||||
if let Some((_, label_frac)) = &app_state.converted_data.mem_labels {
|
||||
label_frac.trim()
|
||||
if app_state.basic_mode_use_percent {
|
||||
format!("{:3.0}%", ram_percentage.round())
|
||||
} else {
|
||||
label_frac.trim().to_string()
|
||||
}
|
||||
} else {
|
||||
EMPTY_MEMORY_FRAC_STRING
|
||||
EMPTY_MEMORY_FRAC_STRING.to_string()
|
||||
};
|
||||
|
||||
let swap_fraction_label =
|
||||
if let Some((_, label_frac)) = &app_state.converted_data.swap_labels {
|
||||
label_frac.trim()
|
||||
} else {
|
||||
EMPTY_MEMORY_FRAC_STRING
|
||||
};
|
||||
|
||||
f.render_widget(
|
||||
draw_widgets.push(
|
||||
PipeGauge::default()
|
||||
.ratio(ram_ratio)
|
||||
.ratio(ram_percentage / 100.0)
|
||||
.start_label("RAM")
|
||||
.inner_label(memory_fraction_label)
|
||||
.label_style(self.colours.ram_style)
|
||||
.gauge_style(self.colours.ram_style),
|
||||
margined_loc[0],
|
||||
);
|
||||
|
||||
f.render_widget(
|
||||
PipeGauge::default()
|
||||
.ratio(swap_ratio)
|
||||
.start_label("SWP")
|
||||
.inner_label(swap_fraction_label)
|
||||
.label_style(self.colours.swap_style)
|
||||
.gauge_style(self.colours.swap_style),
|
||||
margined_loc[1],
|
||||
);
|
||||
let swap_data = &app_state.converted_data.swap_data;
|
||||
|
||||
let swap_percentage = if let Some(swap) = swap_data.last() {
|
||||
swap.1
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
if let Some((_, label_frac)) = &app_state.converted_data.swap_labels {
|
||||
let swap_fraction_label = if app_state.basic_mode_use_percent {
|
||||
format!("{:3.0}%", swap_percentage.round())
|
||||
} else {
|
||||
label_frac.trim().to_string()
|
||||
};
|
||||
draw_widgets.push(
|
||||
PipeGauge::default()
|
||||
.ratio(swap_percentage / 100.0)
|
||||
.start_label("SWP")
|
||||
.inner_label(swap_fraction_label)
|
||||
.label_style(self.colours.swap_style)
|
||||
.gauge_style(self.colours.swap_style),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "zfs")]
|
||||
{
|
||||
let arc_data = &app_state.converted_data.arc_data;
|
||||
let arc_ratio = if let Some(arc) = arc_data.last() {
|
||||
arc.1 / 100.0
|
||||
let arc_percentage = if let Some(arc) = arc_data.last() {
|
||||
arc.1
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let arc_fraction_label =
|
||||
if let Some((_, label_frac)) = &app_state.converted_data.arc_labels {
|
||||
label_frac.trim()
|
||||
if let Some((_, label_frac)) = &app_state.converted_data.arc_labels {
|
||||
let arc_fraction_label = if app_state.basic_mode_use_percent {
|
||||
format!("{:3.0}%", arc_percentage.round())
|
||||
} else {
|
||||
EMPTY_MEMORY_FRAC_STRING
|
||||
label_frac.trim().to_string()
|
||||
};
|
||||
|
||||
f.render_widget(
|
||||
PipeGauge::default()
|
||||
.ratio(arc_ratio)
|
||||
.start_label("ARC")
|
||||
.inner_label(arc_fraction_label)
|
||||
.label_style(self.colours.arc_style)
|
||||
.gauge_style(self.colours.arc_style),
|
||||
margined_loc[2],
|
||||
);
|
||||
draw_widgets.push(
|
||||
PipeGauge::default()
|
||||
.ratio(arc_percentage / 100.0)
|
||||
.start_label("ARC")
|
||||
.inner_label(arc_fraction_label)
|
||||
.label_style(self.colours.arc_style)
|
||||
.gauge_style(self.colours.arc_style),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
{
|
||||
let gpu_styles = &self.colours.gpu_colour_styles;
|
||||
let mut color_index = 0;
|
||||
if let Some(gpu_data) = &app_state.converted_data.gpu_data {
|
||||
gpu_data.iter().for_each(|gpu_data_vec| {
|
||||
let gpu_data = gpu_data_vec.points.as_slice();
|
||||
let gpu_percentage = if let Some(gpu) = gpu_data.last() {
|
||||
gpu.1
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let trimmed_gpu_frac = {
|
||||
if app_state.basic_mode_use_percent {
|
||||
format!("{:3.0}%", gpu_percentage.round())
|
||||
} else {
|
||||
gpu_data_vec.mem_total.trim().to_string()
|
||||
}
|
||||
};
|
||||
let style = {
|
||||
if gpu_styles.is_empty() {
|
||||
tui::style::Style::default()
|
||||
} else if color_index >= gpu_styles.len() {
|
||||
// cycle styles
|
||||
color_index = 1;
|
||||
gpu_styles[color_index - 1]
|
||||
} else {
|
||||
color_index += 1;
|
||||
gpu_styles[color_index - 1]
|
||||
}
|
||||
};
|
||||
draw_widgets.push(
|
||||
PipeGauge::default()
|
||||
.ratio(gpu_percentage / 100.0)
|
||||
.start_label("GPU")
|
||||
.inner_label(trimmed_gpu_frac)
|
||||
.label_style(style)
|
||||
.gauge_style(style),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let margined_loc = Layout::default()
|
||||
.constraints(vec![Constraint::Length(1); draw_widgets.len()])
|
||||
.direction(Direction::Vertical)
|
||||
.horizontal_margin(1)
|
||||
.split(draw_loc);
|
||||
|
||||
draw_widgets
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.for_each(|(index, widget)| {
|
||||
f.render_widget(widget, margined_loc[index]);
|
||||
});
|
||||
|
||||
// Update draw loc in widget map
|
||||
if app_state.should_get_widget_bounds() {
|
||||
if let Some(widget) = app_state.widget_map.get_mut(&widget_id) {
|
||||
|
|
|
@ -29,18 +29,22 @@ impl Painter {
|
|||
draw_loc,
|
||||
);
|
||||
let points = {
|
||||
let mut size = 0;
|
||||
let mut size = 1;
|
||||
if app_state.converted_data.swap_labels.is_some() {
|
||||
size += 1; // add capacity for SWAP
|
||||
}
|
||||
#[cfg(feature = "zfs")]
|
||||
{
|
||||
let arc_data = &app_state.converted_data.arc_data;
|
||||
if let Some(arc) = arc_data.last() {
|
||||
if arc.1 != 0.0 {
|
||||
size += 1; // add capacity for ARC
|
||||
}
|
||||
if app_state.converted_data.arc_labels.is_some() {
|
||||
size += 1; // add capacity for ARC
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
{
|
||||
if let Some(gpu_data) = &app_state.converted_data.gpu_data {
|
||||
size += gpu_data.len(); // add row(s) for gpu
|
||||
}
|
||||
}
|
||||
|
||||
size += 2; // add capacity for RAM and SWP
|
||||
|
||||
let mut points = Vec::with_capacity(size);
|
||||
if let Some((label_percent, label_frac)) = &app_state.converted_data.mem_labels {
|
||||
|
@ -61,16 +65,39 @@ impl Painter {
|
|||
}
|
||||
#[cfg(feature = "zfs")]
|
||||
if let Some((label_percent, label_frac)) = &app_state.converted_data.arc_labels {
|
||||
let arc_data = &app_state.converted_data.arc_data;
|
||||
if let Some(arc) = arc_data.last() {
|
||||
if arc.1 != 0.0 {
|
||||
let arc_label = format!("ARC:{}{}", label_percent, label_frac);
|
||||
let arc_label = format!("ARC:{}{}", label_percent, label_frac);
|
||||
points.push(GraphData {
|
||||
points: &app_state.converted_data.arc_data,
|
||||
style: self.colours.arc_style,
|
||||
name: Some(arc_label.into()),
|
||||
});
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
{
|
||||
if let Some(gpu_data) = &app_state.converted_data.gpu_data {
|
||||
let mut color_index = 0;
|
||||
let gpu_styles = &self.colours.gpu_colour_styles;
|
||||
gpu_data.iter().for_each(|gpu| {
|
||||
let gpu_label =
|
||||
format!("{}:{}{}", gpu.name, gpu.mem_percent, gpu.mem_total);
|
||||
let style = {
|
||||
if gpu_styles.is_empty() {
|
||||
tui::style::Style::default()
|
||||
} else if color_index >= gpu_styles.len() {
|
||||
// cycle styles
|
||||
color_index = 1;
|
||||
gpu_styles[color_index - 1]
|
||||
} else {
|
||||
color_index += 1;
|
||||
gpu_styles[color_index - 1]
|
||||
}
|
||||
};
|
||||
points.push(GraphData {
|
||||
points: &app_state.converted_data.arc_data,
|
||||
style: self.colours.arc_style,
|
||||
name: Some(arc_label.into()),
|
||||
points: gpu.points.as_slice(),
|
||||
style,
|
||||
name: Some(gpu_label.into()),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,15 @@ pub static DEFAULT_LIGHT_MODE_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(||
|
|||
ram_color: Some("blue".to_string()),
|
||||
swap_color: Some("red".to_string()),
|
||||
arc_color: Some("LightBlue".to_string()),
|
||||
gpu_core_colors: Some(vec![
|
||||
"LightGreen".to_string(),
|
||||
"LightCyan".to_string(),
|
||||
"LightRed".to_string(),
|
||||
"Cyan".to_string(),
|
||||
"Green".to_string(),
|
||||
"Blue".to_string(),
|
||||
"Red".to_string(),
|
||||
]),
|
||||
rx_color: Some("blue".to_string()),
|
||||
tx_color: Some("red".to_string()),
|
||||
rx_total_color: Some("LightBlue".to_string()),
|
||||
|
@ -86,6 +95,15 @@ pub static GRUVBOX_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColo
|
|||
ram_color: Some("#8ec07c".to_string()),
|
||||
swap_color: Some("#fabd2f".to_string()),
|
||||
arc_color: Some("#689d6a".to_string()),
|
||||
gpu_core_colors: Some(vec![
|
||||
"#d79921".to_string(),
|
||||
"#458588".to_string(),
|
||||
"#b16286".to_string(),
|
||||
"#fe8019".to_string(),
|
||||
"#b8bb26".to_string(),
|
||||
"#cc241d".to_string(),
|
||||
"#98971a".to_string(),
|
||||
]),
|
||||
rx_color: Some("#8ec07c".to_string()),
|
||||
tx_color: Some("#fabd2f".to_string()),
|
||||
rx_total_color: Some("#689d6a".to_string()),
|
||||
|
@ -132,6 +150,15 @@ pub static GRUVBOX_LIGHT_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| Conf
|
|||
ram_color: Some("#427b58".to_string()),
|
||||
swap_color: Some("#cc241d".to_string()),
|
||||
arc_color: Some("#689d6a".to_string()),
|
||||
gpu_core_colors: Some(vec![
|
||||
"#9d0006".to_string(),
|
||||
"#98971a".to_string(),
|
||||
"#d79921".to_string(),
|
||||
"#458588".to_string(),
|
||||
"#b16286".to_string(),
|
||||
"#fe8019".to_string(),
|
||||
"#b8bb26".to_string(),
|
||||
]),
|
||||
rx_color: Some("#427b58".to_string()),
|
||||
tx_color: Some("#cc241d".to_string()),
|
||||
rx_total_color: Some("#689d6a".to_string()),
|
||||
|
@ -166,6 +193,15 @@ pub static NORD_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColours
|
|||
ram_color: Some("#88c0d0".to_string()),
|
||||
swap_color: Some("#d08770".to_string()),
|
||||
arc_color: Some("#5e81ac".to_string()),
|
||||
gpu_core_colors: Some(vec![
|
||||
"#8fbcbb".to_string(),
|
||||
"#81a1c1".to_string(),
|
||||
"#d8dee9".to_string(),
|
||||
"#b48ead".to_string(),
|
||||
"#a3be8c".to_string(),
|
||||
"#ebcb8b".to_string(),
|
||||
"#bf616a".to_string(),
|
||||
]),
|
||||
rx_color: Some("#88c0d0".to_string()),
|
||||
tx_color: Some("#d08770".to_string()),
|
||||
rx_total_color: Some("#5e81ac".to_string()),
|
||||
|
@ -200,6 +236,15 @@ pub static NORD_LIGHT_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigC
|
|||
ram_color: Some("#81a1c1".to_string()),
|
||||
swap_color: Some("#d08770".to_string()),
|
||||
arc_color: Some("#5e81ac".to_string()),
|
||||
gpu_core_colors: Some(vec![
|
||||
"#8fbcbb".to_string(),
|
||||
"#88c0d0".to_string(),
|
||||
"#4c566a".to_string(),
|
||||
"#b48ead".to_string(),
|
||||
"#a3be8c".to_string(),
|
||||
"#ebcb8b".to_string(),
|
||||
"#bf616a".to_string(),
|
||||
]),
|
||||
rx_color: Some("#81a1c1".to_string()),
|
||||
tx_color: Some("#d08770".to_string()),
|
||||
rx_total_color: Some("#5e81ac".to_string()),
|
||||
|
@ -520,6 +565,8 @@ pub const CONFIG_TEXT: &str = r##"# This is a default config file for bottom. A
|
|||
#swap_color="LightYellow"
|
||||
# Represents the colour ARC will use in the memory legend and graph.
|
||||
#arc_color="LightCyan"
|
||||
# Represents the colour the GPU will use in the memory legend and graph.
|
||||
#gpu_core_colors=["LightGreen", "LightBlue", "LightRed", "Cyan", "Green", "Blue", "Red"]
|
||||
# Represents the colour rx will use in the network legend and graph.
|
||||
#rx_color="LightCyan"
|
||||
# Represents the colour tx will use in the network legend and graph.
|
||||
|
|
|
@ -64,14 +64,17 @@ pub struct ConvertedData {
|
|||
|
||||
pub mem_labels: Option<(String, String)>,
|
||||
pub swap_labels: Option<(String, String)>,
|
||||
#[cfg(feature = "zfs")]
|
||||
pub arc_labels: Option<(String, String)>,
|
||||
|
||||
pub mem_data: Vec<Point>, // TODO: Switch this and all data points over to a better data structure...
|
||||
pub swap_data: Vec<Point>,
|
||||
#[cfg(feature = "zfs")]
|
||||
pub arc_data: Vec<Point>,
|
||||
pub load_avg_data: [f32; 3],
|
||||
pub cpu_data: Vec<CpuWidgetData>,
|
||||
pub battery_data: Vec<ConvertedBatteryData>,
|
||||
#[cfg(feature = "gpu")]
|
||||
pub gpu_data: Option<Vec<ConvertedGpuData>>,
|
||||
}
|
||||
|
||||
impl ConvertedData {
|
||||
|
@ -618,6 +621,97 @@ pub fn convert_arc_data_points(
|
|||
result
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ConvertedGpuData {
|
||||
pub name: String,
|
||||
pub mem_total: String,
|
||||
pub mem_percent: String,
|
||||
pub points: Vec<Point>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
pub fn convert_gpu_data(
|
||||
current_data: &crate::app::data_farmer::DataCollection,
|
||||
) -> Option<Vec<ConvertedGpuData>> {
|
||||
/// Returns the unit type and denominator for given total amount of memory in kibibytes.
|
||||
fn return_unit_and_denominator_for_mem_kib(mem_total_kib: u64) -> (&'static str, f64) {
|
||||
if mem_total_kib < 1024 {
|
||||
// Stay with KiB
|
||||
("KiB", 1.0)
|
||||
} else if mem_total_kib < MEBI_LIMIT {
|
||||
// Use MiB
|
||||
("MiB", KIBI_LIMIT_F64)
|
||||
} else if mem_total_kib < GIBI_LIMIT {
|
||||
// Use GiB
|
||||
("GiB", MEBI_LIMIT_F64)
|
||||
} else {
|
||||
// Use TiB
|
||||
("TiB", GIBI_LIMIT_F64)
|
||||
}
|
||||
}
|
||||
|
||||
let current_time = current_data.current_instant;
|
||||
|
||||
// convert points
|
||||
let mut point_vec: Vec<Vec<Point>> = Vec::with_capacity(current_data.gpu_harvest.len());
|
||||
for (time, data) in ¤t_data.timed_data_vec {
|
||||
data.gpu_data.iter().enumerate().for_each(|(index, point)| {
|
||||
if let Some(data_point) = point {
|
||||
let time_from_start: f64 =
|
||||
(current_time.duration_since(*time).as_millis() as f64).floor();
|
||||
if let Some(point_slot) = point_vec.get_mut(index) {
|
||||
point_slot.push((-time_from_start, *data_point));
|
||||
} else {
|
||||
point_vec.push(vec![(-time_from_start, *data_point)]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if *time == current_time {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert labels
|
||||
let results = current_data
|
||||
.gpu_harvest
|
||||
.iter()
|
||||
.zip(point_vec.into_iter())
|
||||
.map(|(gpu, points)| {
|
||||
let short_name = {
|
||||
let last_words = gpu.0.split_whitespace().rev().take(2).collect::<Vec<_>>();
|
||||
let short_name = format!("{} {}", last_words[1], last_words[0]);
|
||||
short_name
|
||||
};
|
||||
|
||||
ConvertedGpuData {
|
||||
name: short_name,
|
||||
points,
|
||||
mem_percent: format!("{:3.0}%", gpu.1.use_percent.unwrap_or(0.0)),
|
||||
mem_total: {
|
||||
let (unit, denominator) =
|
||||
return_unit_and_denominator_for_mem_kib(gpu.1.mem_total_in_kib);
|
||||
|
||||
format!(
|
||||
" {:.1}{}/{:.1}{}",
|
||||
gpu.1.mem_used_in_kib as f64 / denominator,
|
||||
unit,
|
||||
(gpu.1.mem_total_in_kib as f64 / denominator),
|
||||
unit
|
||||
)
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect::<Vec<ConvertedGpuData>>();
|
||||
|
||||
if !results.is_empty() {
|
||||
Some(results)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -350,6 +350,10 @@ pub fn update_data(app: &mut App) {
|
|||
app.converted_data.arc_data = convert_arc_data_points(data_source);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
{
|
||||
app.converted_data.gpu_data = convert_gpu_data(data_source);
|
||||
}
|
||||
app.mem_state.force_update = None;
|
||||
}
|
||||
|
||||
|
|
|
@ -199,6 +199,7 @@ pub struct ConfigColours {
|
|||
pub ram_color: Option<String>,
|
||||
pub swap_color: Option<String>,
|
||||
pub arc_color: Option<String>,
|
||||
pub gpu_core_colors: Option<Vec<String>>,
|
||||
pub rx_color: Option<String>,
|
||||
pub tx_color: Option<String>,
|
||||
pub rx_total_color: Option<String>, // These only affect basic mode.
|
||||
|
|
Loading…
Reference in New Issue