mirror of
https://github.com/ClementTsang/bottom
synced 2024-09-21 06:42:00 +00:00
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).
This commit is contained in:
parent
3dd748c2f4
commit
b8d3b68e75
1 changed files with 51 additions and 0 deletions
|
@ -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")]
|
#[cfg(target_os = "linux")]
|
||||||
fn get_uid_and_gid(path: &PathBuf) -> (Option<u32>, Option<u32>) {
|
fn get_uid_and_gid(path: &PathBuf) -> (Option<u32>, Option<u32>) {
|
||||||
// FIXME: [OPT] - can we merge our /stat and /status calls?
|
// 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)
|
Ok(process_vector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue