diff options
author | Frederick Zhang <frederick888@tsundere.moe> | 2021-01-22 12:53:55 +1100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-21 20:53:55 -0500 |
commit | b8d3b68e75207a584c421f961d6bb21ce92a0a88 (patch) | |
tree | d95c6113cae19b8315f563180cf1db779c2f6549 /src/app | |
parent | 3dd748c2f487113cf38db32401d376a5047b29ac (diff) |
feature: Use `ps` as fallback to query CPU usage under macOS (#390)
When running without elevated permissions under macOS, sysinfo cannot
query states of processes by root user, which results in 0.0% CPU usage
for all this kind of processes (and state = Unknown).
Here we use `ps`, which has SUID, as a fallback to query CPU usages.
This can be potentially applied to other properties if needed in the
future (we'll need a proper struct and parser).
Diffstat (limited to 'src/app')
-rw-r--r-- | src/app/data_harvester/processes.rs | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/app/data_harvester/processes.rs b/src/app/data_harvester/processes.rs index 81ccc7f8..c9233337 100644 --- a/src/app/data_harvester/processes.rs +++ b/src/app/data_harvester/processes.rs @@ -229,6 +229,37 @@ fn get_linux_cpu_usage( } } +#[cfg(target_os = "macos")] +fn get_macos_cpu_usage(pids: &[i32]) -> std::io::Result<std::collections::HashMap<i32, f64>> { + use itertools::Itertools; + let output = std::process::Command::new("ps") + .args(&["-o", "pid=,pcpu=", "-p"]) + .arg( + pids.iter() + .map(i32::to_string) + .intersperse(",".to_string()) + .collect::<String>(), + ) + .output()?; + let mut result = std::collections::HashMap::new(); + String::from_utf8_lossy(&output.stdout) + .split_whitespace() + .chunks(2) + .into_iter() + .for_each(|chunk| { + let chunk: Vec<&str> = chunk.collect(); + if chunk.len() != 2 { + panic!("Unexpected `ps` output"); + } + let pid = chunk[0].parse(); + let usage = chunk[1].parse(); + if let (Ok(pid), Ok(usage)) = (pid, usage) { + result.insert(pid, usage); + } + }); + Ok(result) +} + #[cfg(target_os = "linux")] fn get_uid_and_gid(path: &PathBuf) -> (Option<u32>, Option<u32>) { // FIXME: [OPT] - can we merge our /stat and /status calls? @@ -566,6 +597,26 @@ pub fn get_process_data( } } + #[cfg(target_os = "macos")] + { + let unknown_state = ProcessStatus::Unknown(0).to_string().to_string(); + let cpu_usage_unknown_pids: Vec<i32> = process_vector + .iter() + .filter(|process| process.process_state == unknown_state) + .map(|process| process.pid) + .collect(); + let cpu_usages = get_macos_cpu_usage(&cpu_usage_unknown_pids)?; + for process in &mut process_vector { + if cpu_usages.contains_key(&process.pid) { + process.cpu_usage_percent = if num_cpus == 0.0 { + *cpu_usages.get(&process.pid).unwrap() + } else { + *cpu_usages.get(&process.pid).unwrap() / num_cpus + }; + } + } + } + Ok(process_vector) } |