1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
use crate::processor; use serde::{Deserialize, Serialize}; use std::fs::File; use std::io::Read; use std::str; use std::time; #[derive(Debug, Default, Copy, Clone)] struct ProcessStat { utime: u64, stime: u64, cutime: u64, cstime: u64, } impl ProcessStat { fn get_total_with_children(&self) -> u64 { self.utime + self.stime + self.cutime + self.cstime } fn get_total(&self) -> u64 { self.utime + self.stime } } #[derive(Debug, Serialize, Deserialize, Default)] pub struct Process { pub processor_usage_with_children: f32, pub processor_usage: f32, pub rss: String, pub pid: String, #[serde(skip)] last_stat: ProcessStat, #[serde(skip)] latest_stat: ProcessStat, #[serde(skip)] last_processor_stat: processor::ProcessStat, #[serde(skip)] latest_processor_stat: processor::ProcessStat, } impl Process { pub fn refresh(&mut self) -> Result<(), String> { self.last_processor_stat = self.latest_processor_stat; self.last_stat = self.latest_stat; self.latest_processor_stat = processor::get_total_processor_stat()?; self.latest_stat = get_process_stat(self.pid.to_owned())?; let total_diff = self.latest_processor_stat.get_total() - self.last_processor_stat.get_total(); let processors = processor::new()?; if total_diff == 0 { self.processor_usage = 0.0; self.processor_usage_with_children = 0.0; } else { self.processor_usage = processors.len() as f32 * (self.latest_stat.get_total() - self.last_stat.get_total()) as f32 / total_diff as f32; self.processor_usage_with_children = processors.len() as f32 * (self.latest_stat.get_total_with_children() - self.last_stat.get_total_with_children()) as f32 / total_diff as f32; } return Ok(()); } } pub fn new(pid: &'static str) -> Result<Process, String> { let mut process = Process::default(); let mut file = match File::open(String::from("/proc/") + pid + "/status") { Ok(o) => o, Err(err) => return Err(err.to_string()), }; let mut content = String::new(); match file.read_to_string(&mut content) { Ok(o) => o, Err(err) => return Err(err.to_string()), }; for i in content .lines() .map(|line| { let mut fields = line.split(":"); let (k, v) = ( fields.next().unwrap_or("").trim(), fields.next().unwrap_or("").trim(), ); (k, v) }) .filter(|(k, v)| match *k { "VmRSS" | "Pid" => true, _ => false, }) { match i.0 { "VmRSS" => process.rss = i.1.replace(" kB", ""), "Pid" => process.pid = i.1.to_string(), _ => {} } } process.latest_stat = get_process_stat(pid.to_owned())?; process.latest_processor_stat = processor::get_total_processor_stat()?; process.processor_usage = 0.0; process.processor_usage_with_children = 0.0; Ok(process) } fn get_process_stat(pid: String) -> Result<ProcessStat, String> { let mut content = String::new(); let mut file = match File::open(String::from("/proc/") + pid.as_str() + "/stat") { Ok(o) => o, Err(err) => return Err(err.to_string()), }; match file.read_to_string(&mut content) { Ok(o) => o, Err(err) => return Err(err.to_string()), }; let fields: Vec<&str> = content.split_ascii_whitespace().collect(); Ok(ProcessStat { utime: fields[13].parse::<u64>().unwrap(), stime: fields[14].parse::<u64>().unwrap(), cutime: fields[15].parse::<u64>().unwrap(), cstime: fields[16].parse::<u64>().unwrap(), }) } #[test] fn process_test() { loop { let mut process = new("1300").unwrap(); std::thread::sleep(std::time::Duration::from_secs(45)); process.refresh().unwrap(); assert_ne!(process.processor_usage, 0.0); assert_ne!(process.processor_usage_with_children, 0.0); println!("{:?}", process.processor_usage) } }