summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClement Tsang <34804052+ClementTsang@users.noreply.github.com>2022-11-21 05:28:42 -0500
committerGitHub <noreply@github.com>2022-11-21 05:28:42 -0500
commit4f00434210a20109f4b9ca27c1b1856f376499b5 (patch)
tree0ce69bbc487460c2acdecbc84d42e73b6faaecb9
parentf887096ceae26c06a690c6400569cf2e74a79dec (diff)
other: non-normalized process CPU% cleanup and docs (#910)
* refactor: simplify non-normalized code * update docs * appease clippy * add comment * unnormalized * fix issues on non-Linux regarding typos/imports
-rw-r--r--CHANGELOG.md1
-rw-r--r--docs/content/configuration/command-line-flags.md79
-rw-r--r--docs/content/configuration/config-file/flags.md65
-rw-r--r--sample_configs/default_config.toml3
-rw-r--r--src/app.rs2
-rw-r--r--src/app/data_harvester.rs58
-rw-r--r--src/app/data_harvester/processes/freebsd.rs4
-rw-r--r--src/app/data_harvester/processes/linux.rs75
-rw-r--r--src/app/data_harvester/processes/macos.rs4
-rw-r--r--src/app/data_harvester/processes/macos_freebsd.rs16
-rw-r--r--src/app/data_harvester/processes/windows.rs8
-rw-r--r--src/clap.rs10
-rw-r--r--src/constants.rs2
-rw-r--r--src/lib.rs6
-rw-r--r--src/options.rs12
15 files changed, 190 insertions, 155 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5b11afe..d134d3f8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#870](https://github.com/ClementTsang/bottom/pull/870): Make disk widget sortable.
- [#881](https://github.com/ClementTsang/bottom/pull/881): Add pasting to the search bar.
- [#892](https://github.com/ClementTsang/bottom/pull/892): Add custom retention periods for data.
+- [#899](https://github.com/ClementTsang/bottom/pull/899): Add non-normalized CPU usage to processes.
## [0.6.8] - 2022-02-01
diff --git a/docs/content/configuration/command-line-flags.md b/docs/content/configuration/command-line-flags.md
index febf2068..6780e392 100644
--- a/docs/content/configuration/command-line-flags.md
+++ b/docs/content/configuration/command-line-flags.md
@@ -6,42 +6,43 @@
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 <CONFIG PATH>` | Sets the location of the config file. |
-| `-u, --current_usage` | Sets process CPU% to be based on current CPU%. |
-| `-t, --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, --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. |
+| 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 <CONFIG PATH>` | Sets the location of the config file. |
+| `-u, --current_usage` | Sets process CPU% to be based on current CPU%. |
+| `-t, --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, --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. |
+| `--unnormalized_cpu` | Show process CPU% without normalizing over the number of cores. |
diff --git a/docs/content/configuration/config-file/flags.md b/docs/content/configuration/config-file/flags.md
index 5aa218ca..606eef63 100644
--- a/docs/content/configuration/config-file/flags.md
+++ b/docs/content/configuration/config-file/flags.md
@@ -6,35 +6,36 @@
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. |
+| 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. |
diff --git a/sample_configs/default_config.toml b/sample_configs/default_config.toml
index a2eabb38..bab1833d 100644
--- a/sample_configs/default_config.toml
+++ b/sample_configs/default_config.toml
@@ -18,7 +18,7 @@
# Whether to set CPU% on a process to be based on the total CPU or just current usage.
#current_usage = false
# Whether to set CPU% on a process to be based on the total CPU or per-core CPU% (not divided by the number of cpus).
-#per_core_percentage = false
+#unnormalized_cpu = false
# Whether to group processes with the same name together by default.
#group_processes = false
# Whether to make process searching case sensitive by default.
@@ -148,7 +148,6 @@
# type="proc"
# default=true
-
# Filters - you can hide specific temperature sensors, network interfaces, and disks using filters. This is admittedly
# a bit hard to use as of now, and there is a planned in-app interface for managing this in the future:
#[disk_filter]
diff --git a/src/app.rs b/src/app.rs
index 5b75e50f..4e77998a 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -57,7 +57,7 @@ pub struct AppConfigFields {
pub left_legend: bool,
pub show_average_cpu: bool,
pub use_current_cpu_total: bool,
- pub per_core_percentage: bool,
+ pub unnormalized_cpu: bool,
pub use_basic_mode: bool,
pub default_time_value: u64,
pub time_interval: u64,
diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs
index 1d28a020..b4d437a5 100644
--- a/src/app/data_harvester.rs
+++ b/src/app/data_harvester.rs
@@ -112,7 +112,7 @@ pub struct DataCollector {
mem_total_kb: u64,
temperature_type: temperature::TemperatureType,
use_current_cpu_total: bool,
- per_core_percentage: bool,
+ unnormalized_cpu: bool,
last_collection_time: Instant,
total_rx: u64,
total_tx: u64,
@@ -145,7 +145,7 @@ impl DataCollector {
mem_total_kb: 0,
temperature_type: temperature::TemperatureType::Celsius,
use_current_cpu_total: false,
- per_core_percentage: false,
+ unnormalized_cpu: false,
last_collection_time: Instant::now(),
total_rx: 0,
total_tx: 0,
@@ -237,8 +237,8 @@ impl DataCollector {
self.use_current_cpu_total = use_current_cpu_total;
}
- pub fn set_per_core_percentage(&mut self, per_core_percentage: bool) {
- self.per_core_percentage = per_core_percentage;
+ pub fn set_unnormalized_cpu(&mut self, unnormalized_cpu: bool) {
+ self.unnormalized_cpu = unnormalized_cpu;
}
pub fn set_show_average_cpu(&mut self, show_average_cpu: bool) {
@@ -327,39 +327,42 @@ impl DataCollector {
}
if self.widgets_to_harvest.use_proc {
- #[cfg(target_os = "linux")]
- {
- if let Ok(logical_count) = heim::cpu::logical_count().await {
- if let Ok(mut process_list) = processes::get_process_data(
+ if let Ok(mut process_list) = {
+ #[cfg(target_os = "linux")]
+ {
+ // Must do this here since we otherwise have to make `get_process_data` async.
+ use self::processes::CpuUsageStrategy;
+
+ let normalize_cpu = if self.unnormalized_cpu {
+ heim::cpu::logical_count()
+ .await
+ .map(|v| CpuUsageStrategy::NonNormalized(v as f64))
+ .unwrap_or(CpuUsageStrategy::Normalized)
+ } else {
+ CpuUsageStrategy::Normalized
+ };
+
+ processes::get_process_data(
&mut self.prev_idle,
&mut self.prev_non_idle,
&mut self.pid_mapping,
self.use_current_cpu_total,
- self.per_core_percentage,
+ normalize_cpu,
current_instant
.duration_since(self.last_collection_time)
.as_secs(),
self.mem_total_kb,
- logical_count,
&mut self.user_table,
- ) {
- // NB: To avoid duplicate sorts on rerenders/events, we sort the processes by PID here.
- // We also want to avoid re-sorting *again* since this process list is sorted!
- process_list.sort_unstable_by_key(|p| p.pid);
- self.data.list_of_processes = Some(process_list);
- }
+ )
}
- }
-
- #[cfg(not(target_os = "linux"))]
- {
- if let Ok(mut process_list) = {
+ #[cfg(not(target_os = "linux"))]
+ {
#[cfg(target_family = "unix")]
{
processes::get_process_data(
&self.sys,
self.use_current_cpu_total,
- self.per_core_percentage,
+ self.unnormalized_cpu,
self.mem_total_kb,
&mut self.user_table,
)
@@ -369,14 +372,17 @@ impl DataCollector {
processes::get_process_data(
&self.sys,
self.use_current_cpu_total,
- self.per_core_percentage,
+ self.unnormalized_cpu,
self.mem_total_kb,
)
}
- } {
- process_list.sort_unstable_by_key(|p| p.pid);
- self.data.list_of_processes = Some(process_list);
}
+ } {
+ // NB: To avoid duplicate sorts on rerenders/events, we sort the processes by PID here.
+ // We also want to avoid re-sorting *again* later on if we're sorting by PID, since we already
+ // did it here!
+ process_list.sort_unstable_by_key(|p| p.pid);
+ self.data.list_of_processes = Some(process_list);
}
}
diff --git a/src/app/data_harvester/processes/freebsd.rs b/src/app/data_harvester/processes/freebsd.rs
index cbcb5eb1..4c5a9e45 100644
--- a/src/app/data_harvester/processes/freebsd.rs
+++ b/src/app/data_harvester/processes/freebsd.rs
@@ -25,13 +25,13 @@ struct ProcessRow {
}
pub fn get_process_data(
- sys: &System, use_current_cpu_total: bool, per_core_percentage: bool, mem_total_kb: u64,
+ sys: &System, use_current_cpu_total: bool, unnormalized_cpu: bool, mem_total_kb: u64,
user_table: &mut UserTable,
) -> crate::utils::error::Result<Vec<ProcessHarvest>> {
super::macos_freebsd::get_process_data(
sys,
use_current_cpu_total,
- per_core_percentage,
+ unnormalized_cpu,
mem_total_kb,
user_table,
get_freebsd_process_cpu_usage,
diff --git a/src/app/data_harvester/processes/linux.rs b/src/app/data_harvester/processes/linux.rs
index d024389d..282e56a3 100644
--- a/src/app/data_harvester/processes/linux.rs
+++ b/src/app/data_harvester/processes/linux.rs
@@ -48,7 +48,15 @@ fn calculate_idle_values(line: &str) -> Point {
(idle, non_idle)
}
-fn cpu_usage_calculation(prev_idle: &mut f64, prev_non_idle: &mut f64) -> error::Result<Point> {
+struct CpuUsage {
+ /// Difference between the total delta and the idle delta.
+ cpu_usage: f64,
+
+ /// Overall CPU usage as a fraction.
+ cpu_fraction: f64,
+}
+
+fn cpu_usage_calculation(prev_idle: &mut f64, prev_non_idle: &mut f64) -> error::Result<CpuUsage> {
let (idle, non_idle) = {
// From SO answer: https://stackoverflow.com/a/23376195
let mut reader = BufReader::new(File::open("/proc/stat")?);
@@ -68,38 +76,37 @@ fn cpu_usage_calculation(prev_idle: &mut f64, prev_non_idle: &mut f64) -> error:
*prev_non_idle = non_idle;
// TODO: Should these return errors instead?
- let result = if total_delta - idle_delta != 0.0 {
+ let cpu_usage = if total_delta - idle_delta != 0.0 {
total_delta - idle_delta
} else {
1.0
};
- let cpu_percentage = if total_delta != 0.0 {
- result / total_delta
+ let cpu_fraction = if total_delta != 0.0 {
+ cpu_usage / total_delta
} else {
0.0
};
- Ok((result, cpu_percentage))
+ Ok(CpuUsage {
+ cpu_usage,
+ cpu_fraction,
+ })
}
-/// Returns the usage and a new set of process times. Note: cpu_fraction should be represented WITHOUT the x100 factor!
-#[inline]
+/// Returns the usage and a new set of process times.
+///
+/// NB: cpu_fraction should be represented WITHOUT the x100 factor!
fn get_linux_cpu_usage(
- stat: &Stat, cpu_usage: f64, cpu_fraction: f64, prev_proc_times: u64, logical_count: u64,
- use_current_cpu_total: bool, per_core_percentage: bool,
+ stat: &Stat, cpu_usage: f64, cpu_fraction: f64, prev_proc_times: u64,
+ use_current_cpu_total: bool,
) -> (f64, u64) {
// Based heavily on https://stackoverflow.com/a/23376195 and https://stackoverflow.com/a/1424556
let new_proc_times = stat.utime + stat.stime;
- let diff = (new_proc_times - prev_proc_times) as f64; // I HATE that it's done like this but there isn't a try_from for u64 -> f64... we can accept a bit of loss in the worst case though
+ let diff = (new_proc_times - prev_proc_times) as f64; // No try_from for u64 -> f64... oh well.
if cpu_usage == 0.0 {
(0.0, new_proc_times)
- } else if per_core_percentage {
- (
- diff / cpu_usage * 100_f64 * cpu_fraction * (logical_count as f64),
- new_proc_times,
- )
} else if use_current_cpu_total {
((diff / cpu_usage) * 100.0, new_proc_times)
} else {
@@ -107,11 +114,10 @@ fn get_linux_cpu_usage(
}
}
-#[allow(clippy::too_many_arguments)]
fn read_proc(
prev_proc: &PrevProcDetails, process: &Process, cpu_usage: f64, cpu_fraction: f64,
- use_current_cpu_total: bool, per_core_percentage: bool, time_difference_in_secs: u64,
- mem_total_kb: u64, logical_count: u64, user_table: &mut UserTable,
+ use_current_cpu_total: bool, time_difference_in_secs: u64, mem_total_kb: u64,
+ user_table: &mut UserTable,
) -> error::Result<(ProcessHarvest, u64)> {
let stat = process.stat()?;
let (command, name) = {
@@ -154,9 +160,7 @@ fn read_proc(
cpu_usage,
cpu_fraction,
prev_proc.cpu_time,
- logical_count,
use_current_cpu_total,
- per_core_percentage,
);
let parent_pid = Some(stat.ppid);
let mem_usage_bytes = stat.rss_bytes()?;
@@ -164,7 +168,6 @@ fn read_proc(
let mem_usage_percent = mem_usage_kb as f64 / mem_total_kb as f64 * 100.0;
// This can fail if permission is denied!
-
let (total_read_bytes, total_write_bytes, read_bytes_per_sec, write_bytes_per_sec) =
if let Ok(io) = process.io() {
let total_read_bytes = io.read_bytes;
@@ -218,16 +221,38 @@ fn read_proc(
))
}
-#[allow(clippy::too_many_arguments)]
+/// How to calculate CPU usage.
+pub enum CpuUsageStrategy {
+ /// Normalized means the displayed usage percentage is divided over the number of CPU cores.
+ ///
+ /// For example, if the "overall" usage over the entire system is 105%, and there are 5 cores, then
+ /// the displayed percentage is 21%.
+ Normalized,
+
+ /// Non-normalized means that the overall usage over the entire system is shown, without dividing
+ /// over the number of cores.
+ NonNormalized(f64),
+}
+
pub fn get_process_data(
prev_idle: &mut f64, prev_non_idle: &mut f64,
pid_mapping: &mut FxHashMap<Pid, PrevProcDetails>, use_current_cpu_total: bool,
- per_core_percentage: bool, time_difference_in_secs: u64, mem_total_kb: u64, logical_count: u64,
+ normalization: CpuUsageStrategy, time_difference_in_secs: u64, mem_total_kb: u64,
user_table: &mut UserTable,
) -> crate::utils::error::Result<Vec<ProcessHarvest>> {
// TODO: [PROC THREADS] Add threads
- if let Ok((cpu_usage, cpu_fraction)) = cpu_usage_calculation(prev_idle, prev_non_idle) {
+ if let Ok(CpuUsage {
+ mut cpu_usage,
+ cpu_fraction,
+ }) = cpu_usage_calculation(prev_idle, prev_non_idle)
+ {
+ if let CpuUsageStrategy::NonNormalized(num_cores) = normalization {
+ // Note we *divide* here because the later calculation divides `cpu_usage` - in effect,
+ // multiplying over the number of cores.
+ cpu_usage /= num_cores;
+ }
+
let mut pids_to_clear: FxHashSet<Pid> = pid_mapping.keys().cloned().collect();
let process_vector: Vec<ProcessHarvest> = std::fs::read_dir("/proc")?
@@ -245,10 +270,8 @@ pub fn get_process_data(
cpu_usage,
cpu_fraction,
use_current_cpu_total,
- per_core_percentage,
time_difference_in_secs,
mem_total_kb,
- logical_count,
user_table,
) {
prev_proc_details.cpu_time = new_process_times;
diff --git a/src/app/data_harvester/processes/macos.rs b/src/app/data_harvester/processes/macos.rs
index c3570290..a2b61b69 100644
--- a/src/app/data_harvester/processes/macos.rs
+++ b/src/app/data_harvester/processes/macos.rs
@@ -7,13 +7,13 @@ use crate::{data_harvester::processes::UserTable, Pid};
mod sysctl_bindings;
pub fn get_process_data(
- sys: &System, use_current_cpu_total: bool, per_core_percentage: bool, mem_total_kb: u64,
+ sys: &System, use_current_cpu_total: bool, unnormalized_cpu: bool, mem_total_kb: u64,
user_table: &mut UserTable,
) -> crate::utils::error::Result<Vec<ProcessHarvest>> {
super::macos_freebsd::get_process_data(
sys,
use_current_cpu_total,
- per_core_percentage,
+ unnormalized_cpu,
mem_total_kb,
user_table,
get_macos_process_cpu_usage,
diff --git a/src/app/data_harvester/processes/macos_freebsd.rs b/src/app/data_harvester/processes/macos_freebsd.rs
index 3f2e340d..251bc847 100644
--- a/src/app/data_harvester/processes/macos_freebsd.rs
+++ b/src/app/data_harvester/processes/macos_freebsd.rs
@@ -9,8 +9,8 @@ use super::ProcessHarvest;
use crate::{data_harvester::processes::UserTable, utils::error::Result, Pid};
pub fn get_process_data<F>(
- sys: &System, use_current_cpu_total: bool, per_core_percentage: bool, mem_total_kb: u64,
- user_table: &mut UserTable, get_process_cpu_usage: F,
+ sys: &System, use_current_cpu_total: bool, unnormalized_cpu: bool, mem_total_kb: u64,
+ user_table: &mut UserTable, backup_cpu_proc_usage: F,
) -> Result<Vec<ProcessHarvest>>
where
F: Fn(&[Pid]) -> io::Result<HashMap<Pid, f64>>,
@@ -18,6 +18,8 @@ where
let mut process_vector: Vec<ProcessHarvest> = Vec::new();
let process_hashmap = sys.processes();
let cpu_usage = sys.global_cpu_info().cpu_usage() as f64 / 100.0;
+ let num_processors = sys.cpus().len() as f64;
+
for process_val in process_hashmap.values() {
let name = if process_val.name().is_empty() {
let process_cmd = process_val.cmd