From 9666fcea827f3c8e1138e29c1eac401968002aab Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Wed, 11 Feb 2026 20:58:13 +0000 Subject: [PATCH 1/2] perf improvement in get_process_info for Linux --- proxy_agent/src/proxy.rs | 44 ++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/proxy_agent/src/proxy.rs b/proxy_agent/src/proxy.rs index dcc50b1a..a9cceea1 100644 --- a/proxy_agent/src/proxy.rs +++ b/proxy_agent/src/proxy.rs @@ -46,9 +46,6 @@ use crate::shared_state::proxy_server_wrapper::ProxyServerSharedState; use serde_derive::{Deserialize, Serialize}; use std::{ffi::OsString, net::IpAddr, path::PathBuf}; -#[cfg(not(windows))] -use sysinfo::{Pid, ProcessRefreshKind, RefreshKind, System, UpdateKind}; - #[derive(Serialize, Deserialize, Clone)] #[allow(non_snake_case)] pub struct Claims { @@ -97,26 +94,33 @@ async fn get_user( } } +/// Get process information (executable path and command line) for the given process ID. +/// Reads directly from the /proc filesystem on Linux for better performance. +/// Returns (executable path, command line). If the process information cannot be retrieved, returns (empty path, "undefined" command line). +/// Remarks: both /proc/{pid}/exe and /proc/{pid}/cmdline are universally supported across all Linux distributions since kernel 1.0 +/// Remarks: Donot use sysinfo::System::refresh_process_specifics(pid, refresh_kind) to get this information, +/// as it reads all files from /proc/{pid}/* and Create Process struct with all fields, +/// which is very inefficient when we only need the executable path and command line. #[cfg(not(windows))] fn get_process_info(process_id: u32) -> (PathBuf, String) { - let mut process_name = PathBuf::default(); - let mut process_cmd_line = UNDEFINED.to_string(); + // Get executable path from /proc/{pid}/exe symlink + let exe_path = format!("/proc/{}/exe", process_id); + let process_name = std::fs::read_link(&exe_path).unwrap_or_default(); - let pid = Pid::from_u32(process_id); - let sys = System::new_with_specifics( - RefreshKind::new().with_processes( - ProcessRefreshKind::new() - .with_cmd(UpdateKind::Always) - .with_exe(UpdateKind::Always), - ), - ); - if let Some(p) = sys.process(pid) { - process_name = match p.exe() { - Some(path) => path.to_path_buf(), - None => PathBuf::default(), - }; - process_cmd_line = p.cmd().join(" "); - } + // Get command line from /proc/{pid}/cmdline (null-separated arguments) + let cmdline_path = format!("/proc/{}/cmdline", process_id); + let process_cmd_line = match std::fs::read(&cmdline_path) { + Ok(bytes) => { + // cmdline is null-separated, convert to space-separated string + bytes + .split(|&b| b == 0) + .filter(|s| !s.is_empty()) + .map(|s| String::from_utf8_lossy(s).into_owned()) + .collect::>() + .join(" ") + } + Err(_) => UNDEFINED.to_string(), + }; (process_name, process_cmd_line) } From 416b431af0c88172b021be01375a44fa762ac74d Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Wed, 11 Feb 2026 21:15:10 +0000 Subject: [PATCH 2/2] fix --- proxy_agent/src/proxy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy_agent/src/proxy.rs b/proxy_agent/src/proxy.rs index a9cceea1..faea5a27 100644 --- a/proxy_agent/src/proxy.rs +++ b/proxy_agent/src/proxy.rs @@ -98,7 +98,7 @@ async fn get_user( /// Reads directly from the /proc filesystem on Linux for better performance. /// Returns (executable path, command line). If the process information cannot be retrieved, returns (empty path, "undefined" command line). /// Remarks: both /proc/{pid}/exe and /proc/{pid}/cmdline are universally supported across all Linux distributions since kernel 1.0 -/// Remarks: Donot use sysinfo::System::refresh_process_specifics(pid, refresh_kind) to get this information, +/// Remarks: Do not use sysinfo::System::refresh_process_specifics(pid, refresh_kind) to get this information, /// as it reads all files from /proc/{pid}/* and Create Process struct with all fields, /// which is very inefficient when we only need the executable path and command line. #[cfg(not(windows))]