diff options
Diffstat (limited to 'src/app/data_harvester/processes/linux.rs')
-rw-r--r-- | src/app/data_harvester/processes/linux.rs | 110 |
1 files changed, 69 insertions, 41 deletions
diff --git a/src/app/data_harvester/processes/linux.rs b/src/app/data_harvester/processes/linux.rs index 4918230f..48adb8d7 100644 --- a/src/app/data_harvester/processes/linux.rs +++ b/src/app/data_harvester/processes/linux.rs @@ -1,10 +1,12 @@ //! Process data collection for Linux. -use std::fs::File; +mod process; +use process::*; + +use std::fs::{self, File}; use std::io::{BufRead, BufReader}; use hashbrown::{HashMap, HashSet}; -use procfs::process::{Process, Stat}; use sysinfo::{ProcessStatus, System}; use super::{ProcessHarvest, UserTable}; @@ -96,7 +98,7 @@ fn cpu_usage_calculation(prev_idle: &mut f64, prev_non_idle: &mut f64) -> error: /// Returns the usage and a new set of process times. /// -/// NB: cpu_fraction should be represented WITHOUT the x100 factor! +/// NB: `cpu_fraction` should be represented WITHOUT the x100 factor! fn get_linux_cpu_usage( stat: &Stat, cpu_usage: f64, cpu_fraction: f64, prev_proc_times: u64, use_current_cpu_total: bool, @@ -115,14 +117,21 @@ fn get_linux_cpu_usage( } fn read_proc( - prev_proc: &PrevProcDetails, process: &Process, cpu_usage: f64, cpu_fraction: f64, + prev_proc: &PrevProcDetails, process: Process, cpu_usage: f64, cpu_fraction: f64, use_current_cpu_total: bool, time_difference_in_secs: u64, total_memory: u64, user_table: &mut UserTable, ) -> error::Result<(ProcessHarvest, u64)> { - let stat = process.stat()?; + let Process { + pid: _, + uid, + stat, + io, + cmdline, + } = process; + let (command, name) = { let truncated_name = stat.comm.as_str(); - if let Ok(cmdline) = process.cmdline() { + if let Ok(cmdline) = cmdline { if cmdline.is_empty() { (format!("[{}]", truncated_name), truncated_name.to_string()) } else { @@ -168,7 +177,7 @@ fn read_proc( // This can fail if permission is denied! let (total_read_bytes, total_write_bytes, read_bytes_per_sec, write_bytes_per_sec) = - if let Ok(io) = process.io() { + if let Ok(io) = io { let total_read_bytes = io.read_bytes; let total_write_bytes = io.write_bytes; let prev_total_read_bytes = prev_proc.total_read_bytes; @@ -194,7 +203,14 @@ fn read_proc( (0, 0, 0, 0) }; - let uid = process.uid()?; + let user = uid + .and_then(|uid| { + user_table + .get_uid_to_username_mapping(uid) + .map(Into::into) + .ok() + }) + .unwrap_or_else(|| "N/A".into()); Ok(( ProcessHarvest { @@ -210,11 +226,8 @@ fn read_proc( total_read_bytes, total_write_bytes, process_state, - uid: Some(uid), - user: user_table - .get_uid_to_username_mapping(uid) - .map(Into::into) - .unwrap_or_else(|_| "N/A".into()), + uid, + user, }, new_process_times, )) @@ -230,11 +243,15 @@ pub(crate) struct ProcHarvestOptions { pub unnormalized_cpu: bool, } +fn is_str_numeric(s: &str) -> bool { + s.chars().all(|c| c.is_ascii_digit()) +} + pub(crate) fn get_process_data( sys: &System, prev_proc: PrevProc<'_>, pid_mapping: &mut HashMap<Pid, PrevProcDetails>, proc_harvest_options: ProcHarvestOptions, time_difference_in_secs: u64, total_memory: u64, user_table: &mut UserTable, -) -> crate::utils::error::Result<Vec<ProcessHarvest>> { +) -> error::Result<Vec<ProcessHarvest>> { let ProcHarvestOptions { use_current_cpu_total, unnormalized_cpu, @@ -263,36 +280,47 @@ pub(crate) fn get_process_data( let mut pids_to_clear: HashSet<Pid> = pid_mapping.keys().cloned().collect(); - let process_vector: Vec<ProcessHarvest> = std::fs::read_dir("/proc")? + let pids = fs::read_dir("/proc")? + .flatten() .filter_map(|dir| { - if let Ok(dir) = dir { - if let Ok(pid) = dir.file_name().to_string_lossy().trim().parse::<Pid>() { - let Ok(process) = Process::new(pid) else { - return None; - }; - let prev_proc_details = pid_mapping.entry(pid).or_default(); - - if let Ok((process_harvest, new_process_times)) = read_proc( - prev_proc_details, - &process, - cpu_usage, - cpu_fraction, - use_current_cpu_total, - time_difference_in_secs, - total_memory, - user_table, - ) { - prev_proc_details.cpu_time = new_process_times; - prev_proc_details.total_read_bytes = process_harvest.total_read_bytes; - prev_proc_details.total_write_bytes = process_harvest.total_write_bytes; - - pids_to_clear.remove(&pid); - return Some(process_harvest); - } + if is_str_numeric(dir.file_name().to_string_lossy().trim()) { + Some(dir.path()) + } else { + None + } + }) + .collect::<Vec<_>>(); + + use rayon::prelude::*; + let process_vector: Vec<ProcessHarvest> = pids + .into_par_iter() + .filter_map(|pid_path| { + if let Ok(process) = Process::from_path(pid_path) { + let pid = process.pid; + let prev_proc_details = pid_mapping.entry(pid).or_default(); + + if let Ok((process_harvest, new_process_times)) = read_proc( + prev_proc_details, + process, + cpu_usage, + cpu_fraction, + use_current_cpu_total, + time_difference_in_secs, + total_memory, + user_table, + ) { + prev_proc_details.cpu_time = new_process_times; + prev_proc_details.total_read_bytes = process_harvest.total_read_bytes; + prev_proc_details.total_write_bytes = process_harvest.total_write_bytes; + + pids_to_clear.remove(&pid); + Some(process_harvest) + } else { + None } + } else { + None } - - None }) .collect(); |