rustps/
lib.rs

1use std::fmt::Debug;
2use std::fs;
3use std::io;
4use std::fs::File;
5use std::io::{BufRead, BufReader, Error};
6#[derive(Debug)]
7///进程
8pub struct ProcessStat{
9    ///pid
10    pid: Option<i32>,
11    ///进程占用的真实内存大小
12    rss: Option<String>,
13    ///调用命令的完整信息
14    cmd: Option<String>,
15    ///进程状态
16    state: Option<String>,
17    ///父进程PID
18    ppid: Option<String>,
19    ///进程及其子进程被调度进内核态的时间,以jiffy为单位 1jiffy=1/100s
20    cstime: Option<String>,
21    ///进程及其子进程被调度进用户态的时间
22    cutime: Option<String>,
23    ///虚拟内存大小
24    vsize: Option<String>,
25    ///cpu利用率
26    cpu_use: Option<f64>,
27    ///进程进入用户态的时间(单位jiffy)
28    utime: Option<String>,
29    ///进程进入内核态的时间
30    stime: Option<String>,
31    ///内存占用峰值
32    vmpeak: Option<String>,
33    ///实际用户
34    ruid: Option<String>,
35    ///实际组
36    rgid: Option<String>,
37}
38
39
40impl Default for ProcessStat{
41    fn default() ->ProcessStat  {
42	ProcessStat { pid: None, rss: None, cmd: None, state: None, ppid: None, cstime: None, vsize: None , cpu_use: None, cutime: None, stime: None, utime: None, vmpeak: None, ruid: None,rgid: None}
43    }
44}
45impl ProcessStat{
46    ///创建新的进程信息表
47    pub fn new() -> ProcessStat {
48	ProcessStat::default()
49    }
50    ///根据PID获取表
51pub fn new_from_pid(pid: i32, cpu_frequency: f64) -> Result<ProcessStat, io::Error> {
52    // 从/proc/pid/status获取进程信息
53    // 通过定位/proc/{pid}/status中的行数,并通过trim_start_matches删除前缀,trim删除空格等
54    let status_str = fs::read_to_string(format!("/proc/{}/status", pid))?;
55    let stat_str = fs::read_to_string(format!("/proc/{}/stat", pid))?;
56    // 从/proc/pid/cmdline获取
57    let comm_str = fs::read_to_string(format!("/proc/{}/cmdline", pid))?;
58
59    let utime = stat_str.split_whitespace().nth(14).map(|line| line.parse::<f64>().unwrap_or(0.0));
60    let stime = stat_str.split_whitespace().nth(15).map(|line| line.parse::<f64>().unwrap_or(0.0));
61    let u_time = utime.unwrap_or(0.0);
62    let s_time = stime.unwrap_or(0.0);
63    let cpu_usage = 100.0 * (s_time / cpu_frequency);  // 计算 CPU 利用率
64
65    let rss = if let Some(line) = status_str.lines().nth(22) {
66        if line.contains("VmRSS") {
67            if line.trim_start_matches("VmRSS:").trim() == "sigign" {
68                None
69            } else {
70                Some(line.trim_start_matches("VmRSS:").trim().to_string())
71            }
72        } else {
73            None
74        }
75    } else {
76        None
77    };
78
79    let vmpeak = if let Some(line) = status_str.lines().nth(17) {
80        if line.contains("VmPeak") {
81            if line.trim_start_matches("VmPeak:").trim() == "fffffffff" {
82                None
83            } else {
84                Some(line.trim_start_matches("VmPeak:").trim().to_string())
85            }
86        } else {
87            None
88        }
89    } else {
90        None
91    };
92    let status_str_lines = status_str.lines();
93    Ok(ProcessStat {
94        pid: Some(pid),
95        state: status_str.lines().nth(2).map(|line| line.trim_start_matches("State:").trim().to_string()),
96        cmd: Some(comm_str.replace("\0","")),
97        rss,
98        ppid: status_str.lines().nth(6).map(|line| line.trim_start_matches("PPid:").trim().to_string()),
99        cstime: stat_str.split_whitespace().nth(17).map(|line| line.to_string()),
100        vsize: status_str.lines().nth(18).map(|line| line.trim_start_matches("VmSize:").trim().to_string()),
101        cpu_use: Some(cpu_usage),
102        utime: stat_str.split_whitespace().nth(13).map(|line| line.to_string()),
103        stime: stat_str.split_whitespace().nth(14).map(|line| line.to_string()),
104        cutime: stat_str.split_whitespace().nth(16).map(|line| line.to_string()),
105        vmpeak,
106	ruid: status_str.lines().nth(8).map(|line| line.trim_start_matches("Uid:").split_whitespace().next().unwrap().trim().to_string()),
107	rgid: status_str.lines().nth(9).map(|line| line.trim_start_matches("Gid:").split_whitespace().next().unwrap().trim().to_string())
108    })
109}
110}
111
112///获取处理器频率
113pub fn get_cpu_frequency() -> io::Result<f64> {
114    let cpu_frequency = fs::read_to_string("/proc/cpuinfo")?
115        .lines()
116        .find(|line| line.contains("cpu MHz"))
117        .and_then(|line| line.split(':').last())
118        .and_then(|freq_str| freq_str.trim().parse::<f64>().ok())
119        .map(|freq| freq * 1e6 / 100.0); // Converting MHz to Hz, and then to percentage
120    cpu_frequency.ok_or(io::Error::new(io::ErrorKind::Other, "Failed to read CPU MHz"))
121}
122
123///获取进程信息
124pub fn load_process_stats() -> Result<Vec<ProcessStat>, io::Error> {
125    let mut process_stats: Vec<ProcessStat> = Vec::new();
126    let entries = fs::read_dir("/proc")?;  // 读取/proc目录下的文件
127    for entry in entries {
128        if let Ok(entry) = entry {
129            if let Ok(file_name) = entry.file_name().into_string() {
130                if let Ok(pid) = file_name.parse::<i32>() {  // 尝试将文件名解析为PID
131                    if let Ok(process_stat) = ProcessStat::new_from_pid(pid,get_cpu_frequency()?) {
132                        process_stats.push(process_stat);
133                    }
134                }
135            }
136        }
137    }
138    Ok(process_stats)
139}
140/// 格式化输出进程信息表
141pub fn format_process_stats(process_stats: &[ProcessStat]) {
142    println!("{:<8} {:<8} {:<8} {:<8} {:<8} {:<8} {:<8} {:<8}",
143             "RUID", "PID", "PPID", "RSS", "VMPEAK", "STATE", "CPU%", "CMD");
144    for process_stat in process_stats {
145        let pid = process_stat.pid.unwrap_or(-1); // 默认值为-1,如果没有pid,打印-1
146        let ppid = process_stat.ppid.as_ref().map_or("None", |s| s);
147        let rss = process_stat.rss.as_ref().map_or("None", |s| s);
148        let vmpeak = process_stat.vmpeak.as_ref().map_or("None", |s| s);
149        let state = process_stat.state.as_ref().map_or("None", |s| s);
150        let cpu_use = process_stat.cpu_use.unwrap_or(-1.0); // 默认值为-1.0,如果没有cpu_use,打印-1.0
151        let cmd = process_stat.cmd.as_ref().map_or("None", |s| s);
152        let ruid = process_stat.ruid.as_ref().map_or("unknow", |s| s);
153        println!("{:<8} {:<8} {:<8} {:<8} {:<8} {:<8} {:<8} {:<8}",
154                 ruid,pid, ppid, rss, vmpeak, state, cpu_use, cmd);
155    }
156}
157///打印一个进程信息
158pub fn format_one_process(pid: i32) -> Result<(), io::Error> {
159    if let Ok(process_stat) = ProcessStat::new_from_pid(pid, get_cpu_frequency()?) {
160        let pid = process_stat.pid.unwrap_or(-1); // 默认值为-1,如果没有pid,打印-1
161        let ppid = process_stat.ppid.as_deref().unwrap_or("None");
162        let rss = process_stat.rss.as_deref().unwrap_or("None");
163        let vmpeak = process_stat.vmpeak.as_deref().unwrap_or("None");
164        let state = process_stat.state.as_deref().unwrap_or("None");
165        let cpu_use = process_stat.cpu_use.unwrap_or(-1.0); // 默认值为-1.0,如果没有cpu_use,打印-1.0
166        let cmd = process_stat.cmd.as_deref().unwrap_or("None");
167        println!("{:<8} {:<8} {:<8} {:<8} {:<8} {:<8} {:<8}",
168                 pid, ppid, rss, vmpeak, state, cpu_use, cmd);
169        Ok(())
170    } else {
171        Err(io::Error::new(io::ErrorKind::Other, "Failed to read process stats"))
172    }
173}
174