diff --git a/docs/content/configuration/config-file/flags.md b/docs/content/configuration/config-file/flags.md index ed9d0aefb..0fa99a63d 100644 --- a/docs/content/configuration/config-file/flags.md +++ b/docs/content/configuration/config-file/flags.md @@ -42,3 +42,4 @@ each time: | `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. | +| `change_memory_prefix` | String (one of ["KiB", "MiB", "GiB", "TiB", "auto"]) | Change the memory prefix. | diff --git a/sample_configs/default_config.toml b/sample_configs/default_config.toml index a7731dd66..5bd497f69 100644 --- a/sample_configs/default_config.toml +++ b/sample_configs/default_config.toml @@ -27,6 +27,12 @@ #whole_word = false # Whether to make process searching use regex by default. #regex = false +# What prefix should be used for memory. Defaults to "auto". Prefix is one of: +#change_memory_prefix = "auto" +#change_memory_prefix = "KiB" +#change_memory_prefix = "MiB" +#change_memory_prefix = "GiB" +#change_memory_prefix = "TiB" # Defaults to Celsius. Temperature is one of: #temperature_type = "k" #temperature_type = "f" diff --git a/src/app.rs b/src/app.rs index f9e7de16d..691275719 100644 --- a/src/app.rs +++ b/src/app.rs @@ -62,6 +62,7 @@ pub struct AppConfigFields { pub enable_cache_memory: bool, pub show_table_scroll_position: bool, pub is_advanced_kill: bool, + pub change_memory_prefix: String, // TODO: Remove these, move network details state-side. pub network_unit_type: DataUnit, pub network_scale_type: AxisScaling, diff --git a/src/bin/main.rs b/src/bin/main.rs index 0ee3289f3..637cd2b36 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -275,20 +275,28 @@ fn main() -> Result<()> { convert_gpu_data(&app.data_collection); } - 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); + app.converted_data.mem_labels = convert_mem_label( + &app.data_collection.memory_harvest, + app.app_config_fields.change_memory_prefix.clone(), + ); + app.converted_data.swap_labels = convert_mem_label( + &app.data_collection.swap_harvest, + app.app_config_fields.change_memory_prefix.clone(), + ); #[cfg(not(target_os = "windows"))] { - app.converted_data.cache_labels = - convert_mem_label(&app.data_collection.cache_harvest); + app.converted_data.cache_labels = convert_mem_label( + &app.data_collection.cache_harvest, + app.app_config_fields.change_memory_prefix.clone(), + ); } #[cfg(feature = "zfs")] { - let arc_labels = - convert_mem_label(&app.data_collection.arc_harvest); + let arc_labels = convert_mem_label( + &app.data_collection.arc_harvest, + app.app_config_fields.change_memory_prefix.clone(), + ); app.converted_data.arc_labels = arc_labels; } } diff --git a/src/constants.rs b/src/constants.rs index f09a5d5bb..95c8edd20 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -545,6 +545,12 @@ pub const CONFIG_TEXT: &str = r#"# This is a default config file for bottom. Al #whole_word = false # Whether to make process searching use regex by default. #regex = false +# What prefix should be used for memory. Defaults to "auto". Prefix is one of: +#change_memory_prefix = "auto" +#change_memory_prefix = "KiB" +#change_memory_prefix = "MiB" +#change_memory_prefix = "GiB" +#change_memory_prefix = "TiB" # Defaults to Celsius. Temperature is one of: #temperature_type = "k" #temperature_type = "f" diff --git a/src/data_collection.rs b/src/data_collection.rs index d00d88e01..5aee28b2d 100644 --- a/src/data_collection.rs +++ b/src/data_collection.rs @@ -104,6 +104,7 @@ pub struct DataCollector { temperature_type: TemperatureType, use_current_cpu_total: bool, unnormalized_cpu: bool, + change_memory_prefix: String, last_collection_time: Instant, total_rx: u64, total_tx: u64, @@ -146,6 +147,7 @@ impl DataCollector { temperature_type: TemperatureType::Celsius, use_current_cpu_total: false, unnormalized_cpu: false, + change_memory_prefix: String::from("auto"), last_collection_time: Instant::now(), total_rx: 0, total_tx: 0, @@ -226,6 +228,10 @@ impl DataCollector { self.unnormalized_cpu = unnormalized_cpu; } + pub fn set_change_memory_prefix(&mut self, change_memory_prefix: String) { + self.change_memory_prefix = change_memory_prefix; + } + pub fn set_show_average_cpu(&mut self, show_average_cpu: bool) { self.show_average_cpu = show_average_cpu; } diff --git a/src/data_conversion.rs b/src/data_conversion.rs index 0d1c46048..6920751d2 100644 --- a/src/data_conversion.rs +++ b/src/data_conversion.rs @@ -266,8 +266,31 @@ pub fn convert_swap_data_points(current_data: &DataCollection) -> Vec { /// /// The expected usage is to divide out the given value with the returned denominator in order to be able to use it /// with the returned binary unit (e.g. divide 3000 bytes by 1024 to have a value in KiB). -fn get_mem_binary_unit_and_denominator(bytes: u64) -> (&'static str, f64) { - if bytes < KIBI_LIMIT { +fn get_mem_binary_unit_and_denominator( + bytes: u64, change_memory_prefix: String, +) -> (&'static str, f64) { + if change_memory_prefix != "auto" { + return match change_memory_prefix.as_str() { + "KiB" => ("KiB", KIBI_LIMIT_F64), + "MiB" => ("MiB", MEBI_LIMIT_F64), + "GiB" => ("GiB", GIBI_LIMIT_F64), + "TiB" => ("TiB", TEBI_LIMIT_F64), + _ => { + if bytes < KIBI_LIMIT { + // Stick with bytes if under a kibibyte. + ("B", 1.0) + } else if bytes < MEBI_LIMIT { + ("KiB", KIBI_LIMIT_F64) + } else if bytes < GIBI_LIMIT { + ("MiB", MEBI_LIMIT_F64) + } else if bytes < TEBI_LIMIT { + ("GiB", GIBI_LIMIT_F64) + } else { + ("TiB", TEBI_LIMIT_F64) + } + } + }; + } else if bytes < KIBI_LIMIT { // Stick with bytes if under a kibibyte. ("B", 1.0) } else if bytes < MEBI_LIMIT { @@ -277,16 +300,18 @@ fn get_mem_binary_unit_and_denominator(bytes: u64) -> (&'static str, f64) { } else if bytes < TEBI_LIMIT { ("GiB", GIBI_LIMIT_F64) } else { - // Otherwise just use tebibytes, which is probably safe for most use cases. ("TiB", TEBI_LIMIT_F64) } } /// Returns the unit type and denominator for given total amount of memory in kibibytes. -pub fn convert_mem_label(harvest: &MemHarvest) -> Option<(String, String)> { +pub fn convert_mem_label( + harvest: &MemHarvest, change_memory_prefix: String, +) -> 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); + let (unit, denominator) = + get_mem_binary_unit_and_denominator(harvest.total_bytes, change_memory_prefix); format!( " {:.1}{}/{:.1}{}", @@ -613,8 +638,10 @@ pub fn convert_gpu_data(current_data: &DataCollection) -> Option, dot_marker: Option, temperature_type: Option, + change_memory: Option, rate: Option, left_legend: Option, current_usage: Option, unnormalized_cpu: Option, + change_memory_prefix: Option, group_processes: Option, case_sensitive: Option, whole_word: Option, @@ -271,6 +273,8 @@ pub fn init_app( left_legend: is_flag_enabled!(left_legend, matches, config), use_current_cpu_total: is_flag_enabled!(current_usage, matches, config), unnormalized_cpu: is_flag_enabled!(unnormalized_cpu, matches, config), + change_memory_prefix: get_change_memory_prefix(matches, config) + .context("Update 'change_memory_prefix' in your config file.")?, use_basic_mode, default_time_value, time_interval: get_time_interval(matches, config, retention_ms) @@ -615,6 +619,19 @@ fn get_show_average_cpu(matches: &ArgMatches, config: &Config) -> bool { true } +fn get_change_memory_prefix(matches: &ArgMatches, config: &Config) -> error::Result { + if let Some(change_memory_prefix) = matches.get_one::("change_memory_prefix") { + Ok(change_memory_prefix.to_string()) + } else if let Some(flags) = &config.flags { + if let Some(prefix) = &flags.change_memory_prefix { + Ok(prefix.clone()) + } else { + Ok("auto".to_string()) + } + } else { + Ok("auto".to_string()) + } +} fn try_parse_ms(s: &str) -> error::Result { if let Ok(val) = humantime::parse_duration(s) { Ok(val.as_millis().try_into()?) diff --git a/src/options/args.rs b/src/options/args.rs index 2c524da8a..c69b74d55 100644 --- a/src/options/args.rs +++ b/src/options/args.rs @@ -403,6 +403,12 @@ use CPU (3) as the default instead. .action(ArgAction::Version) .help("Prints version information."); + let change_memory_prefix = Arg::new("change_memory_prefix") + .long("change_memory_prefix") + .action(ArgAction::Set) + .help("Displays the memory widget with a mega prefix.") + .long_help("Displays the memory widget in megabibytes instead of rounding it to the nearest prefix. Defaults to rounding it to the nearest prefix. Example: 1.2GiB will be displayed as 1228MiB."); + const VERSION: &str = match option_env!("NIGHTLY_VERSION") { Some(nightly_version) => nightly_version, None => crate_version!(), @@ -426,6 +432,7 @@ use CPU (3) as the default instead. config_location, color, mem_as_value, + change_memory_prefix, default_time_value, default_widget_count, default_widget_type,