mprober_lib/process/process_time_stat.rs
1use std::{io::ErrorKind, path::Path};
2
3use crate::{
4 process::ProcessStat,
5 scanner_rust::{generic_array::typenum::U96, Scanner, ScannerError},
6};
7
8#[derive(Default, Debug, Clone)]
9pub struct ProcessTimeStat {
10 pub utime: u32,
11 pub stime: u32,
12}
13
14impl ProcessTimeStat {
15 /// Compute CPU utilization in percentage between two `ProcessTimeStat` instances at different time. If it returns `1.0`, means `100%`.
16 ///
17 /// ```rust
18 /// use std::{thread::sleep, time::Duration};
19 ///
20 /// use mprober_lib::{cpu, process};
21 ///
22 /// let pre_average_cpu_stat = cpu::get_average_cpu_stat().unwrap();
23 /// let pre_process_time_stat = process::get_process_time_stat(1).unwrap();
24 ///
25 /// sleep(Duration::from_millis(100));
26 ///
27 /// let average_cpu_stat = cpu::get_average_cpu_stat().unwrap();
28 /// let process_time_stat = process::get_process_time_stat(1).unwrap();
29 ///
30 /// let total_cpu_time_f64 = {
31 /// let pre_average_cpu_time = pre_average_cpu_stat.compute_cpu_time();
32 /// let average_cpu_time = average_cpu_stat.compute_cpu_time();
33 ///
34 /// (average_cpu_time.get_total_time()
35 /// - pre_average_cpu_time.get_total_time()) as f64
36 /// };
37 ///
38 /// let cpu_percentage = pre_process_time_stat
39 /// .compute_cpu_utilization_in_percentage(
40 /// &process_time_stat,
41 /// total_cpu_time_f64,
42 /// );
43 ///
44 /// println!("{:.2}%", cpu_percentage * 100.0);
45 /// ```
46 #[inline]
47 pub fn compute_cpu_utilization_in_percentage(
48 &self,
49 process_time_stat_after_this: &ProcessTimeStat,
50 total_cpu_time: f64,
51 ) -> f64 {
52 let d_utime = process_time_stat_after_this.utime - self.utime;
53 let d_stime = process_time_stat_after_this.stime - self.stime;
54 let d_time_f64 = (d_utime + d_stime) as f64;
55
56 if total_cpu_time < 1.0 {
57 0.0
58 } else if d_time_f64 >= total_cpu_time {
59 1.0
60 } else {
61 d_time_f64 / total_cpu_time
62 }
63 }
64}
65
66impl From<ProcessStat> for ProcessTimeStat {
67 #[inline]
68 fn from(process_stat: ProcessStat) -> Self {
69 ProcessTimeStat {
70 utime: process_stat.utime, stime: process_stat.stime
71 }
72 }
73}
74
75/// Get the time stat of a specific process found by ID by reading the `/proc/PID/stat` file.
76///
77/// ```rust
78/// use mprober_lib::process;
79///
80/// let process_time_stat = process::get_process_time_stat(1).unwrap();
81///
82/// println!("{process_time_stat:#?}");
83/// ```
84pub fn get_process_time_stat(pid: u32) -> Result<ProcessTimeStat, ScannerError> {
85 let stat_path = Path::new("/proc").join(pid.to_string()).join("stat");
86
87 let mut sc: Scanner<_, U96> = Scanner::scan_path2(stat_path)?;
88
89 sc.drop_next()?.ok_or(ErrorKind::UnexpectedEof)?;
90
91 loop {
92 let comm = sc.next_raw()?.ok_or(ErrorKind::UnexpectedEof)?;
93
94 if comm.ends_with(b")") {
95 break;
96 }
97 }
98
99 for _ in 0..11 {
100 sc.drop_next()?.ok_or(ErrorKind::UnexpectedEof)?;
101 }
102
103 let utime = sc.next_u32()?.ok_or(ErrorKind::UnexpectedEof)?;
104 let stime = sc.next_u32()?.ok_or(ErrorKind::UnexpectedEof)?;
105
106 let time_stat = ProcessTimeStat {
107 utime,
108 stime,
109 };
110
111 Ok(time_stat)
112}