Skip to content

Commit b8d3b68

Browse files
authored
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).
1 parent 3dd748c commit b8d3b68

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

src/app/data_harvester/processes.rs

+51
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,37 @@ fn get_linux_cpu_usage(
229229
}
230230
}
231231

232+
#[cfg(target_os = "macos")]
233+
fn get_macos_cpu_usage(pids: &[i32]) -> std::io::Result<std::collections::HashMap<i32, f64>> {
234+
use itertools::Itertools;
235+
let output = std::process::Command::new("ps")
236+
.args(&["-o", "pid=,pcpu=", "-p"])
237+
.arg(
238+
pids.iter()
239+
.map(i32::to_string)
240+
.intersperse(",".to_string())
241+
.collect::<String>(),
242+
)
243+
.output()?;
244+
let mut result = std::collections::HashMap::new();
245+
String::from_utf8_lossy(&output.stdout)
246+
.split_whitespace()
247+
.chunks(2)
248+
.into_iter()
249+
.for_each(|chunk| {
250+
let chunk: Vec<&str> = chunk.collect();
251+
if chunk.len() != 2 {
252+
panic!("Unexpected `ps` output");
253+
}
254+
let pid = chunk[0].parse();
255+
let usage = chunk[1].parse();
256+
if let (Ok(pid), Ok(usage)) = (pid, usage) {
257+
result.insert(pid, usage);
258+
}
259+
});
260+
Ok(result)
261+
}
262+
232263
#[cfg(target_os = "linux")]
233264
fn get_uid_and_gid(path: &PathBuf) -> (Option<u32>, Option<u32>) {
234265
// FIXME: [OPT] - can we merge our /stat and /status calls?
@@ -566,6 +597,26 @@ pub fn get_process_data(
566597
}
567598
}
568599

600+
#[cfg(target_os = "macos")]
601+
{
602+
let unknown_state = ProcessStatus::Unknown(0).to_string().to_string();
603+
let cpu_usage_unknown_pids: Vec<i32> = process_vector
604+
.iter()
605+
.filter(|process| process.process_state == unknown_state)
606+
.map(|process| process.pid)
607+
.collect();
608+
let cpu_usages = get_macos_cpu_usage(&cpu_usage_unknown_pids)?;
609+
for process in &mut process_vector {
610+
if cpu_usages.contains_key(&process.pid) {
611+
process.cpu_usage_percent = if num_cpus == 0.0 {
612+
*cpu_usages.get(&process.pid).unwrap()
613+
} else {
614+
*cpu_usages.get(&process.pid).unwrap() / num_cpus
615+
};
616+
}
617+
}
618+
}
619+
569620
Ok(process_vector)
570621
}
571622

0 commit comments

Comments
 (0)