1use std::thread;
2use std::time::Duration;
3
4pub fn sample_cpu(pid: i32) -> Option<f64> {
9 let (pid_t1, sys_t1) = read_cpu_ticks(pid)?;
10 thread::sleep(Duration::from_millis(200));
11 let (pid_t2, sys_t2) = read_cpu_ticks(pid)?;
12
13 let d_pid = pid_t2.saturating_sub(pid_t1) as f64;
14 let d_sys = sys_t2.saturating_sub(sys_t1) as f64;
15
16 if d_sys == 0.0 {
17 return None;
18 }
19 let ncpus = cpu_count().max(1) as f64;
21 Some((d_pid / d_sys) * 100.0 * ncpus)
22}
23
24fn read_cpu_ticks(pid: i32) -> Option<(u64, u64)> {
25 let stat_raw = std::fs::read_to_string(format!("/proc/{}/stat", pid)).ok()?;
27 let after_comm = stat_raw.rfind(')').map(|i| &stat_raw[i + 2..])?;
30 let fields: Vec<&str> = after_comm.split_whitespace().collect();
31 let utime: u64 = fields.get(11)?.parse().ok()?;
33 let stime: u64 = fields.get(12)?.parse().ok()?;
34 let process_ticks = utime + stime;
35
36 let kstat_raw = std::fs::read_to_string("/proc/stat").ok()?;
38 let first_line = kstat_raw.lines().next()?;
39 let cpu_fields: Vec<u64> = first_line
40 .split_whitespace()
41 .skip(1)
42 .filter_map(|s| s.parse().ok())
43 .collect();
44 let total_ticks: u64 = cpu_fields.iter().sum();
45
46 Some((process_ticks, total_ticks))
47}
48
49fn cpu_count() -> usize {
50 std::fs::read_to_string("/proc/stat")
51 .map(|s| {
52 s.lines()
53 .filter(|l| l.starts_with("cpu") && l.len() > 3)
54 .count()
55 })
56 .unwrap_or(1)
57}