feature: add buffer and cache memory (#1063)

* First implementation of cache memory data collection, mostly copied from RAM and swap implementations

* First implementation of cache memory display, copied from RAM and swap implementations. placed cache as second in the list as it is more similar to the RAM than any other item in the list

* expanded comment to explain method.

* rustfmt

* all cache-related code excluded on windows, in the process refactored src/data_conversion.rs convert_mem_label() to convert a single label instead of all at once

* better factoring-out of cache memory logic to allow individual disabling

* added --enable_cache_memory flag, disabled cache memory collection by default

* renamed CCH to CHE
not sure how i messed that up

* changelog updated

* Added command line flag documentation

* updated config file documentation

* specified that buffer and cache memory display does not work on windows

* resolved merge conflicts

* added documentation to cache memory data collection

* capitalized Windows

* implemented missing canvas styling logic

* fixed misplaced no-windows flag

* reduced colour collisions, as cache colour was the same as the first GPU colour

* made FIFTH_COLOUR constant windows-only

* Revert "made FIFTH_COLOUR constant windows-only"

This reverts commit 72698f1dd7.

* made FIFTH_COLOUR constant non-windows-only

* minor fix for basic mode row count

* Update src/app/data_harvester/memory/sysinfo.rs

Co-authored-by: Clement Tsang <34804052+ClementTsang@users.noreply.github.com>

* Update src/canvas/widgets/mem_basic.rs

Co-authored-by: Clement Tsang <34804052+ClementTsang@users.noreply.github.com>

* updated default_config.toml

* formatting

---------

Co-authored-by: ClementTsang <34804052+ClementTsang@users.noreply.github.com>
This commit is contained in:
Twan Stok 2023-04-13 04:51:41 +02:00 committed by GitHub
parent e61e5f2af6
commit 1b1e80ec3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 309 additions and 133 deletions

View File

@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1016](https://github.com/ClementTsang/bottom/pull/1016): Add support for displaying process usernames on Windows.
- [#1022](https://github.com/ClementTsang/bottom/pull/1022): Support three-character hex colour strings for styling.
- [#1024](https://github.com/ClementTsang/bottom/pull/1024): Support FreeBSD temperature sensors based on `hw.temperature`.
- [#1063](https://github.com/ClementTsang/bottom/pull/1063): Add buffer and cache memory tracking
## Changes

View File

@ -6,44 +6,45 @@
The following flags can be provided to bottom in the command line to change the behaviour of the program (run `btm --help` for more information on each flag):
| Flag | Behaviour |
| -------------------------------------------- | --------------------------------------------------------------- |
| `--autohide_time` | Temporarily shows the time scale in graphs. |
| `-b`, `--basic` | Hides graphs and uses a more basic look. |
| `--battery` | Shows the battery widget. |
| `-S`, `--case_sensitive` | Enables case sensitivity by default. |
| `-c`, `--celsius` | Sets the temperature type to Celsius. |
| `--color <COLOR SCHEME>` | Use a color scheme, use --help for supported values. |
| `-C <CONFIG PATH>`, `--config <CONFIG PATH>` | Sets the location of the config file. |
| `-u`, `--current_usage` | Sets process CPU% to be based on current CPU%. |
| `-t <MS>`, `--default_time_value <MS>` | Default time value for graphs in ms. |
| `--default_widget_count <INT>` | Sets the n'th selected widget type as the default. |
| `--default_widget_type <WIDGET TYPE>` | Sets the default widget type, use --help for more info. |
| `--disable_advanced_kill` | Hides advanced options to stop a process on Unix-like systems. |
| `--disable_click` | Disables mouse clicks. |
| `-m`, `--dot_marker` | Uses a dot marker for graphs. |
| `-f`, `--fahrenheit` | Sets the temperature type to Fahrenheit. |
| `-g`, `--group` | Groups processes with the same name by default. |
| `-h`, `--help` | Prints help information. Use --help for more info. |
| `-a`, `--hide_avg_cpu` | Hides the average CPU usage. |
| `--hide_table_gap` | Hides the spacing between table headers and entries. |
| `--hide_time` | Hides the time scale. |
| `-k`, `--kelvin` | Sets the temperature type to Kelvin. |
| `-l`, `--left_legend` | Puts the CPU chart legend to the left side. |
| `--mem_as_value` | Defaults to showing process memory usage by value. |
| `--network_use_binary_prefix` | Displays the network widget with binary prefixes. |
| `--network_use_bytes` | Displays the network widget using bytes. |
| `--network_use_log` | Displays the network widget with a log scale. |
| `--process_command` | Show processes as their commands by default. |
| `-r`, `--rate <MS>` | Sets a refresh rate in ms. |
| `-R`, `--regex` | Enables regex by default. |
| `--show_table_scroll_position` | Shows the scroll position tracker in table widgets. |
| `-d <MS>`, `--time_delta <MS>` | The amount in ms changed upon zooming. |
| `-T`, `--tree` | Defaults to showing the process widget in tree mode. |
| `--use_old_network_legend` | DEPRECATED - uses the older network legend. |
| `-V`, `--version` | Prints version information. |
| `-W`, `--whole_word` | Enables whole-word matching by default. |
| `--enable_gpu_memory` | Enable collecting and displaying GPU memory usage. |
| `--retention` | How much data is stored at once in terms of time. |
| `-n`, `--unnormalized_cpu` | Show process CPU% without normalizing over the number of cores. |
| `-e`, `--expanded` | Expand the default widget upon starting the app. |
| Flag | Behaviour |
|----------------------------------------------|--------------------------------------------------------------------------------------|
| `--autohide_time` | Temporarily shows the time scale in graphs. |
| `-b`, `--basic` | Hides graphs and uses a more basic look. |
| `--battery` | Shows the battery widget. |
| `-S`, `--case_sensitive` | Enables case sensitivity by default. |
| `-c`, `--celsius` | Sets the temperature type to Celsius. |
| `--color <COLOR SCHEME>` | Use a color scheme, use --help for supported values. |
| `-C <CONFIG PATH>`, `--config <CONFIG PATH>` | Sets the location of the config file. |
| `-u`, `--current_usage` | Sets process CPU% to be based on current CPU%. |
| `-t <MS>`, `--default_time_value <MS>` | Default time value for graphs in ms. |
| `--default_widget_count <INT>` | Sets the n'th selected widget type as the default. |
| `--default_widget_type <WIDGET TYPE>` | Sets the default widget type, use --help for more info. |
| `--disable_advanced_kill` | Hides advanced options to stop a process on Unix-like systems. |
| `--disable_click` | Disables mouse clicks. |
| `--enable_cache_memory` | Enable collecting and displaying cache and buffer memory (not available on Windows). |
| `-m`, `--dot_marker` | Uses a dot marker for graphs. |
| `-f`, `--fahrenheit` | Sets the temperature type to Fahrenheit. |
| `-g`, `--group` | Groups processes with the same name by default. |
| `-h`, `--help` | Prints help information. Use --help for more info. |
| `-a`, `--hide_avg_cpu` | Hides the average CPU usage. |
| `--hide_table_gap` | Hides the spacing between table headers and entries. |
| `--hide_time` | Hides the time scale. |
| `-k`, `--kelvin` | Sets the temperature type to Kelvin. |
| `-l`, `--left_legend` | Puts the CPU chart legend to the left side. |
| `--mem_as_value` | Defaults to showing process memory usage by value. |
| `--network_use_binary_prefix` | Displays the network widget with binary prefixes. |
| `--network_use_bytes` | Displays the network widget using bytes. |
| `--network_use_log` | Displays the network widget with a log scale. |
| `--process_command` | Show processes as their commands by default. |
| `-r`, `--rate <MS>` | Sets a refresh rate in ms. |
| `-R`, `--regex` | Enables regex by default. |
| `--show_table_scroll_position` | Shows the scroll position tracker in table widgets. |
| `-d <MS>`, `--time_delta <MS>` | The amount in ms changed upon zooming. |
| `-T`, `--tree` | Defaults to showing the process widget in tree mode. |
| `--use_old_network_legend` | DEPRECATED - uses the older network legend. |
| `-V`, `--version` | Prints version information. |
| `-W`, `--whole_word` | Enables whole-word matching by default. |
| `--enable_gpu_memory` | Enable collecting and displaying GPU memory usage. |
| `--retention` | How much data is stored at once in terms of time. |
| `-n`, `--unnormalized_cpu` | Show process CPU% without normalizing over the number of cores. |
| `-e`, `--expanded` | Expand the default widget upon starting the app. |

View File

@ -4,39 +4,41 @@
This section is in progress, and is just copied from the old documentation.
Most of the [command line flags](../../command-line-flags) have config file equivalents to avoid having to type them out each time:
Most of the [command line flags](../../command-line-flags) have config file equivalents to avoid having to type them out
each time:
| Field | Type | Functionality |
| ---------------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| `hide_avg_cpu` | Boolean | Hides the average CPU usage. |
| `dot_marker` | Boolean | Uses a dot marker for graphs. |
| `left_legend` | Boolean | Puts the CPU chart legend to the left side. |
| `current_usage` | Boolean | Sets process CPU% to be based on current CPU%. |
| `group_processes` | Boolean | Groups processes with the same name by default. |
| `case_sensitive` | Boolean | Enables case sensitivity by default. |
| `whole_word` | Boolean | Enables whole-word matching by default. |
| `regex` | Boolean | Enables regex by default. |
| `basic` | Boolean | Hides graphs and uses a more basic look. |
| `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. |
| `battery` | Boolean | Shows the battery widget. |
| `rate` | Unsigned Int (represents milliseconds) | Sets a refresh rate in ms. |
| `default_time_value` | Unsigned Int (represents milliseconds) | Default time value for graphs in ms. |
| `time_delta` | Unsigned Int (represents milliseconds) | The amount in ms changed upon zooming. |
| `hide_time` | Boolean | Hides the time scale. |
| `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) | Sets the temperature unit type. |
| `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) | Sets the default widget type, use --help for more info. |
| `default_widget_count` | Unsigned Int (represents which `default_widget_type`) | Sets the n'th selected widget type as the default. |
| `disable_click` | Boolean | Disables mouse clicks. |
| `color` | String (one of ["default", "default-light", "gruvbox", "gruvbox-light", "nord", "nord-light"]) | Use a color scheme, use --help for supported values. |
| `mem_as_value` | Boolean | Defaults to showing process memory usage by value. |
| `tree` | Boolean | Defaults to showing the process widget in tree mode. |
| `show_table_scroll_position` | Boolean | Shows the scroll position tracker in table widgets. |
| `process_command` | Boolean | Show processes as their commands by default. |
| `disable_advanced_kill` | Boolean | Hides advanced options to stop a process on Unix-like systems. |
| `network_use_binary_prefix` | Boolean | Displays the network widget with binary prefixes. |
| `network_use_bytes` | Boolean | Displays the network widget using bytes. |
| `network_use_log` | Boolean | Displays the network widget with a log scale. |
| `enable_gpu_memory` | Boolean | Shows the GPU memory widget. |
| `retention` | String (human readable time, such as "10m", "1h", etc.) | How much data is stored at once in terms of time. |
| `unnormalized_cpu` | Boolean | Show process CPU% without normalizing over the number of cores. |
| `expanded_on_startup` | Boolean | Expand the default widget upon starting the app. |
| Field | Type | Functionality |
|------------------------------|------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
| `hide_avg_cpu` | Boolean | Hides the average CPU usage. |
| `dot_marker` | Boolean | Uses a dot marker for graphs. |
| `left_legend` | Boolean | Puts the CPU chart legend to the left side. |
| `current_usage` | Boolean | Sets process CPU% to be based on current CPU%. |
| `group_processes` | Boolean | Groups processes with the same name by default. |
| `case_sensitive` | Boolean | Enables case sensitivity by default. |
| `whole_word` | Boolean | Enables whole-word matching by default. |
| `regex` | Boolean | Enables regex by default. |
| `basic` | Boolean | Hides graphs and uses a more basic look. |
| `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. |
| `battery` | Boolean | Shows the battery widget. |
| `rate` | Unsigned Int (represents milliseconds) | Sets a refresh rate in ms. |
| `default_time_value` | Unsigned Int (represents milliseconds) | Default time value for graphs in ms. |
| `time_delta` | Unsigned Int (represents milliseconds) | The amount in ms changed upon zooming. |
| `hide_time` | Boolean | Hides the time scale. |
| `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) | Sets the temperature unit type. |
| `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) | Sets the default widget type, use --help for more info. |
| `default_widget_count` | Unsigned Int (represents which `default_widget_type`) | Sets the n'th selected widget type as the default. |
| `disable_click` | Boolean | Disables mouse clicks. |
| `color` | String (one of ["default", "default-light", "gruvbox", "gruvbox-light", "nord", "nord-light"]) | Use a color scheme, use --help for supported values. |
| `enable_cache_memory` | Boolean | Enable collecting and displaying cache and buffer memory (not available on Windows). |
| `mem_as_value` | Boolean | Defaults to showing process memory usage by value. |
| `tree` | Boolean | Defaults to showing the process widget in tree mode. |
| `show_table_scroll_position` | Boolean | Shows the scroll position tracker in table widgets. |
| `process_command` | Boolean | Show processes as their commands by default. |
| `disable_advanced_kill` | Boolean | Hides advanced options to stop a process on Unix-like systems. |
| `network_use_binary_prefix` | Boolean | Displays the network widget with binary prefixes. |
| `network_use_bytes` | Boolean | Displays the network widget using bytes. |
| `network_use_log` | Boolean | Displays the network widget with a log scale. |
| `enable_gpu_memory` | Boolean | Shows the GPU memory widget. |
| `retention` | String (human readable time, such as "10m", "1h", etc.) | How much data is stored at once in terms of time. |
| `unnormalized_cpu` | Boolean | Show process CPU% without normalizing over the number of cores. |
| `expanded_on_startup` | Boolean | Expand the default widget upon starting the app. |

View File

@ -75,6 +75,8 @@
#disable_advanced_kill = false
# Shows GPU(s) memory
#enable_gpu_memory = false
# Shows cache and buffer memory
#enable_cache_memory = false
# How much data is stored at once in terms of time.
#retention = "10m"
@ -96,6 +98,8 @@
#swap_color="LightYellow"
# Represents the colour ARC will use in the memory legend and graph.
#arc_color="LightCyan"
# Represents the colour cache and buffer memory will use in the memory legend and graph.
#cache_color="LightRed"
# 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.

View File

@ -60,6 +60,7 @@ pub struct AppConfigFields {
pub table_gap: u16,
pub disable_click: bool,
pub enable_gpu_memory: bool,
pub enable_cache_memory: bool,
pub show_table_scroll_position: bool,
pub is_advanced_kill: bool,
// TODO: Remove these, move network details state-side.

View File

@ -35,6 +35,8 @@ pub struct TimedData {
pub cpu_data: Vec<Value>,
pub load_avg_data: [f32; 3],
pub mem_data: Option<Value>,
#[cfg(not(target_os = "windows"))]
pub cache_data: Option<Value>,
pub swap_data: Option<Value>,
#[cfg(feature = "zfs")]
pub arc_data: Option<Value>,
@ -108,6 +110,8 @@ pub struct DataCollection {
pub timed_data_vec: Vec<(Instant, TimedData)>,
pub network_harvest: network::NetworkHarvest,
pub memory_harvest: memory::MemHarvest,
#[cfg(not(target_os = "windows"))]
pub cache_harvest: memory::MemHarvest,
pub swap_harvest: memory::MemHarvest,
pub cpu_harvest: cpu::CpuHarvest,
pub load_avg_harvest: cpu::LoadAvgHarvest,
@ -132,6 +136,8 @@ impl Default for DataCollection {
timed_data_vec: Vec::default(),
network_harvest: network::NetworkHarvest::default(),
memory_harvest: memory::MemHarvest::default(),
#[cfg(not(target_os = "windows"))]
cache_harvest: memory::MemHarvest::default(),
swap_harvest: memory::MemHarvest::default(),
cpu_harvest: cpu::CpuHarvest::default(),
load_avg_harvest: cpu::LoadAvgHarvest::default(),
@ -206,11 +212,17 @@ impl DataCollection {
self.eat_network(network, &mut new_entry);
}
// Memory and Swap
// Memory, Swap
if let (Some(memory), Some(swap)) = (harvested_data.memory, harvested_data.swap) {
self.eat_memory_and_swap(memory, swap, &mut new_entry);
}
// Cache memory
#[cfg(not(target_os = "windows"))]
if let Some(cache) = harvested_data.cache {
self.eat_cache(cache, &mut new_entry);
}
#[cfg(feature = "zfs")]
if let Some(arc) = harvested_data.arc {
self.eat_arc(arc, &mut new_entry);
@ -275,6 +287,15 @@ impl DataCollection {
self.swap_harvest = swap;
}
#[cfg(not(target_os = "windows"))]
fn eat_cache(&mut self, cache: memory::MemHarvest, new_entry: &mut TimedData) {
// Cache and buffer memory
new_entry.cache_data = cache.use_percent;
// In addition copy over latest data for easy reference
self.cache_harvest = cache;
}
fn eat_network(&mut self, network: network::NetworkHarvest, new_entry: &mut TimedData) {
// RX
if network.rx > 0 {

View File

@ -31,6 +31,8 @@ pub struct Data {
pub cpu: Option<cpu::CpuHarvest>,
pub load_avg: Option<cpu::LoadAvgHarvest>,
pub memory: Option<memory::MemHarvest>,
#[cfg(not(target_os = "windows"))]
pub cache: Option<memory::MemHarvest>,
pub swap: Option<memory::MemHarvest>,
pub temperature_sensors: Option<Vec<temperature::TempHarvest>>,
pub network: Option<network::NetworkHarvest>,
@ -52,6 +54,8 @@ impl Default for Data {
cpu: None,
load_avg: None,
memory: None,
#[cfg(not(target_os = "windows"))]
cache: None,
swap: None,
temperature_sensors: None,
list_of_processes: None,
@ -404,6 +408,12 @@ impl DataCollector {
fn update_memory_usage(&mut self) {
if self.widgets_to_harvest.use_mem {
self.data.memory = memory::get_ram_usage(&self.sys);
#[cfg(not(target_os = "windows"))]
if self.widgets_to_harvest.use_cache {
self.data.cache = memory::get_cache_usage(&self.sys);
}
self.data.swap = memory::get_swap_usage(
#[cfg(not(target_os = "windows"))]
&self.sys,

View File

@ -1,8 +1,10 @@
//! Memory data collection.
pub mod sysinfo;
#[cfg(not(target_os = "windows"))]
pub(crate) use self::sysinfo::get_cache_usage;
pub(crate) use self::sysinfo::get_ram_usage;
pub mod sysinfo;
cfg_if::cfg_if! {
if #[cfg(target_os = "windows")] {
pub mod windows;

View File

@ -36,3 +36,25 @@ pub(crate) fn get_swap_usage(sys: &System) -> Option<MemHarvest> {
},
})
}
/// Returns cache usage. sysinfo has no way to do this directly but it should equal the difference
/// between the available and free memory. Free memory is defined as memory not containing any data,
/// which means cache and buffer memory are not "free". Available memory is defined as memory able
/// to be allocated by processes, which includes cache and buffer memory. On Windows, this will
/// always be 0. For more information, see [docs](https://docs.rs/sysinfo/0.28.4/sysinfo/trait.SystemExt.html#tymethod.available_memory)
/// and [memory explanation](https://askubuntu.com/questions/867068/what-is-available-memory-while-using-free-command)
#[cfg(not(target_os = "windows"))]
pub(crate) fn get_cache_usage(sys: &System) -> Option<MemHarvest> {
let mem_used = sys.available_memory().saturating_sub(sys.free_memory());
let mem_total = sys.total_memory();
Some(MemHarvest {
total_bytes: mem_total,
used_bytes: mem_used,
use_percent: if mem_total == 0 {
None
} else {
Some(mem_used as f64 / mem_total as f64 * 100.0)
},
})
}

View File

@ -997,6 +997,7 @@ Supported widget names:
pub struct UsedWidgets {
pub use_cpu: bool,
pub use_mem: bool,
pub use_cache: bool,
pub use_gpu: bool,
pub use_net: bool,
pub use_proc: bool,

View File

@ -20,6 +20,13 @@ use std::{
};
use anyhow::{Context, Result};
use crossterm::{
event::{EnableBracketedPaste, EnableMouseCapture},
execute,
terminal::{enable_raw_mode, EnterAlternateScreen},
};
use tui::{backend::CrosstermBackend, Terminal};
use bottom::{
canvas::{self, canvas_styling::CanvasColours},
constants::*,
@ -27,12 +34,6 @@ use bottom::{
options::*,
*,
};
use crossterm::{
event::{EnableBracketedPaste, EnableMouseCapture},
execute,
terminal::{enable_raw_mode, EnterAlternateScreen},
};
use tui::{backend::CrosstermBackend, Terminal};
// #[global_allocator]
// static ALLOC: dhat::Alloc = dhat::Alloc;
@ -245,6 +246,11 @@ fn main() -> Result<()> {
if app.used_widgets.use_mem {
app.converted_data.mem_data =
convert_mem_data_points(&app.data_collection);
#[cfg(not(target_os = "windows"))]
{
app.converted_data.cache_data =
convert_cache_data_points(&app.data_collection);
}
app.converted_data.swap_data =
convert_swap_data_points(&app.data_collection);
#[cfg(feature = "zfs")]
@ -257,11 +263,17 @@ fn main() -> Result<()> {
app.converted_data.gpu_data =
convert_gpu_data(&app.data_collection);
}
let (memory_labels, swap_labels) =
convert_mem_labels(&app.data_collection);
app.converted_data.mem_labels = memory_labels;
app.converted_data.swap_labels = swap_labels;
app.converted_data.mem_labels =
convert_mem_label(&app.data_collection.memory_harvest);
app.converted_data.swap_labels =
convert_mem_label(&app.data_collection.swap_harvest);
#[cfg(not(target_os = "windows"))]
{
app.converted_data.cache_labels =
convert_mem_label(&app.data_collection.cache_harvest);
}
#[cfg(feature = "zfs")]
{
let arc_labels = convert_arc_labels(&app.data_collection);

View File

@ -435,6 +435,13 @@ impl Painter {
}
}
#[cfg(not(target_os = "windows"))]
{
if app_state.converted_data.cache_labels.is_some() {
mem_rows += 1;
}
}
#[cfg(feature = "gpu")]
{
if let Some(gpu_data) = &app_state.converted_data.gpu_data {

View File

@ -18,6 +18,8 @@ pub struct CanvasColours {
pub currently_selected_text_style: Style,
pub table_header_style: Style,
pub ram_style: Style,
#[cfg(not(target_os = "windows"))]
pub cache_style: Style,
pub swap_style: Style,
pub arc_style: Style,
pub gpu_colour_styles: Vec<Style>,
@ -54,6 +56,8 @@ impl Default for CanvasColours {
.bg(currently_selected_bg_colour),
table_header_style: Style::default().fg(HIGHLIGHT_COLOUR),
ram_style: Style::default().fg(FIRST_COLOUR),
#[cfg(not(target_os = "windows"))]
cache_style: Style::default().fg(FIFTH_COLOUR),
swap_style: Style::default().fg(SECOND_COLOUR),
arc_style: Style::default().fg(THIRD_COLOUR),
gpu_colour_styles: vec![
@ -162,6 +166,12 @@ impl CanvasColours {
.context("Update 'ram_color' in your config file..")?;
}
#[cfg(not(target_os = "windows"))]
if let Some(cache_color) = &colours.cache_color {
self.set_cache_colour(cache_color)
.context("Update 'cache_color' in your config file..")?;
}
if let Some(swap_color) = &colours.swap_color {
self.set_swap_colour(swap_color)
.context("Update 'swap_color' in your config file..")?;
@ -275,6 +285,12 @@ impl CanvasColours {
Ok(())
}
#[cfg(not(target_os = "windows"))]
pub fn set_cache_colour(&mut self, colour: &str) -> error::Result<()> {
self.cache_style = str_to_fg(colour)?;
Ok(())
}
pub fn set_swap_colour(&mut self, colour: &str) -> error::Result<()> {
self.swap_style = str_to_fg(colour)?;
Ok(())

View File

@ -9,6 +9,8 @@ pub const FIRST_COLOUR: Color = Color::LightMagenta;
pub const SECOND_COLOUR: Color = Color::LightYellow;
pub const THIRD_COLOUR: Color = Color::LightCyan;
pub const FOURTH_COLOUR: Color = Color::LightGreen;
#[cfg(not(target_os = "windows"))]
pub const FIFTH_COLOUR: Color = Color::LightRed;
pub const HIGHLIGHT_COLOUR: Color = Color::LightBlue;
pub const AVG_COLOUR: Color = Color::Red;
pub const ALL_COLOUR: Color = Color::Green;

View File

@ -53,6 +53,33 @@ impl Painter {
.gauge_style(self.colours.ram_style),
);
#[cfg(not(target_os = "windows"))]
{
if let Some((_, label_frac)) = &app_state.converted_data.cache_labels {
let cache_data = &app_state.converted_data.cache_data;
let cache_percentage = if let Some(cache) = cache_data.last() {
cache.1
} else {
0.0
};
let cache_fraction_label = if app_state.basic_mode_use_percent {
format!("{:3.0}%", cache_percentage.round())
} else {
label_frac.trim().to_string()
};
draw_widgets.push(
PipeGauge::default()
.ratio(cache_percentage / 100.0)
.start_label("CHE")
.inner_label(cache_fraction_label)
.label_style(self.colours.cache_style)
.gauge_style(self.colours.cache_style),
);
}
}
let swap_data = &app_state.converted_data.swap_data;
let swap_percentage = if let Some(swap) = swap_data.last() {

View File

@ -56,6 +56,15 @@ impl Painter {
name: Some(mem_label.into()),
});
}
#[cfg(not(target_os = "windows"))]
if let Some((label_percent, label_frac)) = &app_state.converted_data.cache_labels {
let cache_label = format!("CHE:{}{}", label_percent, label_frac);
points.push(GraphData {
points: &app_state.converted_data.cache_data,
style: self.colours.cache_style,
name: Some(cache_label.into()),
});
}
if let Some((label_percent, label_frac)) = &app_state.converted_data.swap_labels {
let swap_label = format!("SWP:{}{}", label_percent, label_frac);
points.push(GraphData {

View File

@ -441,6 +441,14 @@ use CPU (3) as the default instead.
app = app.arg(enable_gpu_memory);
}
#[cfg(not(target_os = "windows"))]
{
let cache = Arg::new("enable_cache_memory")
.long("enable_cache_memory")
.help("Enable collecting and displaying cache and buffer memory.");
app = app.arg(cache);
}
app
}

View File

@ -37,6 +37,8 @@ pub static DEFAULT_LIGHT_MODE_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(||
graph_color: Some("black".into()),
disabled_text_color: Some("gray".into()),
ram_color: Some("blue".into()),
#[cfg(not(target_os = "windows"))]
cache_color: Some("LightRed".into()),
swap_color: Some("red".into()),
arc_color: Some("LightBlue".into()),
gpu_core_colors: Some(vec![
@ -91,6 +93,8 @@ pub static GRUVBOX_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColo
"#af3a03".into(),
]),
ram_color: Some("#8ec07c".into()),
#[cfg(not(target_os = "windows"))]
cache_color: Some("#b16286".into()),
swap_color: Some("#fabd2f".into()),
arc_color: Some("#689d6a".into()),
gpu_core_colors: Some(vec![
@ -146,6 +150,8 @@ pub static GRUVBOX_LIGHT_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| Conf
"#af3a03".into(),
]),
ram_color: Some("#427b58".into()),
#[cfg(not(target_os = "windows"))]
cache_color: Some("d79921".into()),
swap_color: Some("#cc241d".into()),
arc_color: Some("#689d6a".into()),
gpu_core_colors: Some(vec![
@ -189,6 +195,8 @@ pub static NORD_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColours
"#bf616a".into(),
]),
ram_color: Some("#88c0d0".into()),
#[cfg(not(target_os = "windows"))]
cache_color: Some("#d8dee9".into()),
swap_color: Some("#d08770".into()),
arc_color: Some("#5e81ac".into()),
gpu_core_colors: Some(vec![
@ -232,6 +240,8 @@ pub static NORD_LIGHT_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigC
"#bf616a".into(),
]),
ram_color: Some("#81a1c1".into()),
#[cfg(not(target_os = "windows"))]
cache_color: Some("#4c566a".into()),
swap_color: Some("#d08770".into()),
arc_color: Some("#5e81ac".into()),
gpu_core_colors: Some(vec![

View File

@ -3,6 +3,7 @@
use kstring::KString;
use crate::app::data_harvester::memory::MemHarvest;
use crate::app::{
data_farmer::DataCollection,
data_harvester::{cpu::CpuDataType, temperature::TemperatureType},
@ -68,9 +69,13 @@ pub struct ConvertedData {
pub network_data_tx: Vec<Point>,
pub mem_labels: Option<(String, String)>,
#[cfg(not(target_os = "windows"))]
pub cache_labels: Option<(String, String)>,
pub swap_labels: Option<(String, String)>,
pub mem_data: Vec<Point>, /* TODO: Switch this and all data points over to a better data structure... */
#[cfg(not(target_os = "windows"))]
pub cache_data: Vec<Point>,
pub swap_data: Vec<Point>,
#[cfg(feature = "zfs")]
@ -219,6 +224,25 @@ pub fn convert_mem_data_points(current_data: &DataCollection) -> Vec<Point> {
result
}
#[cfg(not(target_os = "windows"))]
pub fn convert_cache_data_points(current_data: &DataCollection) -> Vec<Point> {
let mut result: Vec<Point> = Vec::new();
let current_time = current_data.current_instant;
for (time, data) in &current_data.timed_data_vec {
if let Some(cache_data) = data.cache_data {
let time_from_start: f64 =
(current_time.duration_since(*time).as_millis() as f64).floor();
result.push((-time_from_start, cache_data));
if *time == current_time {
break;
}
}
}
result
}
pub fn convert_swap_data_points(current_data: &DataCollection) -> Vec<Point> {
let mut result: Vec<Point> = Vec::new();
let current_time = current_data.current_instant;
@ -257,52 +281,23 @@ fn get_mem_binary_unit_and_denominator(bytes: u64) -> (&'static str, f64) {
}
}
pub fn convert_mem_labels(
current_data: &DataCollection,
) -> (Option<(String, String)>, Option<(String, String)>) {
(
if current_data.memory_harvest.total_bytes > 0 {
Some((
format!(
"{:3.0}%",
current_data.memory_harvest.use_percent.unwrap_or(0.0)
),
{
let (unit, denominator) = get_mem_binary_unit_and_denominator(
current_data.memory_harvest.total_bytes,
);
/// Returns the unit type and denominator for given total amount of memory in kibibytes.
pub fn convert_mem_label(harvest: &MemHarvest) -> Option<(String, String)> {
if harvest.total_bytes > 0 {
Some((format!("{:3.0}%", harvest.use_percent.unwrap_or(0.0)), {
let (unit, denominator) = get_mem_binary_unit_and_denominator(harvest.total_bytes);
format!(
" {:.1}{unit}/{:.1}{unit}",
current_data.memory_harvest.used_bytes as f64 / denominator,
(current_data.memory_harvest.total_bytes as f64 / denominator),
)
},
))
} else {
None
},
if current_data.swap_harvest.total_bytes > 0 {
Some((
format!(
"{:3.0}%",
current_data.swap_harvest.use_percent.unwrap_or(0.0)
),
{
let (unit, denominator) =
get_mem_binary_unit_and_denominator(current_data.swap_harvest.total_bytes);
format!(
" {:.1}{unit}/{:.1}{unit}",
current_data.swap_harvest.used_bytes as f64 / denominator,
(current_data.swap_harvest.total_bytes as f64 / denominator),
)
},
))
} else {
None
},
)
format!(
" {:.1}{}/{:.1}{}",
harvest.used_bytes as f64 / denominator,
unit,
(harvest.total_bytes as f64 / denominator),
unit
)
}))
} else {
None
}
}
pub fn get_rx_tx_data_points(

View File

@ -386,6 +386,10 @@ pub fn update_data(app: &mut App) {
// TODO: [OPT] Prefer reassignment over new vectors?
if app.mem_state.force_update.is_some() {
app.converted_data.mem_data = convert_mem_data_points(data_source);
#[cfg(not(target_os = "windows"))]
{
app.converted_data.cache_data = convert_cache_data_points(data_source);
}
app.converted_data.swap_data = convert_swap_data_points(data_source);
#[cfg(feature = "zfs")]
{

View File

@ -79,6 +79,7 @@ pub struct ConfigFlags {
pub network_use_log: Option<bool>,
pub network_use_binary_prefix: Option<bool>,
pub enable_gpu_memory: Option<bool>,
pub enable_cache_memory: Option<bool>,
#[serde(with = "humantime_serde")]
#[serde(default)]
pub retention: Option<Duration>,
@ -91,6 +92,8 @@ pub struct ConfigColours {
pub avg_cpu_color: Option<Cow<'static, str>>,
pub cpu_core_colors: Option<Vec<Cow<'static, str>>>,
pub ram_color: Option<Cow<'static, str>>,
#[cfg(not(target_os = "windows"))]
pub cache_color: Option<Cow<'static, str>>,
pub swap_color: Option<Cow<'static, str>>,
pub arc_color: Option<Cow<'static, str>>,
pub gpu_core_colors: Option<Vec<Cow<'static, str>>>,
@ -235,6 +238,7 @@ pub fn build_app(
table_gap: u16::from(!(is_flag_enabled!(hide_table_gap, matches, config))),
disable_click: is_flag_enabled!(disable_click, matches, config),
enable_gpu_memory: get_enable_gpu_memory(matches, config),
enable_cache_memory: get_enable_cache_memory(matches, config),
show_table_scroll_position: is_flag_enabled!(show_table_scroll_position, matches, config),
is_advanced_kill,
network_scale_type,
@ -382,6 +386,7 @@ pub fn build_app(
let used_widgets = UsedWidgets {
use_cpu: used_widget_set.get(&Cpu).is_some() || used_widget_set.get(&BasicCpu).is_some(),
use_mem,
use_cache: use_mem && get_enable_cache_memory(matches, config),
use_gpu: use_mem && get_enable_gpu_memory(matches, config),
use_net: used_widget_set.get(&Net).is_some() || used_widget_set.get(&BasicNet).is_some(),
use_proc: used_widget_set.get(&Proc).is_some(),
@ -712,6 +717,22 @@ fn get_enable_gpu_memory(matches: &ArgMatches, config: &Config) -> bool {
false
}
#[allow(unused_variables)]
fn get_enable_cache_memory(matches: &ArgMatches, config: &Config) -> bool {
#[cfg(not(target_os = "windows"))]
{
if matches.contains_id("enable_cache_memory") {
return true;
} else if let Some(flags) = &config.flags {
if let Some(enable_cache_memory) = flags.enable_cache_memory {
return enable_cache_memory;
}
}
}
false
}
fn get_ignore_list(ignore_list: &Option<IgnoreList>) -> error::Result<Option<Filter>> {
if let Some(ignore_list) = ignore_list {
let list: Result<Vec<_>, _> = ignore_list