From 01e0c7339348a9100ac3ab13b7511af159fd042d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Dec 2019 18:11:15 +0100 Subject: [PATCH 001/171] Add specific path to get raspberry pi CPU temperature --- src/linux/component.rs | 103 ++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/src/linux/component.rs b/src/linux/component.rs index 456891062..f23b738bb 100644 --- a/src/linux/component.rs +++ b/src/linux/component.rs @@ -8,7 +8,7 @@ use ComponentExt; use std::collections::HashMap; use std::ffi::OsStr; -use std::fs::{read_dir, File}; +use std::fs::{metadata, read_dir, File}; use std::io::Read; use std::path::{Path, PathBuf}; @@ -36,8 +36,16 @@ fn get_file_line(file: &Path, capacity: usize) -> Option { } } +fn is_file>(path: T) -> bool { + metadata(path) + .ok() + .map(|m| m.is_file()) + .unwrap_or_else(|| false) +} + fn append_files(components: &mut Vec, folder: &Path) { - let mut matchings = HashMap::new(); + let mut matchings: HashMap> = HashMap::new(); + if let Ok(dir) = read_dir(folder) { for entry in dir { if let Ok(entry) = entry { @@ -54,11 +62,17 @@ fn append_files(components: &mut Vec, folder: &Path) { } if let Some(entry) = entry.file_name() { if let Some(entry) = entry.to_str() { - if let Ok(id) = entry[4..5].parse::() { + let mut parts = entry.split('_'); + if let Some(Some(id)) = parts.next().map(|s| s[4..].parse::().ok()) { matchings .entry(id) - .or_insert_with(|| Vec::with_capacity(1)) - .push(entry[6..].to_owned()); + .or_insert_with(|| Vec::with_capacity(5)) + .push( + parts + .next() + .map(|s| format!("_{}", s)) + .unwrap_or_else(|| String::new()), + ); } } } @@ -69,45 +83,41 @@ fn append_files(components: &mut Vec, folder: &Path) { let mut found_label = None; for (pos, v) in val.iter().enumerate() { match v.as_str() { - "input" => { + // raspberry has empty string for temperature input + "_input" | "" => { found_input = Some(pos); } - "label" => { + "_label" => { found_label = Some(pos); } _ => {} } - if found_label.is_some() && found_input.is_some() { - let mut p_label = folder.to_path_buf(); - let mut p_input = folder.to_path_buf(); - let mut p_crit = folder.to_path_buf(); - let mut p_max = folder.to_path_buf(); - - p_label.push(&format!("temp{}_label", key)); - p_input.push(&format!("temp{}_input", key)); - p_max.push(&format!("temp{}_max", key)); - p_crit.push(&format!("temp{}_crit", key)); - if let Some(content) = get_file_line(p_label.as_path(), 10) { - let label = content.replace("\n", ""); - let max = if let Some(max) = get_file_line(p_max.as_path(), 10) { - Some( - max.replace("\n", "").parse::().unwrap_or(100_000f32) - / 1000f32, - ) - } else { - None - }; - let crit = if let Some(crit) = get_file_line(p_crit.as_path(), 10) { - Some( - crit.replace("\n", "").parse::().unwrap_or(100_000f32) - / 1000f32, - ) - } else { - None - }; - components.push(Component::new(label, p_input.as_path(), max, crit)); - break; - } + } + if found_label.is_some() && found_input.is_some() { + let mut p_label = folder.to_path_buf(); + let mut p_input = folder.to_path_buf(); + let mut p_crit = folder.to_path_buf(); + let mut p_max = folder.to_path_buf(); + + p_label.push(&format!("temp{}_label", key)); + p_input.push(&format!("temp{}{}", key, val[found_input.unwrap()])); + p_max.push(&format!("temp{}_max", key)); + p_crit.push(&format!("temp{}_crit", key)); + if is_file(&p_input) { + let label = get_file_line(p_label.as_path(), 10) + .unwrap_or_else(|| format!("Component {}", key)) // needed for raspberry pi + .replace("\n", ""); + let max = if let Some(max) = get_file_line(p_max.as_path(), 10) { + Some(max.replace("\n", "").parse::().unwrap_or(100_000f32) / 1000f32) + } else { + None + }; + let crit = if let Some(crit) = get_file_line(p_crit.as_path(), 10) { + Some(crit.replace("\n", "").parse::().unwrap_or(100_000f32) / 1000f32) + } else { + None + }; + components.push(Component::new(label, p_input.as_path(), max, crit)); } } } @@ -167,7 +177,8 @@ impl ComponentExt for Component { } pub fn get_components() -> Vec { - let mut ret = Vec::new(); + let mut components = Vec::new(); + if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) { for entry in dir { if let Ok(entry) = entry { @@ -182,10 +193,18 @@ pub fn get_components() -> Vec { { continue; } - append_files(&mut ret, &entry); + append_files(&mut components, &entry); } } + } else if is_file("/sys/class/thermal/thermal_zone0/temp") { + // Specfic to raspberry pi. + components.push(Component::new( + "CPU".to_owned(), + Path::new("/sys/class/thermal/thermal_zone0/temp"), + None, + None, + )); } - ret.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase())); - ret + components.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase())); + components } From acd082b141741283f6f84b80b587f57c1bfdc77d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Dec 2019 23:05:26 +0100 Subject: [PATCH 002/171] Add more specific refresh methods --- src/common.rs | 16 ++++++++++++---- src/traits.rs | 32 +++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/common.rs b/src/common.rs index 5224699f1..d7891a27a 100644 --- a/src/common.rs +++ b/src/common.rs @@ -112,11 +112,13 @@ assert_eq!(r.", stringify!($name), "(), false); /// ``` #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct RefreshKind { - system: bool, network: bool, processes: bool, disk_list: bool, disks: bool, + memory: bool, + cpu: bool, + temperatures: bool, } impl RefreshKind { @@ -137,11 +139,13 @@ impl RefreshKind { /// ``` pub fn new() -> RefreshKind { RefreshKind { - system: false, network: false, processes: false, disks: false, disk_list: false, + memory: false, + cpu: false, + temperatures: false, } } @@ -162,17 +166,21 @@ impl RefreshKind { /// ``` pub fn everything() -> RefreshKind { RefreshKind { - system: true, network: true, processes: true, disks: true, disk_list: true, + memory: true, + cpu: true, + temperatures: true, } } - impl_get_set!(system, with_system, without_system); impl_get_set!(network, with_network, without_network); impl_get_set!(processes, with_processes, without_processes); impl_get_set!(disks, with_disks, without_disks); impl_get_set!(disk_list, with_disk_list, without_disk_list); + impl_get_set!(memory, with_memory, without_memory); + impl_get_set!(cpu, with_cpu, without_cpu); + impl_get_set!(temperatures, with_temperatures, without_temperatures); } diff --git a/src/traits.rs b/src/traits.rs index 6656b8c59..e2773ae09 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -156,8 +156,14 @@ pub trait SystemExt: Sized { /// s.refresh_specifics(RefreshKind::new().with_network().with_processes()); /// ``` fn refresh_specifics(&mut self, refreshes: RefreshKind) { - if refreshes.system() { - self.refresh_system(); + if refreshes.memory() { + self.refresh_memory(); + } + if refreshes.cpu() { + self.refresh_cpu(); + } + if refreshes.temperatures() { + self.refresh_temperatures(); } if refreshes.network() { self.refresh_network(); @@ -174,7 +180,27 @@ pub trait SystemExt: Sized { } /// Refresh system information (such as memory, swap, CPU usage and components' temperature). - fn refresh_system(&mut self); + /// + /// If you want some more specific refresh, you might be interested into looking at + /// [`refresh_memory`], [`refresh_cpu`] and [`refresh_temperatures`]. + /// + /// [`refresh_memory`]: SystemExt::refresh_memory + /// [`refresh_cpu`]: SystemExt::refresh_memory + /// [`refresh_temperatures`]: SystemExt::refresh_temperatures + fn refresh_system(&mut self) { + self.refresh_memory(); + self.refresh_cpu(); + self.refresh_temperatures(); + } + + /// Refresh RAM and SWAP usage. + fn refresh_memory(&mut self); + + /// Refresh CPU usage. + fn refresh_cpu(&mut self); + + /// Refresh components' temperature. + fn refresh_temperatures(&mut self); /// Get all processes and update their information. fn refresh_processes(&mut self); From 45d7d54f2d5e992270b7a1d074c15b65c0a05132 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Dec 2019 23:14:25 +0100 Subject: [PATCH 003/171] Implement new refresh functions for linux --- src/linux/system.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index b8c6934b3..8213fda86 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -145,11 +145,8 @@ impl SystemExt for System { s } - fn refresh_system(&mut self) { + fn refresh_memory(&mut self) { self.uptime = get_uptime(); - for component in &mut self.temperatures { - component.update(); - } if let Ok(data) = get_all_data("/proc/meminfo") { for line in data.split('\n') { let field = match line.split(':').next() { @@ -166,9 +163,19 @@ impl SystemExt for System { } } } + } + + fn refresh_cpu(&mut self) { + self.uptime = get_uptime(); self.refresh_processors(None); } + fn refresh_temperatures(&mut self) { + for component in &mut self.temperatures { + component.update(); + } + } + fn refresh_processes(&mut self) { self.uptime = get_uptime(); if refresh_procs( From 28458b3d8b37f9b93524fdb544b8d466ae0016a4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Dec 2019 23:17:23 +0100 Subject: [PATCH 004/171] Add new refresh functions for the C interface --- src/c_interface.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/c_interface.rs b/src/c_interface.rs index 2592f3b4f..d144c35d7 100644 --- a/src/c_interface.rs +++ b/src/c_interface.rs @@ -46,6 +46,42 @@ pub extern "C" fn sysinfo_refresh_system(system: CSystem) { Box::into_raw(system); } +/// Equivalent of `System::refresh_memory()`. +#[no_mangle] +pub extern "C" fn sysinfo_refresh_memory(system: CSystem) { + assert!(!system.is_null()); + let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; + { + let system: &mut System = system.borrow_mut(); + system.refresh_memory(); + } + Box::into_raw(system); +} + +/// Equivalent of `System::refresh_cpu()`. +#[no_mangle] +pub extern "C" fn sysinfo_refresh_cpu(system: CSystem) { + assert!(!system.is_null()); + let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; + { + let system: &mut System = system.borrow_mut(); + system.refresh_cpu(); + } + Box::into_raw(system); +} + +/// Equivalent of `System::refresh_cpu()`. +#[no_mangle] +pub extern "C" fn sysinfo_refresh_temperatures(system: CSystem) { + assert!(!system.is_null()); + let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; + { + let system: &mut System = system.borrow_mut(); + system.refresh_temperatures(); + } + Box::into_raw(system); +} + /// Equivalent of `System::refresh_all()`. #[no_mangle] pub extern "C" fn sysinfo_refresh_all(system: CSystem) { From a1c2466f9728fc0802f1f2a1b4d5974685a909fb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Dec 2019 23:29:01 +0100 Subject: [PATCH 005/171] Add new refresh methods for mac --- src/mac/system.rs | 54 +++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/src/mac/system.rs b/src/mac/system.rs index f697e989b..80071bce0 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -637,6 +637,25 @@ fn get_arg_max() -> usize { } } +unsafe fn get_sys_value( + high: u32, + low: u32, + mut len: usize, + value: *mut c_void, + mib: &mut [i32; 2], +) -> bool { + mib[0] = high as i32; + mib[1] = low as i32; + libc::sysctl( + mib.as_mut_ptr(), + 2, + value, + &mut len as *mut usize, + ::std::ptr::null_mut(), + 0, + ) == 0 +} + impl System { fn clear_procs(&mut self) { let mut to_delete = Vec::new(); @@ -673,28 +692,10 @@ impl SystemExt for System { s } - fn refresh_system(&mut self) { - self.uptime = get_uptime(); - unsafe fn get_sys_value( - high: u32, - low: u32, - mut len: usize, - value: *mut c_void, - mib: &mut [i32; 2], - ) -> bool { - mib[0] = high as i32; - mib[1] = low as i32; - libc::sysctl( - mib.as_mut_ptr(), - 2, - value, - &mut len as *mut usize, - ::std::ptr::null_mut(), - 0, - ) == 0 - } - + fn refresh_memory(&mut self) { let mut mib = [0, 0]; + + self.uptime = get_uptime(); unsafe { // get system values // get swap info @@ -746,7 +747,11 @@ impl SystemExt for System { - u64::from(stat.purgeable_count)) * self.page_size_kb; } + } + } + fn refresh_temperatures(&mut self) { + unsafe { if let Some(con) = self.connection { if self.temperatures.is_empty() { // getting CPU critical temperature @@ -809,7 +814,14 @@ impl SystemExt for System { } } } + } + } + fn refresh_cpu(&mut self) { + self.uptime = get_uptime(); + + let mut mib = [0, 0]; + unsafe { // get processor values let mut num_cpu_u = 0u32; let mut cpu_info: *mut i32 = ::std::ptr::null_mut(); From 494ea162c6443c7d2c873e15eef09081736f4ff5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Dec 2019 23:31:57 +0100 Subject: [PATCH 006/171] Add new refresh methods for windows --- src/windows/system.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/windows/system.rs b/src/windows/system.rs index ab29d21f6..83d3d2776 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -248,16 +248,7 @@ impl SystemExt for System { s } - fn refresh_system(&mut self) { - unsafe { - let mut mem_info: MEMORYSTATUSEX = zeroed(); - mem_info.dwLength = size_of::() as u32; - GlobalMemoryStatusEx(&mut mem_info); - self.mem_total = auto_cast!(mem_info.ullTotalPhys, u64); - self.mem_free = auto_cast!(mem_info.ullAvailPhys, u64); - //self.swap_total = auto_cast!(mem_info.ullTotalPageFile - mem_info.ullTotalPhys, u64); - //self.swap_free = auto_cast!(mem_info.ullAvailPageFile, u64); - } + fn refresh_cpu(&mut self) { self.uptime = get_uptime(); if let Some(ref mut query) = self.query { for p in self.processors.iter_mut() { @@ -272,6 +263,23 @@ impl SystemExt for System { } } + fn refresh_memory(&mut self) { + self.uptime = get_uptime(); + unsafe { + let mut mem_info: MEMORYSTATUSEX = zeroed(); + mem_info.dwLength = size_of::() as u32; + GlobalMemoryStatusEx(&mut mem_info); + self.mem_total = auto_cast!(mem_info.ullTotalPhys, u64); + self.mem_free = auto_cast!(mem_info.ullAvailPhys, u64); + //self.swap_total = auto_cast!(mem_info.ullTotalPageFile - mem_info.ullTotalPhys, u64); + //self.swap_free = auto_cast!(mem_info.ullAvailPageFile, u64); + } + } + + fn refresh_temperatures(&mut self) { + // does nothing for the moment... + } + fn refresh_network(&mut self) { network::refresh(&mut self.network, &self.query); } From baaf33399d8c70fb53759a8b786d6339fbcef198 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Dec 2019 23:32:51 +0100 Subject: [PATCH 007/171] Add new refresh methods for unknown --- src/unknown/system.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/unknown/system.rs b/src/unknown/system.rs index bf2e90b42..14ed598e0 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -29,7 +29,11 @@ impl SystemExt for System { } } - fn refresh_system(&mut self) {} + fn refresh_memory(&mut self) {} + + fn refresh_cpu(&mut self) {} + + fn refresh_temperatures(&mut self) {} fn refresh_processes(&mut self) {} From dd520a8df3d2c94104ec87758f5bd92aa40f6a5b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Dec 2019 23:38:25 +0100 Subject: [PATCH 008/171] fix RefreshKind examples --- src/common.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/common.rs b/src/common.rs index d7891a27a..a80b5963c 100644 --- a/src/common.rs +++ b/src/common.rs @@ -131,11 +131,13 @@ impl RefreshKind { /// /// let r = RefreshKind::new(); /// - /// assert_eq!(r.system(), false); /// assert_eq!(r.network(), false); /// assert_eq!(r.processes(), false); /// assert_eq!(r.disk_list(), false); /// assert_eq!(r.disks(), false); + /// assert_eq!(r.memory(), false); + /// assert_eq!(r.cpu(), false); + /// assert_eq!(r.temperatures(), false); /// ``` pub fn new() -> RefreshKind { RefreshKind { @@ -158,11 +160,13 @@ impl RefreshKind { /// /// let r = RefreshKind::everything(); /// - /// assert_eq!(r.system(), true); /// assert_eq!(r.network(), true); /// assert_eq!(r.processes(), true); /// assert_eq!(r.disk_list(), true); /// assert_eq!(r.disks(), true); + /// assert_eq!(r.memory(), true); + /// assert_eq!(r.cpu(), true); + /// assert_eq!(r.temperatures(), true); /// ``` pub fn everything() -> RefreshKind { RefreshKind { From ac315a038bf6953173f83a8a96d67d5dba569bc5 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 7 Dec 2019 01:38:07 +0100 Subject: [PATCH 009/171] Greatly improve windows performance --- Cargo.toml | 1 + src/sysinfo.rs | 1 + src/windows/process.rs | 195 +++++++++++++++++++++++++++------------ src/windows/processor.rs | 5 +- src/windows/system.rs | 192 ++++++++++++++++++++++---------------- 5 files changed, 257 insertions(+), 137 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4081c2a28..03d747e70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ doc-comment = "0.3" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "tlhelp32", "winbase", "winerror", "winioctl", "winnt"] } +ntapi = "0.3" [target.'cfg(not(target_os = "unknown"))'.dependencies] libc = "0.2" diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 8960fc2d7..4ea6b634b 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -68,6 +68,7 @@ cfg_if! { mod windows; use windows as sys; extern crate winapi; + extern crate ntapi; } else if #[cfg(unix)] { mod linux; use linux as sys; diff --git a/src/windows/process.rs b/src/windows/process.rs index 80cc3d1e9..37a44917d 100644 --- a/src/windows/process.rs +++ b/src/windows/process.rs @@ -23,9 +23,6 @@ use winapi::um::psapi::{ LIST_MODULES_ALL, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX, }; use winapi::um::sysinfoapi::GetSystemTimeAsFileTime; -use winapi::um::tlhelp32::{ - CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS, -}; use winapi::um::winnt::{ HANDLE, /*, PWSTR*/ PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, PROCESS_VM_READ, ULARGE_INTEGER, /*THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION, THREAD_SUSPEND_RESUME,*/ @@ -96,8 +93,8 @@ pub struct Process { environ: Vec, cwd: PathBuf, root: PathBuf, - memory: u64, - virtual_memory: u64, + pub(crate) memory: u64, + pub(crate) virtual_memory: u64, parent: Option, status: ProcessStatus, handle: HandleWrapper, @@ -106,6 +103,120 @@ pub struct Process { old_user_cpu: u64, start_time: u64, cpu_usage: f32, + pub(crate) updated: bool, +} + +unsafe fn get_process_name(process_handler: HANDLE, h_mod: *mut c_void) -> String { + let mut process_name = [0u16; MAX_PATH + 1]; + + GetModuleBaseNameW( + process_handler, + h_mod as _, + process_name.as_mut_ptr(), + MAX_PATH as DWORD + 1, + ); + let mut pos = 0; + for x in process_name.iter() { + if *x == 0 { + break; + } + pos += 1; + } + String::from_utf16_lossy(&process_name[..pos]) +} + +unsafe fn get_h_mod(process_handler: HANDLE, h_mod: &mut *mut c_void) -> bool { + let mut cb_needed = 0; + EnumProcessModulesEx( + process_handler, + h_mod as *mut *mut c_void as _, + ::std::mem::size_of::() as DWORD, + &mut cb_needed, + LIST_MODULES_ALL, + ) != 0 +} + +unsafe fn get_exe(process_handler: HANDLE, h_mod: *mut c_void) -> PathBuf { + let mut exe_buf = [0u16; MAX_PATH + 1]; + GetModuleFileNameExW( + process_handler, + h_mod as _, + exe_buf.as_mut_ptr(), + MAX_PATH as DWORD + 1, + ); + + let mut pos = 0; + for x in exe_buf.iter() { + if *x == 0 { + break; + } + pos += 1; + } + + PathBuf::from(String::from_utf16_lossy(&exe_buf[..pos])) +} + +impl Process { + pub(crate) fn new_full( + pid: Pid, + parent: Option, + memory: u64, + virtual_memory: u64, + name: String, + ) -> Process { + if let Some(process_handler) = get_process_handler(pid) { + unsafe { + let mut h_mod = ::std::ptr::null_mut(); + get_h_mod(process_handler, &mut h_mod); + let environ = get_proc_env(process_handler, pid as u32, &name); + + let exe = get_exe(process_handler, h_mod); + let mut root = exe.clone(); + root.pop(); + Process { + handle: HandleWrapper(process_handler), + name, + pid, + parent, + cmd: get_cmd_line(pid), + environ, + exe, + cwd: PathBuf::new(), + root, + status: ProcessStatus::Run, + memory, + virtual_memory, + cpu_usage: 0., + old_cpu: 0, + old_sys_cpu: 0, + old_user_cpu: 0, + start_time: get_start_time(process_handler), + updated: true, + } + } + } else { + Process { + handle: HandleWrapper(::std::ptr::null_mut()), + name, + pid, + parent, + cmd: get_cmd_line(pid), + environ: Vec::new(), + exe: get_executable_path(pid), + cwd: PathBuf::new(), + root: PathBuf::new(), + status: ProcessStatus::Run, + memory, + virtual_memory, + cpu_usage: 0., + old_cpu: 0, + old_sys_cpu: 0, + old_user_cpu: 0, + start_time: 0, + updated: true, + } + } + } } // TODO: it's possible to get environment variables like it's done in @@ -117,64 +228,28 @@ impl ProcessExt for Process { fn new(pid: Pid, parent: Option, _: u64) -> Process { if let Some(process_handler) = get_process_handler(pid) { let mut h_mod = ::std::ptr::null_mut(); - let mut process_name = [0u16; MAX_PATH + 1]; - let mut cb_needed = 0; unsafe { - if EnumProcessModulesEx( - process_handler, - &mut h_mod, - ::std::mem::size_of::() as DWORD, - &mut cb_needed, - LIST_MODULES_ALL, - ) != 0 - { - GetModuleBaseNameW( - process_handler, - h_mod, - process_name.as_mut_ptr(), - MAX_PATH as DWORD + 1, - ); - } - let mut pos = 0; - for x in process_name.iter() { - if *x == 0 { - break; - } - pos += 1; - } - let name = String::from_utf16_lossy(&process_name[..pos]); + let name = if get_h_mod(process_handler, &mut h_mod) { + get_process_name(process_handler, h_mod) + } else { + String::new() + }; let environ = get_proc_env(process_handler, pid as u32, &name); - let mut exe_buf = [0u16; MAX_PATH + 1]; - GetModuleFileNameExW( - process_handler, - h_mod, - exe_buf.as_mut_ptr(), - MAX_PATH as DWORD + 1, - ); - - pos = 0; - for x in exe_buf.iter() { - if *x == 0 { - break; - } - pos += 1; - } - - let exe = PathBuf::from(String::from_utf16_lossy(&exe_buf[..pos])); + let exe = get_exe(process_handler, h_mod); let mut root = exe.clone(); root.pop(); Process { handle: HandleWrapper(process_handler), - name: name, - pid: pid, - parent: parent, + name, + pid, + parent, cmd: get_cmd_line(pid), - environ: environ, - exe: exe, + environ, + exe, cwd: PathBuf::new(), - root: root, + root, status: ProcessStatus::Run, memory: 0, virtual_memory: 0, @@ -183,14 +258,15 @@ impl ProcessExt for Process { old_sys_cpu: 0, old_user_cpu: 0, start_time: get_start_time(process_handler), + updated: true, } } } else { Process { handle: HandleWrapper(::std::ptr::null_mut()), name: String::new(), - pid: pid, - parent: parent, + pid, + parent, cmd: get_cmd_line(pid), environ: Vec::new(), exe: get_executable_path(pid), @@ -204,6 +280,7 @@ impl ProcessExt for Process { old_sys_cpu: 0, old_user_cpu: 0, start_time: 0, + updated: true, } } } @@ -319,7 +396,11 @@ unsafe fn get_start_time(handle: HANDLE) -> u64 { tmp / 10_000_000 - 11_644_473_600 } -pub unsafe fn get_parent_process_id(pid: Pid) -> Option { +/*pub unsafe fn get_parent_process_id(pid: Pid) -> Option { + use winapi::um::tlhelp32::{ + CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS, + }; + let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); let mut entry: PROCESSENTRY32 = zeroed(); entry.dwSize = size_of::() as u32; @@ -335,7 +416,7 @@ pub unsafe fn get_parent_process_id(pid: Pid) -> Option { } CloseHandle(snapshot); None -} +}*/ /*fn run_wmi(args: &[&str]) -> Option { use std::process::Command; diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 156138720..6e446d623 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -16,8 +16,9 @@ use winapi::shared::minwindef::{FALSE, ULONG}; use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::handleapi::CloseHandle; use winapi::um::pdh::{ - PdhAddCounterW, PdhRemoveCounter, PdhCollectQueryData, PdhCollectQueryDataEx, PdhGetFormattedCounterValue, - PdhOpenQueryA, PdhCloseQuery, PDH_FMT_COUNTERVALUE, PDH_FMT_DOUBLE, PDH_FMT_LARGE, PDH_HCOUNTER, PDH_HQUERY, + PdhAddCounterW, PdhCloseQuery, PdhCollectQueryData, PdhCollectQueryDataEx, + PdhGetFormattedCounterValue, PdhOpenQueryA, PdhRemoveCounter, PDH_FMT_COUNTERVALUE, + PDH_FMT_DOUBLE, PDH_FMT_LARGE, PDH_HCOUNTER, PDH_HQUERY, }; use winapi::um::synchapi::{CreateEventA, WaitForSingleObject}; use winapi::um::winbase::{INFINITE, WAIT_OBJECT_0}; diff --git a/src/windows/system.rs b/src/windows/system.rs index 83d3d2776..9e4020738 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -19,25 +19,25 @@ use RefreshKind; use SystemExt; use windows::network::{self, NetworkData}; -use windows::process::{ - compute_cpu_usage, get_handle, get_parent_process_id, update_proc_info, Process, -}; +use windows::process::{compute_cpu_usage, get_handle, update_proc_info, Process}; use windows::processor::CounterValue; use windows::tools::*; +use ntapi::ntexapi::{ + NtQuerySystemInformation, SystemProcessInformation, SYSTEM_PROCESS_INFORMATION, +}; use winapi::shared::minwindef::{DWORD, FALSE}; +use winapi::shared::ntdef::{PVOID, ULONG}; +use winapi::shared::ntstatus::STATUS_INFO_LENGTH_MISMATCH; use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::minwinbase::STILL_ACTIVE; use winapi::um::pdh::PdhEnumObjectItemsW; use winapi::um::processthreadsapi::GetExitCodeProcess; -use winapi::um::psapi::K32EnumProcesses; use winapi::um::sysinfoapi::{GlobalMemoryStatusEx, MEMORYSTATUSEX}; use winapi::um::winnt::HANDLE; use rayon::prelude::*; -const PROCESS_LEN: usize = 10192; - /// Struct containing system's information. pub struct System { process_list: HashMap, @@ -53,52 +53,24 @@ pub struct System { uptime: u64, } -impl System { - fn clear_procs(&mut self) { - if self.processors.len() > 0 { - let mut to_delete = Vec::new(); - - for (pid, proc_) in self.process_list.iter_mut() { - if !is_proc_running(get_handle(proc_)) { - to_delete.push(*pid); - } else { - compute_cpu_usage(proc_, self.processors.len() as u64 - 1); - } - } - for pid in to_delete { - self.process_list.remove(&pid); - } - } - } -} - -struct Wrap(Process); - -unsafe impl Send for Wrap {} - -struct WrapSystem<'a>(UnsafeCell<&'a mut System>); - -impl<'a> WrapSystem<'a> { - fn get(&self) -> &'a mut System { - unsafe { *(self.0.get()) } - } -} +// Useful for parallel iterations. +struct Wrap(T); -unsafe impl<'a> Send for WrapSystem<'a> {} -unsafe impl<'a> Sync for WrapSystem<'a> {} +unsafe impl Send for Wrap {} +unsafe impl Sync for Wrap {} impl SystemExt for System { #[allow(non_snake_case)] fn new_with_specifics(refreshes: RefreshKind) -> System { let mut s = System { - process_list: HashMap::new(), + process_list: HashMap::with_capacity(500), mem_total: 0, mem_free: 0, swap_total: 0, swap_free: 0, processors: init_processors(), temperatures: component::get_components(), - disks: Vec::new(), + disks: Vec::with_capacity(2), query: Query::new(), network: network::new(), uptime: get_uptime(), @@ -294,47 +266,111 @@ impl SystemExt for System { } fn refresh_processes(&mut self) { - // I think that 10192 as length will be enough to get all processes at once... - let mut process_ids: Vec = Vec::with_capacity(PROCESS_LEN); - let mut cb_needed = 0; + // Windows 10 notebook requires at least 512kb of memory to make it in one go + let mut buffer_size: usize = 512 * 1024; + loop { + let mut process_information: Vec = Vec::with_capacity(buffer_size); + + let mut cb_needed = 0; + let ntstatus = unsafe { + process_information.set_len(buffer_size); + NtQuerySystemInformation( + SystemProcessInformation, + process_information.as_mut_ptr() as PVOID, + buffer_size as ULONG, + &mut cb_needed, + ) + }; + + if ntstatus != STATUS_INFO_LENGTH_MISMATCH { + if ntstatus < 0 { + eprintln!( + "Couldn't get process infos: NtQuerySystemInformation returned {}", + ntstatus + ); + } - unsafe { - process_ids.set_len(PROCESS_LEN); - } - let size = ::std::mem::size_of::() * process_ids.len(); - unsafe { - if K32EnumProcesses(process_ids.as_mut_ptr(), size as DWORD, &mut cb_needed) == 0 { - return; - } - } - let nb_processes = cb_needed / ::std::mem::size_of::() as DWORD; - unsafe { - process_ids.set_len(nb_processes as usize); - } + // Parse the data block to get process information + let mut process_ids = Vec::with_capacity(500); + let mut process_information_offset = 0; + loop { + let p = unsafe { + process_information + .as_ptr() + .offset(process_information_offset) + as *const SYSTEM_PROCESS_INFORMATION + }; + let pi = unsafe { &*p }; - { - let this = WrapSystem(UnsafeCell::new(self)); - - process_ids - .par_iter() - .filter_map(|pid| { - let pid = *pid as usize; - if !refresh_existing_process(this.get(), pid, false) { - let ppid = unsafe { get_parent_process_id(pid) }; - let mut p = Process::new(pid, ppid, 0); - update_proc_info(&mut p); - Some(Wrap(p)) - } else { - None + process_ids.push(Wrap(p)); + + if pi.NextEntryOffset == 0 { + break; } - }) - .collect::>() + + process_information_offset += pi.NextEntryOffset as isize; + } + let nb_processors = self.processors.len() as u64; + let process_list = Wrap(UnsafeCell::new(&mut self.process_list)); + // TODO: instead of using parallel iterator only here, would be better to be able + // to run it over `process_information` directly! + let processes = process_ids + .into_par_iter() + .filter_map(|pi| unsafe { + let pi = *pi.0; + let pid = pi.UniqueProcessId as usize; + if let Some(proc_) = (*process_list.0.get()).get_mut(&pid) { + proc_.memory = (pi.WorkingSetSize as u64) >> 10u64; + proc_.virtual_memory = (pi.VirtualSize as u64) >> 10u64; + compute_cpu_usage(proc_, nb_processors); + proc_.updated = true; + return None; + } + let mut real_len = 0; + while real_len < pi.ImageName.Length as usize + && *pi.ImageName.Buffer.offset(real_len as isize) != 0 + { + real_len += 1; + } + let name: &[u16] = + ::std::slice::from_raw_parts(pi.ImageName.Buffer, real_len); + let mut p = Process::new_full( + pid, + if pi.InheritedFromUniqueProcessId as usize != 0 { + Some(pi.InheritedFromUniqueProcessId as usize) + } else { + None + }, + (pi.WorkingSetSize as u64) >> 10u64, + (pi.VirtualSize as u64) >> 10u64, + String::from_utf16_lossy(name), + ); + compute_cpu_usage(&mut p, nb_processors); + Some(p) + }) + .collect::>(); + self.process_list.retain(|_, v| { + let x = v.updated; + v.updated = false; + x + }); + for p in processes.into_iter() { + self.process_list.insert(p.pid(), p); + } + + break; + } + + // GetNewBufferSize + if cb_needed == 0 { + buffer_size *= 2; + continue; + } + // allocating a few more kilo bytes just in case there are some new process + // kicked in since new call to NtQuerySystemInformation + buffer_size = (cb_needed + (1024 * 10)) as usize; } - .into_iter() - .for_each(|p| { - self.process_list.insert(p.0.pid(), p.0); - }); - self.clear_procs(); + //; } fn refresh_disks(&mut self) { @@ -413,7 +449,7 @@ fn refresh_existing_process(s: &mut System, pid: Pid, compute_cpu: bool) -> bool } update_proc_info(entry); if compute_cpu { - compute_cpu_usage(entry, s.processors.len() as u64 - 1); + compute_cpu_usage(entry, s.processors.len() as u64); } true } else { From ea42fb4533d2efa91694f2bc2c5d0f963d2cc227 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 7 Dec 2019 01:56:56 +0100 Subject: [PATCH 010/171] Update crate version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 03d747e70..5c5bedb86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sysinfo" -version = "0.9.6" +version = "0.10.0" authors = ["Guillaume Gomez "] description = "Library to handle processes" From 535bafabaafd9a109bf332b5d24680aeb1212bcc Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 7 Dec 2019 16:28:16 +0100 Subject: [PATCH 011/171] Don't get system time more than necessary --- src/windows/process.rs | 19 +++++++++++++------ src/windows/system.rs | 11 ++++++----- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/windows/process.rs b/src/windows/process.rs index 37a44917d..8b6ac646e 100644 --- a/src/windows/process.rs +++ b/src/windows/process.rs @@ -509,7 +509,7 @@ unsafe fn get_proc_env(_handle: HANDLE, _pid: u32, _name: &str) -> Vec { ret } -pub fn get_executable_path(_pid: Pid) -> PathBuf { +pub(crate) fn get_executable_path(_pid: Pid) -> PathBuf { /*let where_req = format!("ProcessId={}", pid); if let Some(ret) = run_wmi(&["process", "where", &where_req, "get", "ExecutablePath"]) { @@ -523,14 +523,10 @@ pub fn get_executable_path(_pid: Pid) -> PathBuf { PathBuf::new() } -pub fn compute_cpu_usage(p: &mut Process, nb_processors: u64) { +pub(crate) fn get_system_computation_time() -> ULARGE_INTEGER { unsafe { let mut now: ULARGE_INTEGER = ::std::mem::zeroed(); - let mut sys: ULARGE_INTEGER = ::std::mem::zeroed(); - let mut user: ULARGE_INTEGER = ::std::mem::zeroed(); let mut ftime: FILETIME = zeroed(); - let mut fsys: FILETIME = zeroed(); - let mut fuser: FILETIME = zeroed(); GetSystemTimeAsFileTime(&mut ftime); memcpy( @@ -538,6 +534,17 @@ pub fn compute_cpu_usage(p: &mut Process, nb_processors: u64) { &mut ftime as *mut FILETIME as *mut c_void, size_of::(), ); + now + } +} + +pub(crate) fn compute_cpu_usage(p: &mut Process, nb_processors: u64, now: ULARGE_INTEGER) { + unsafe { + let mut sys: ULARGE_INTEGER = ::std::mem::zeroed(); + let mut user: ULARGE_INTEGER = ::std::mem::zeroed(); + let mut ftime: FILETIME = zeroed(); + let mut fsys: FILETIME = zeroed(); + let mut fuser: FILETIME = zeroed(); GetProcessTimes( *p.handle, diff --git a/src/windows/system.rs b/src/windows/system.rs index 9e4020738..7cf955933 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -19,7 +19,7 @@ use RefreshKind; use SystemExt; use windows::network::{self, NetworkData}; -use windows::process::{compute_cpu_usage, get_handle, update_proc_info, Process}; +use windows::process::{compute_cpu_usage, get_handle, get_system_computation_time, update_proc_info, Process}; use windows::processor::CounterValue; use windows::tools::*; @@ -268,6 +268,7 @@ impl SystemExt for System { fn refresh_processes(&mut self) { // Windows 10 notebook requires at least 512kb of memory to make it in one go let mut buffer_size: usize = 512 * 1024; + loop { let mut process_information: Vec = Vec::with_capacity(buffer_size); @@ -312,6 +313,7 @@ impl SystemExt for System { } let nb_processors = self.processors.len() as u64; let process_list = Wrap(UnsafeCell::new(&mut self.process_list)); + let system_time = get_system_computation_time(); // TODO: instead of using parallel iterator only here, would be better to be able // to run it over `process_information` directly! let processes = process_ids @@ -322,7 +324,7 @@ impl SystemExt for System { if let Some(proc_) = (*process_list.0.get()).get_mut(&pid) { proc_.memory = (pi.WorkingSetSize as u64) >> 10u64; proc_.virtual_memory = (pi.VirtualSize as u64) >> 10u64; - compute_cpu_usage(proc_, nb_processors); + compute_cpu_usage(proc_, nb_processors, system_time); proc_.updated = true; return None; } @@ -345,7 +347,7 @@ impl SystemExt for System { (pi.VirtualSize as u64) >> 10u64, String::from_utf16_lossy(name), ); - compute_cpu_usage(&mut p, nb_processors); + compute_cpu_usage(&mut p, nb_processors, system_time); Some(p) }) .collect::>(); @@ -370,7 +372,6 @@ impl SystemExt for System { // kicked in since new call to NtQuerySystemInformation buffer_size = (cb_needed + (1024 * 10)) as usize; } - //; } fn refresh_disks(&mut self) { @@ -449,7 +450,7 @@ fn refresh_existing_process(s: &mut System, pid: Pid, compute_cpu: bool) -> bool } update_proc_info(entry); if compute_cpu { - compute_cpu_usage(entry, s.processors.len() as u64); + compute_cpu_usage(entry, s.processors.len() as u64, get_system_computation_time()); } true } else { From 055c6ba81e9eb8d1c964286e92cdb418073b5b57 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 7 Dec 2019 16:36:45 +0100 Subject: [PATCH 012/171] Improve process name getter --- src/windows/system.rs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/windows/system.rs b/src/windows/system.rs index 7cf955933..203a0dfc1 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -328,14 +328,7 @@ impl SystemExt for System { proc_.updated = true; return None; } - let mut real_len = 0; - while real_len < pi.ImageName.Length as usize - && *pi.ImageName.Buffer.offset(real_len as isize) != 0 - { - real_len += 1; - } - let name: &[u16] = - ::std::slice::from_raw_parts(pi.ImageName.Buffer, real_len); + let name = get_process_name(&pi, pid); let mut p = Process::new_full( pid, if pi.InheritedFromUniqueProcessId as usize != 0 { @@ -345,7 +338,7 @@ impl SystemExt for System { }, (pi.WorkingSetSize as u64) >> 10u64, (pi.VirtualSize as u64) >> 10u64, - String::from_utf16_lossy(name), + name, ); compute_cpu_usage(&mut p, nb_processors, system_time); Some(p) @@ -457,3 +450,24 @@ fn refresh_existing_process(s: &mut System, pid: Pid, compute_cpu: bool) -> bool false } } + +fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: usize) -> String { + let name = &process.ImageName; + if name.Buffer.is_null() { + match process_id { + 0 => "Idle".to_owned(), + 4 => "System".to_owned(), + _ => format!(" Process {}", process_id), + } + } else { + let slice = unsafe { + std::slice::from_raw_parts( + name.Buffer, + //The length is in bytes, not the length of string + name.Length as usize / std::mem::size_of::(), + ) + }; + + String::from_utf16_lossy(slice) + } +} From f9c4dd011f6388c387340a227d9de67d3ad0ec2d Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 7 Dec 2019 16:44:05 +0100 Subject: [PATCH 013/171] Remove unneeded winapi feature --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5c5bedb86..77cded6dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ rayon = "^1.0" doc-comment = "0.3" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "tlhelp32", "winbase", "winerror", "winioctl", "winnt"] } +winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt"] } ntapi = "0.3" [target.'cfg(not(target_os = "unknown"))'.dependencies] From 020b7ad01f40356557e4b3924c1d871bc233eb70 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 7 Dec 2019 17:02:52 +0100 Subject: [PATCH 014/171] Improve disks API speed --- src/windows/system.rs | 4 +- src/windows/tools.rs | 230 +++++++++++++++++++++--------------------- 2 files changed, 117 insertions(+), 117 deletions(-) diff --git a/src/windows/system.rs b/src/windows/system.rs index 203a0dfc1..83012da73 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -368,9 +368,9 @@ impl SystemExt for System { } fn refresh_disks(&mut self) { - for disk in &mut self.disks { + self.disks.par_iter_mut().for_each(|disk| { disk.update(); - } + }); } fn refresh_disk_list(&mut self) { diff --git a/src/windows/tools.rs b/src/windows/tools.rs index 6e0065649..8d279af4c 100644 --- a/src/windows/tools.rs +++ b/src/windows/tools.rs @@ -12,6 +12,8 @@ use std::collections::HashMap; use std::ffi::OsStr; use std::mem::{size_of, zeroed}; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + use winapi::ctypes::c_void; use winapi::shared::minwindef::{BYTE, DWORD, MAX_PATH, TRUE}; @@ -132,134 +134,132 @@ pub unsafe fn get_drive_size(handle: HANDLE) -> u64 { } pub unsafe fn get_disks() -> Vec { - let mut disks = Vec::new(); let drives = GetLogicalDrives(); if drives == 0 { - return disks; + return Vec::new(); } - for x in 0..size_of::() * 8 { - if (drives >> x) & 1 == 0 { - continue; - } - let mount_point = [b'A' as u16 + x as u16, b':' as u16, b'\\' as u16, 0]; - if GetDriveTypeW(mount_point.as_ptr()) != DRIVE_FIXED { - continue; - } - let mut name = [0u16; MAX_PATH + 1]; - let mut file_system = [0u16; 32]; - if GetVolumeInformationW( - mount_point.as_ptr(), - name.as_mut_ptr(), - name.len() as DWORD, - ::std::ptr::null_mut(), - ::std::ptr::null_mut(), - ::std::ptr::null_mut(), - file_system.as_mut_ptr(), - file_system.len() as DWORD, - ) == 0 - { - continue; - } - let mut pos = 0; - for x in name.iter() { - if *x == 0 { - break; + (0..size_of::() * 8).into_par_iter() + .filter_map(|x| { + if (drives >> x) & 1 == 0 { + return None; } - pos += 1; - } - let name = String::from_utf16_lossy(&name[..pos]); - let name = OsStr::new(&name); + let mount_point = [b'A' as u16 + x as u16, b':' as u16, b'\\' as u16, 0]; + if GetDriveTypeW(mount_point.as_ptr()) != DRIVE_FIXED { + return None; + } + let mut name = [0u16; MAX_PATH + 1]; + let mut file_system = [0u16; 32]; + if GetVolumeInformationW( + mount_point.as_ptr(), + name.as_mut_ptr(), + name.len() as DWORD, + ::std::ptr::null_mut(), + ::std::ptr::null_mut(), + ::std::ptr::null_mut(), + file_system.as_mut_ptr(), + file_system.len() as DWORD, + ) == 0 + { + return None; + } + let mut pos = 0; + for x in name.iter() { + if *x == 0 { + break; + } + pos += 1; + } + let name = String::from_utf16_lossy(&name[..pos]); + let name = OsStr::new(&name); - pos = 0; - for x in file_system.iter() { - if *x == 0 { - break; + pos = 0; + for x in file_system.iter() { + if *x == 0 { + break; + } + pos += 1; } - pos += 1; - } - let file_system: Vec = file_system[..pos].iter().map(|x| *x as u8).collect(); + let file_system: Vec = file_system[..pos].iter().map(|x| *x as u8).collect(); - let drive_name = [ - b'\\' as u16, - b'\\' as u16, - b'.' as u16, - b'\\' as u16, - b'A' as u16 + x as u16, - b':' as u16, - 0, - ]; - let handle = open_drive(&drive_name, 0); - if handle == INVALID_HANDLE_VALUE { - disks.push(new_disk( - name, - &mount_point, - &file_system, - DiskType::Unknown(-1), + let drive_name = [ + b'\\' as u16, + b'\\' as u16, + b'.' as u16, + b'\\' as u16, + b'A' as u16 + x as u16, + b':' as u16, 0, - )); - CloseHandle(handle); - continue; - } - let disk_size = get_drive_size(handle); - /*let mut spq_trim: ffi::STORAGE_PROPERTY_QUERY = ::std::mem::zeroed(); - spq_trim.PropertyId = ffi::StorageDeviceTrimProperty; - spq_trim.QueryType = ffi::PropertyStandardQuery; - let mut dtd: ffi::DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed();*/ - #[allow(non_snake_case)] - #[repr(C)] - struct STORAGE_PROPERTY_QUERY { - PropertyId: i32, - QueryType: i32, - AdditionalParameters: [BYTE; 1], - } - #[allow(non_snake_case)] - #[repr(C)] - struct DEVICE_TRIM_DESCRIPTOR { - Version: DWORD, - Size: DWORD, - TrimEnabled: BOOLEAN, - } - let mut spq_trim = STORAGE_PROPERTY_QUERY { - PropertyId: 8i32, - QueryType: 0i32, - AdditionalParameters: [0], - }; - let mut dtd: DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed(); + ]; + let handle = open_drive(&drive_name, 0); + if handle == INVALID_HANDLE_VALUE { + CloseHandle(handle); + return Some(new_disk( + name, + &mount_point, + &file_system, + DiskType::Unknown(-1), + 0, + )); + } + let disk_size = get_drive_size(handle); + /*let mut spq_trim: ffi::STORAGE_PROPERTY_QUERY = ::std::mem::zeroed(); + spq_trim.PropertyId = ffi::StorageDeviceTrimProperty; + spq_trim.QueryType = ffi::PropertyStandardQuery; + let mut dtd: ffi::DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed();*/ + #[allow(non_snake_case)] + #[repr(C)] + struct STORAGE_PROPERTY_QUERY { + PropertyId: i32, + QueryType: i32, + AdditionalParameters: [BYTE; 1], + } + #[allow(non_snake_case)] + #[repr(C)] + struct DEVICE_TRIM_DESCRIPTOR { + Version: DWORD, + Size: DWORD, + TrimEnabled: BOOLEAN, + } + let mut spq_trim = STORAGE_PROPERTY_QUERY { + PropertyId: 8i32, + QueryType: 0i32, + AdditionalParameters: [0], + }; + let mut dtd: DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed(); - let mut dw_size = 0; - if DeviceIoControl( - handle, - IOCTL_STORAGE_QUERY_PROPERTY, - &mut spq_trim as *mut STORAGE_PROPERTY_QUERY as *mut c_void, - size_of::() as DWORD, - &mut dtd as *mut DEVICE_TRIM_DESCRIPTOR as *mut c_void, - size_of::() as DWORD, - &mut dw_size, - ::std::ptr::null_mut(), - ) == 0 - || dw_size != size_of::() as DWORD - { - disks.push(new_disk( + let mut dw_size = 0; + if DeviceIoControl( + handle, + IOCTL_STORAGE_QUERY_PROPERTY, + &mut spq_trim as *mut STORAGE_PROPERTY_QUERY as *mut c_void, + size_of::() as DWORD, + &mut dtd as *mut DEVICE_TRIM_DESCRIPTOR as *mut c_void, + size_of::() as DWORD, + &mut dw_size, + ::std::ptr::null_mut(), + ) == 0 + || dw_size != size_of::() as DWORD + { + CloseHandle(handle); + return Some(new_disk( + name, + &mount_point, + &file_system, + DiskType::Unknown(-1), + disk_size, + )); + } + let is_ssd = dtd.TrimEnabled != 0; + CloseHandle(handle); + Some(new_disk( name, &mount_point, &file_system, - DiskType::Unknown(-1), + if is_ssd { DiskType::SSD } else { DiskType::HDD }, disk_size, - )); - CloseHandle(handle); - continue; - } - let is_ssd = dtd.TrimEnabled != 0; - CloseHandle(handle); - disks.push(new_disk( - name, - &mount_point, - &file_system, - if is_ssd { DiskType::SSD } else { DiskType::HDD }, - disk_size, - )); - } - disks + )) + }) + .collect::>() } #[allow(non_snake_case)] From f914a546787f21633b8d5f7922f1ce79836a454e Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 7 Dec 2019 17:03:09 +0100 Subject: [PATCH 015/171] fmt --- src/windows/system.rs | 10 ++++++++-- src/windows/tools.rs | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/windows/system.rs b/src/windows/system.rs index 83012da73..6e3e77b52 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -19,7 +19,9 @@ use RefreshKind; use SystemExt; use windows::network::{self, NetworkData}; -use windows::process::{compute_cpu_usage, get_handle, get_system_computation_time, update_proc_info, Process}; +use windows::process::{ + compute_cpu_usage, get_handle, get_system_computation_time, update_proc_info, Process, +}; use windows::processor::CounterValue; use windows::tools::*; @@ -443,7 +445,11 @@ fn refresh_existing_process(s: &mut System, pid: Pid, compute_cpu: bool) -> bool } update_proc_info(entry); if compute_cpu { - compute_cpu_usage(entry, s.processors.len() as u64, get_system_computation_time()); + compute_cpu_usage( + entry, + s.processors.len() as u64, + get_system_computation_time(), + ); } true } else { diff --git a/src/windows/tools.rs b/src/windows/tools.rs index 8d279af4c..abcac0078 100644 --- a/src/windows/tools.rs +++ b/src/windows/tools.rs @@ -138,7 +138,8 @@ pub unsafe fn get_disks() -> Vec { if drives == 0 { return Vec::new(); } - (0..size_of::() * 8).into_par_iter() + (0..size_of::() * 8) + .into_par_iter() .filter_map(|x| { if (drives >> x) & 1 == 0 { return None; From ffb273d62b90ce5bf74bee2163e458f7ef460fd1 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 7 Dec 2019 17:03:26 +0100 Subject: [PATCH 016/171] Update crate version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 77cded6dc..e86463dd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sysinfo" -version = "0.10.0" +version = "0.10.1" authors = ["Guillaume Gomez "] description = "Library to handle processes" From 4afec8513baeaea05181f91e9ef0e16bb04f5f95 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Mon, 9 Dec 2019 01:15:54 +0100 Subject: [PATCH 017/171] Start implementation to get temperatures --- Cargo.toml | 2 +- src/windows/component.rs | 270 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 271 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e86463dd3..570835301 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ rayon = "^1.0" doc-comment = "0.3" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt"] } +winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase"] } ntapi = "0.3" [target.'cfg(not(target_os = "unknown"))'.dependencies] diff --git a/src/windows/component.rs b/src/windows/component.rs index a1c063b33..2c50e72a3 100644 --- a/src/windows/component.rs +++ b/src/windows/component.rs @@ -45,5 +45,275 @@ impl ComponentExt for Component { } pub fn get_components() -> Vec { + Connection::new() + .and_then(|x| x.initialize_security()) + .and_then(|x| x.create_instance()) + .and_then(|x| x.connect_server()) + .and_then(|x| x.set_proxy_blanket()) + .and_then(|x| x.exec_query()) + .and_then(|x| { + x.iterate(); + Some(()) + }); Vec::new() } + +use std::ptr::null_mut; + +use winapi::shared::rpcdce::{RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, RPC_C_AUTHN_LEVEL_CALL}; +use winapi::shared::winerror::FAILED; +use winapi::shared::wtypesbase::CLSCTX_INPROC_SERVER; +use winapi::um::combaseapi::{CoCreateInstance, CoInitializeEx, CoUninitialize, CoInitializeSecurity, CoSetProxyBlanket}; +use winapi::um::objbase::COINIT_MULTITHREADED; +use winapi::um::objidl::EOAC_NONE; +use winapi::um::oleauto::SysAllocString; +use winapi::um::oleauto::VariantClear; +use winapi::um::wbemcli::{CLSID_WbemLocator, IEnumWbemClassObject, IID_IWbemLocator, IWbemLocator, IWbemServices, WBEM_S_NO_ERROR, WBEM_FLAG_NONSYSTEM_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_FLAG_FORWARD_ONLY}; +use winapi::shared::wtypes::BSTR; +use winapi::um::oleauto::SysFreeString; +use winapi::um::wbemcli::IWbemClassObject; + use winapi::um::oaidl::VARIANT_n3; + +struct Instance(*mut IWbemLocator); + +impl Drop for Instance { + fn drop(&mut self) { + if !self.0.is_null() { + unsafe { (*self.0).Release(); } + } + } +} + +struct ServerConnection(*mut IWbemServices); + +impl Drop for ServerConnection { + fn drop(&mut self) { + if !self.0.is_null() { + unsafe { (*self.0).Release(); } + } + } +} + +struct Enumerator(*mut IEnumWbemClassObject); + +impl Drop for Enumerator { + fn drop(&mut self) { + if !self.0.is_null() { + unsafe { (*self.0).Release(); } + } + } +} + +macro_rules! bstr { + ($($x:expr),*) => {{ + let x: &[u16] = &[$($x as u16),*]; + SysAllocString(x.as_ptr()) + }} +} + +struct Connection { + instance: Option, + server_connection: Option, + enumerator: Option, +} + +impl Connection { + fn new() -> Option { + let x = unsafe { CoInitializeEx(null_mut(), 0) }; + if FAILED(x) { + eprintln!("1 => {}", x); + None + } else { + Some(Connection { + instance: None, + server_connection: None, + enumerator: None, + }) + } + } + + fn initialize_security(self) -> Option { + if FAILED(unsafe { + CoInitializeSecurity( + null_mut(), + -1, + null_mut(), + null_mut(), + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, + null_mut(), + EOAC_NONE, + null_mut(), + ) + }) { + eprintln!("2"); + None + } else { + Some(self) + } + } + + fn create_instance(mut self) -> Option { + let mut pLoc = null_mut(); + + if FAILED(unsafe { + CoCreateInstance( + *(&CLSID_WbemLocator as *const _ as *const usize) as *mut _, + null_mut(), + CLSCTX_INPROC_SERVER, + *(&IID_IWbemLocator as *const _ as *const usize) as *mut _, + &mut pLoc as *mut _ as *mut _, + ) + }) { + eprintln!("3"); + None + } else { + self.instance = Some(Instance(pLoc)); + Some(self) + } + } + + fn connect_server(mut self) -> Option { + let mut pSvc = null_mut(); + + if let Some(ref instance) = self.instance { + unsafe { + let s = bstr!('R', 'O', 'O', 'T', '\\', 'W', 'M', 'I'); + let res = (*instance.0).ConnectServer( + s, + null_mut(), + null_mut(), + null_mut(), + 0, + null_mut(), + null_mut(), + &mut pSvc as *mut _, + ); + SysFreeString(s); + if FAILED(res) { + eprintln!("4"); + return None; + } + } + } else { + eprintln!("5"); + return None; + } + self.server_connection = Some(ServerConnection(pSvc)); + Some(self) + } + + fn set_proxy_blanket(self) -> Option { + if let Some(ref server_connection) = self.server_connection { + unsafe { + if FAILED(CoSetProxyBlanket( + server_connection.0 as *mut _, + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + null_mut(), + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, + null_mut(), + EOAC_NONE, + )) { + eprintln!("6"); + return None; + } + } + } else { + eprintln!("7"); + return None; + } + Some(self) + } + + fn exec_query(mut self) -> Option { + let mut pEnumerator = null_mut(); + + if let Some(ref server_connection) = self.server_connection { + unsafe { + let s = bstr!('W', 'Q', 'L'); // query kind + let query = bstr!('S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','M','S','A','c','p','i','_','T','h','e','r','m','a','l','Z','o','n','e','T','e','m','p','e','r','a','t','u','r','e'); + let hres = (*server_connection.0).ExecQuery( + s, + query, + (WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY) as _, + null_mut(), + &mut pEnumerator as *mut _, + ); + SysFreeString(s); + SysFreeString(query); + if FAILED(hres) { + eprintln!("8"); + return None; + } + } + } else { + eprintln!("9"); + return None; + } + self.enumerator = Some(Enumerator(pEnumerator)); + Some(self) + } + + fn iterate(mut self) { + let pEnum = match self.enumerator.take() { + Some(x) => x, + None => { + eprintln!("10"); + return; + } + }; + loop { + let mut pObj: *mut IWbemClassObject = null_mut(); + let mut uReturned = 0; + + let hRes = unsafe { + (*pEnum.0).Next( + 0, // Time out + 1, // One object + &mut pObj as *mut _, + &mut uReturned, + ) + }; + + if uReturned == 0 { + eprintln!("and done!"); + break; + } + + unsafe { + (*pObj).BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY as _); + + let mut pVal: VARIANT_n3 = ::std::mem::uninitialized(); + let mut pstrName: BSTR = null_mut(); + + while (*pObj).Next(0, &mut pstrName, &mut pVal as *mut _ as *mut _, null_mut(), null_mut()) == WBEM_S_NO_ERROR as _ { + { + let mut i = 0; + while (*pstrName.offset(i)) != 0 { + i += 1; + } + let bytes = ::std::slice::from_raw_parts(pstrName as *const u16, i as usize + 1); + i = 0; + while (*pVal.bstrVal().offset(i)) != 0 { + i += 1; + } + let bytes2 = ::std::slice::from_raw_parts(*pVal.bstrVal() as *const u16, i as usize + 1); + println!("==> {}::{}", String::from_utf16_lossy(bytes), String::from_utf16_lossy(bytes2)); + } + SysFreeString(pstrName); + VariantClear(&mut pVal as *mut _ as *mut _); + } + } + + unsafe { (*pObj).Release(); } + } + } +} + +impl Drop for Connection { + fn drop(&mut self) { + unsafe { CoUninitialize(); } + } +} From 4597f39c5a6b0d974138b9a2420e4db11cbb8d46 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 10 Dec 2019 00:06:10 +0100 Subject: [PATCH 018/171] Working version --- src/windows/component.rs | 76 +++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/src/windows/component.rs b/src/windows/component.rs index 2c50e72a3..0b44561be 100644 --- a/src/windows/component.rs +++ b/src/windows/component.rs @@ -67,17 +67,18 @@ use winapi::um::combaseapi::{CoCreateInstance, CoInitializeEx, CoUninitialize, C use winapi::um::objbase::COINIT_MULTITHREADED; use winapi::um::objidl::EOAC_NONE; use winapi::um::oleauto::SysAllocString; -use winapi::um::oleauto::VariantClear; +use winapi::um::oleauto::{VariantClear, VariantInit}; use winapi::um::wbemcli::{CLSID_WbemLocator, IEnumWbemClassObject, IID_IWbemLocator, IWbemLocator, IWbemServices, WBEM_S_NO_ERROR, WBEM_FLAG_NONSYSTEM_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_FLAG_FORWARD_ONLY}; use winapi::shared::wtypes::BSTR; use winapi::um::oleauto::SysFreeString; use winapi::um::wbemcli::IWbemClassObject; - use winapi::um::oaidl::VARIANT_n3; + use winapi::um::oaidl::{VARIANT, VARIANT_n3}; struct Instance(*mut IWbemLocator); impl Drop for Instance { fn drop(&mut self) { + println!("Instance::drop"); if !self.0.is_null() { unsafe { (*self.0).Release(); } } @@ -88,6 +89,7 @@ struct ServerConnection(*mut IWbemServices); impl Drop for ServerConnection { fn drop(&mut self) { + println!("ServerConnection::drop"); if !self.0.is_null() { unsafe { (*self.0).Release(); } } @@ -98,6 +100,7 @@ struct Enumerator(*mut IEnumWbemClassObject); impl Drop for Enumerator { fn drop(&mut self) { + println!("Enumerator::drop"); if !self.0.is_null() { unsafe { (*self.0).Release(); } } @@ -106,7 +109,7 @@ impl Drop for Enumerator { macro_rules! bstr { ($($x:expr),*) => {{ - let x: &[u16] = &[$($x as u16),*]; + let x: &[u16] = &[$($x as u16),*, 0]; SysAllocString(x.as_ptr()) }} } @@ -119,20 +122,18 @@ struct Connection { impl Connection { fn new() -> Option { - let x = unsafe { CoInitializeEx(null_mut(), 0) }; - if FAILED(x) { - eprintln!("1 => {}", x); - None - } else { - Some(Connection { - instance: None, - server_connection: None, - enumerator: None, - }) - } + // "Funnily", this function returns ok, false or "this function has already been called". + // So whatever, let's just ignore whatever it might return then! + unsafe { CoInitializeEx(null_mut(), 0) }; + Some(Connection { + instance: None, + server_connection: None, + enumerator: None, + }) } fn initialize_security(self) -> Option { + println!("initialize_security"); if FAILED(unsafe { CoInitializeSecurity( null_mut(), @@ -154,14 +155,15 @@ impl Connection { } fn create_instance(mut self) -> Option { + println!("create_instance"); let mut pLoc = null_mut(); if FAILED(unsafe { CoCreateInstance( - *(&CLSID_WbemLocator as *const _ as *const usize) as *mut _, + &CLSID_WbemLocator as *const _, null_mut(), CLSCTX_INPROC_SERVER, - *(&IID_IWbemLocator as *const _ as *const usize) as *mut _, + &IID_IWbemLocator as *const _, &mut pLoc as *mut _ as *mut _, ) }) { @@ -174,11 +176,12 @@ impl Connection { } fn connect_server(mut self) -> Option { + println!("connect_server"); let mut pSvc = null_mut(); if let Some(ref instance) = self.instance { unsafe { - let s = bstr!('R', 'O', 'O', 'T', '\\', 'W', 'M', 'I'); + let s = bstr!('r', 'o', 'o', 't', '\\', 'W', 'M', 'I'); let res = (*instance.0).ConnectServer( s, null_mut(), @@ -191,7 +194,7 @@ impl Connection { ); SysFreeString(s); if FAILED(res) { - eprintln!("4"); + eprintln!("4 => {}", res); return None; } } @@ -204,6 +207,7 @@ impl Connection { } fn set_proxy_blanket(self) -> Option { + println!("set_proxy_blanket"); if let Some(ref server_connection) = self.server_connection { unsafe { if FAILED(CoSetProxyBlanket( @@ -233,6 +237,7 @@ impl Connection { if let Some(ref server_connection) = self.server_connection { unsafe { let s = bstr!('W', 'Q', 'L'); // query kind + // SELECT * FROM MSAcpi_ThermalZoneTemperature let query = bstr!('S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','M','S','A','c','p','i','_','T','h','e','r','m','a','l','Z','o','n','e','T','e','m','p','e','r','a','t','u','r','e'); let hres = (*server_connection.0).ExecQuery( s, @@ -241,6 +246,7 @@ impl Connection { null_mut(), &mut pEnumerator as *mut _, ); + println!("xa"); SysFreeString(s); SysFreeString(query); if FAILED(hres) { @@ -269,14 +275,20 @@ impl Connection { let mut uReturned = 0; let hRes = unsafe { - (*pEnum.0).Next( - 0, // Time out + println!("foo {:?}", (*pEnum.0).lpVtbl as *const _ as usize); + use winapi::um::wbemcli::WBEM_INFINITE; + let x = (*(*pEnum.0).lpVtbl).Next; + x( + pEnum.0, + WBEM_INFINITE as _, // Time out 1, // One object &mut pObj as *mut _, &mut uReturned, ) }; + println!("-> {:?}", hRes); + if uReturned == 0 { eprintln!("and done!"); break; @@ -285,22 +297,31 @@ impl Connection { unsafe { (*pObj).BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY as _); - let mut pVal: VARIANT_n3 = ::std::mem::uninitialized(); + let mut pVal: VARIANT = ::std::mem::uninitialized(); let mut pstrName: BSTR = null_mut(); + //VariantInit(&mut pVal as *mut _ as *mut _); while (*pObj).Next(0, &mut pstrName, &mut pVal as *mut _ as *mut _, null_mut(), null_mut()) == WBEM_S_NO_ERROR as _ { { + println!("c"); let mut i = 0; while (*pstrName.offset(i)) != 0 { i += 1; } - let bytes = ::std::slice::from_raw_parts(pstrName as *const u16, i as usize + 1); + let bytes = ::std::slice::from_raw_parts(pstrName as *const u16, i as usize); + println!("a"); i = 0; - while (*pVal.bstrVal().offset(i)) != 0 { + let pVal = &pVal.n1; + let x = pVal.decVal(); + println!("x {:?} {}", x.Hi32, x.Lo64); + /*while *x.offset(i) != 0 { + println!("a"); i += 1; } - let bytes2 = ::std::slice::from_raw_parts(*pVal.bstrVal() as *const u16, i as usize + 1); - println!("==> {}::{}", String::from_utf16_lossy(bytes), String::from_utf16_lossy(bytes2)); + println!("b {:?}", x); + let bytes2 = ::std::slice::from_raw_parts(*x as *const u16, i as usize); + println!("==> {}::{}", String::from_utf16_lossy(bytes), String::from_utf16_lossy(bytes2));*/ + println!("==> {}::{}", String::from_utf16_lossy(bytes), x.Hi32); } SysFreeString(pstrName); VariantClear(&mut pVal as *mut _ as *mut _); @@ -314,6 +335,11 @@ impl Connection { impl Drop for Connection { fn drop(&mut self) { + // Those three calls are here to enforce that they get dropped in the good order. + self.enumerator.take(); + self.server_connection.take(); + self.instance.take(); + println!("Connection::drop"); unsafe { CoUninitialize(); } } } From 5e147e644c27a454c5ca990c8e93b8430229cb24 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 10 Dec 2019 01:12:55 +0100 Subject: [PATCH 019/171] clean temperatures code --- src/windows/component.rs | 243 ++++++++++++++++++++------------------- src/windows/system.rs | 6 +- 2 files changed, 130 insertions(+), 119 deletions(-) diff --git a/src/windows/component.rs b/src/windows/component.rs index 0b44561be..b6c7c0477 100644 --- a/src/windows/component.rs +++ b/src/windows/component.rs @@ -4,24 +4,74 @@ // Copyright (c) 2018 Guillaume Gomez // +use std::ptr::null_mut; + +use winapi::shared::rpcdce::{RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, RPC_C_AUTHN_LEVEL_CALL}; +use winapi::shared::winerror::{FAILED, SUCCEEDED}; +use winapi::shared::wtypesbase::CLSCTX_INPROC_SERVER; +use winapi::um::combaseapi::{CoCreateInstance, CoInitializeEx, CoUninitialize, CoInitializeSecurity, CoSetProxyBlanket}; +use winapi::um::objidl::EOAC_NONE; +use winapi::um::oleauto::{SysAllocString, SysFreeString, VariantClear}; +use winapi::um::wbemcli::{CLSID_WbemLocator, IEnumWbemClassObject, IID_IWbemLocator, IWbemClassObject, IWbemLocator, IWbemServices, WBEM_FLAG_NONSYSTEM_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_FLAG_FORWARD_ONLY}; +use winapi::um::oaidl::VARIANT; + use ComponentExt; /// Struct containing a component information (temperature and name for the moment). +/// +/// Please note that on Windows, you need to have Administrator priviledges to get this +/// information. pub struct Component { temperature: f32, max: f32, critical: Option, label: String, + connection: Option, } impl Component { /// Creates a new `Component` with the given information. - pub fn new(label: String, max: Option, critical: Option) -> Component { - Component { - temperature: 0f32, - label: label, - max: max.unwrap_or(0.0), - critical: critical, + fn new() -> Option { + match Connection::new() + .and_then(|x| x.initialize_security()) + .and_then(|x| x.create_instance()) + .and_then(|x| x.connect_server()) + .and_then(|x| x.set_proxy_blanket()) + .and_then(|x| x.exec_query()) { + Some(mut c) => match c.get_temperature(true) { + Some((temperature, critical)) => Some(Component { + temperature, + label: "Computer".to_owned(), + max: temperature, + critical, + connection: Some(c), + }), + None => None, + }, + None => None, + } + } + + pub(crate) fn refresh(&mut self) { + if self.connection.is_none() { + self.connection = Connection::new() + .and_then(|x| x.initialize_security()) + .and_then(|x| x.create_instance()) + .and_then(|x| x.connect_server()) + .and_then(|x| x.set_proxy_blanket()); + } + self.connection = if let Some(x) = self.connection.take() { + x.exec_query() + } else { + None + }; + if let Some(ref mut connection) = self.connection { + if let Some((temperature, _)) = connection.get_temperature(false) { + self.temperature = temperature; + if self.temperature > self.max { + self.max = self.temperature; + } + } } } } @@ -45,40 +95,16 @@ impl ComponentExt for Component { } pub fn get_components() -> Vec { - Connection::new() - .and_then(|x| x.initialize_security()) - .and_then(|x| x.create_instance()) - .and_then(|x| x.connect_server()) - .and_then(|x| x.set_proxy_blanket()) - .and_then(|x| x.exec_query()) - .and_then(|x| { - x.iterate(); - Some(()) - }); - Vec::new() + match Component::new() { + Some(c) => vec![c], + None => Vec::new(), + } } -use std::ptr::null_mut; - -use winapi::shared::rpcdce::{RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, RPC_C_AUTHN_LEVEL_CALL}; -use winapi::shared::winerror::FAILED; -use winapi::shared::wtypesbase::CLSCTX_INPROC_SERVER; -use winapi::um::combaseapi::{CoCreateInstance, CoInitializeEx, CoUninitialize, CoInitializeSecurity, CoSetProxyBlanket}; -use winapi::um::objbase::COINIT_MULTITHREADED; -use winapi::um::objidl::EOAC_NONE; -use winapi::um::oleauto::SysAllocString; -use winapi::um::oleauto::{VariantClear, VariantInit}; -use winapi::um::wbemcli::{CLSID_WbemLocator, IEnumWbemClassObject, IID_IWbemLocator, IWbemLocator, IWbemServices, WBEM_S_NO_ERROR, WBEM_FLAG_NONSYSTEM_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_FLAG_FORWARD_ONLY}; -use winapi::shared::wtypes::BSTR; -use winapi::um::oleauto::SysFreeString; -use winapi::um::wbemcli::IWbemClassObject; - use winapi::um::oaidl::{VARIANT, VARIANT_n3}; - struct Instance(*mut IWbemLocator); impl Drop for Instance { fn drop(&mut self) { - println!("Instance::drop"); if !self.0.is_null() { unsafe { (*self.0).Release(); } } @@ -89,7 +115,6 @@ struct ServerConnection(*mut IWbemServices); impl Drop for ServerConnection { fn drop(&mut self) { - println!("ServerConnection::drop"); if !self.0.is_null() { unsafe { (*self.0).Release(); } } @@ -100,7 +125,6 @@ struct Enumerator(*mut IEnumWbemClassObject); impl Drop for Enumerator { fn drop(&mut self) { - println!("Enumerator::drop"); if !self.0.is_null() { unsafe { (*self.0).Release(); } } @@ -133,7 +157,6 @@ impl Connection { } fn initialize_security(self) -> Option { - println!("initialize_security"); if FAILED(unsafe { CoInitializeSecurity( null_mut(), @@ -147,7 +170,6 @@ impl Connection { null_mut(), ) }) { - eprintln!("2"); None } else { Some(self) @@ -155,8 +177,7 @@ impl Connection { } fn create_instance(mut self) -> Option { - println!("create_instance"); - let mut pLoc = null_mut(); + let mut p_loc = null_mut(); if FAILED(unsafe { CoCreateInstance( @@ -164,23 +185,22 @@ impl Connection { null_mut(), CLSCTX_INPROC_SERVER, &IID_IWbemLocator as *const _, - &mut pLoc as *mut _ as *mut _, + &mut p_loc as *mut _ as *mut _, ) }) { - eprintln!("3"); None } else { - self.instance = Some(Instance(pLoc)); + self.instance = Some(Instance(p_loc)); Some(self) } } fn connect_server(mut self) -> Option { - println!("connect_server"); - let mut pSvc = null_mut(); + let mut p_svc = null_mut(); if let Some(ref instance) = self.instance { unsafe { + // "root\WMI" let s = bstr!('r', 'o', 'o', 't', '\\', 'W', 'M', 'I'); let res = (*instance.0).ConnectServer( s, @@ -190,24 +210,21 @@ impl Connection { 0, null_mut(), null_mut(), - &mut pSvc as *mut _, + &mut p_svc as *mut _, ); SysFreeString(s); if FAILED(res) { - eprintln!("4 => {}", res); return None; } } } else { - eprintln!("5"); return None; } - self.server_connection = Some(ServerConnection(pSvc)); + self.server_connection = Some(ServerConnection(p_svc)); Some(self) } fn set_proxy_blanket(self) -> Option { - println!("set_proxy_blanket"); if let Some(ref server_connection) = self.server_connection { unsafe { if FAILED(CoSetProxyBlanket( @@ -220,115 +237,106 @@ impl Connection { null_mut(), EOAC_NONE, )) { - eprintln!("6"); return None; } } } else { - eprintln!("7"); return None; } Some(self) } fn exec_query(mut self) -> Option { - let mut pEnumerator = null_mut(); + let mut p_enumerator = null_mut(); if let Some(ref server_connection) = self.server_connection { unsafe { + // "WQL" let s = bstr!('W', 'Q', 'L'); // query kind - // SELECT * FROM MSAcpi_ThermalZoneTemperature - let query = bstr!('S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','M','S','A','c','p','i','_','T','h','e','r','m','a','l','Z','o','n','e','T','e','m','p','e','r','a','t','u','r','e'); + // "SELECT * FROM MSAcpi_ThermalZoneTemperature" + let query = bstr!('S','E','L','E','C','T',' ', + '*',' ', + 'F','R','O','M',' ', + 'M','S','A','c','p','i','_','T','h','e','r','m','a','l','Z','o','n','e','T','e','m','p','e','r','a','t','u','r','e'); let hres = (*server_connection.0).ExecQuery( s, query, (WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY) as _, null_mut(), - &mut pEnumerator as *mut _, + &mut p_enumerator as *mut _, ); - println!("xa"); SysFreeString(s); SysFreeString(query); if FAILED(hres) { - eprintln!("8"); return None; } } } else { - eprintln!("9"); return None; } - self.enumerator = Some(Enumerator(pEnumerator)); + self.enumerator = Some(Enumerator(p_enumerator)); Some(self) } - fn iterate(mut self) { - let pEnum = match self.enumerator.take() { + fn get_temperature(&mut self, get_critical: bool) -> Option<(f32, Option)> { + let p_enum = match self.enumerator.take() { Some(x) => x, None => { - eprintln!("10"); - return; + return None; } }; - loop { - let mut pObj: *mut IWbemClassObject = null_mut(); - let mut uReturned = 0; - - let hRes = unsafe { - println!("foo {:?}", (*pEnum.0).lpVtbl as *const _ as usize); - use winapi::um::wbemcli::WBEM_INFINITE; - let x = (*(*pEnum.0).lpVtbl).Next; - x( - pEnum.0, - WBEM_INFINITE as _, // Time out - 1, // One object - &mut pObj as *mut _, - &mut uReturned, - ) + let mut p_obj: *mut IWbemClassObject = null_mut(); + let mut nb_returned = 0; + + unsafe { + use winapi::um::wbemcli::WBEM_INFINITE; + (*p_enum.0).Next( + WBEM_INFINITE as _, // Time out + 1, // One object + &mut p_obj as *mut _, + &mut nb_returned, + ); + }; + + if nb_returned == 0 { + return None; // not enough rights I suppose... + } + + unsafe { + (*p_obj).BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY as _); + + let mut p_val: VARIANT = ::std::mem::MaybeUninit::uninit().assume_init(); + // "CurrentTemperature" + let temp = bstr!('C','u','r','r','e','n','t','T','e','m','p','e','r','a','t','u','r','e'); + let res = (*p_obj).Get(temp, 0, &mut p_val, null_mut(), null_mut()); + + SysFreeString(temp); + VariantClear(&mut p_val as *mut _ as *mut _); + + let temp = if SUCCEEDED(res) { + // temperature is given in tenth of degrees Kelvin + (p_val.n1.decVal().Lo64 / 10) as f32 - 273.15 + } else { + (*p_obj).Release(); + return None; }; - println!("-> {:?}", hRes); + let mut critical = None; + if get_critical { + // "CriticalPoint" + let crit = bstr!('C','r','i','t','i','c','a','l','T','r','i','p','P','o','i','n','t'); + let res = (*p_obj).Get(crit, 0, &mut p_val, null_mut(), null_mut()); - if uReturned == 0 { - eprintln!("and done!"); - break; - } + SysFreeString(crit); + VariantClear(&mut p_val as *mut _ as *mut _); - unsafe { - (*pObj).BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY as _); - - let mut pVal: VARIANT = ::std::mem::uninitialized(); - let mut pstrName: BSTR = null_mut(); - - //VariantInit(&mut pVal as *mut _ as *mut _); - while (*pObj).Next(0, &mut pstrName, &mut pVal as *mut _ as *mut _, null_mut(), null_mut()) == WBEM_S_NO_ERROR as _ { - { - println!("c"); - let mut i = 0; - while (*pstrName.offset(i)) != 0 { - i += 1; - } - let bytes = ::std::slice::from_raw_parts(pstrName as *const u16, i as usize); - println!("a"); - i = 0; - let pVal = &pVal.n1; - let x = pVal.decVal(); - println!("x {:?} {}", x.Hi32, x.Lo64); - /*while *x.offset(i) != 0 { - println!("a"); - i += 1; - } - println!("b {:?}", x); - let bytes2 = ::std::slice::from_raw_parts(*x as *const u16, i as usize); - println!("==> {}::{}", String::from_utf16_lossy(bytes), String::from_utf16_lossy(bytes2));*/ - println!("==> {}::{}", String::from_utf16_lossy(bytes), x.Hi32); - } - SysFreeString(pstrName); - VariantClear(&mut pVal as *mut _ as *mut _); + if SUCCEEDED(res) { + // temperature is given in tenth of degrees Kelvin + critical = Some((p_val.n1.decVal().Lo64 / 10) as f32 - 273.15); } } - - unsafe { (*pObj).Release(); } + (*p_obj).Release(); + Some((temp, critical)) } } } @@ -339,7 +347,6 @@ impl Drop for Connection { self.enumerator.take(); self.server_connection.take(); self.instance.take(); - println!("Connection::drop"); unsafe { CoUninitialize(); } } } diff --git a/src/windows/system.rs b/src/windows/system.rs index 6e3e77b52..35ba37cc9 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -250,8 +250,12 @@ impl SystemExt for System { } } + /// Please note that on Windows, you need to have Administrator priviledges to get this + /// information. fn refresh_temperatures(&mut self) { - // does nothing for the moment... + for component in &mut self.temperatures { + component.refresh(); + } } fn refresh_network(&mut self) { From cc9d3b34a320c72f5bc1a144e7c0f73455dbc731 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 10 Dec 2019 01:14:25 +0100 Subject: [PATCH 020/171] fmt --- src/windows/component.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/windows/component.rs b/src/windows/component.rs index b6c7c0477..8d0efd630 100644 --- a/src/windows/component.rs +++ b/src/windows/component.rs @@ -6,13 +6,21 @@ use std::ptr::null_mut; -use winapi::shared::rpcdce::{RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, RPC_C_AUTHN_LEVEL_CALL}; +use winapi::shared::rpcdce::{ + RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + RPC_C_AUTHN_LEVEL_CALL, +}; use winapi::shared::winerror::{FAILED, SUCCEEDED}; use winapi::shared::wtypesbase::CLSCTX_INPROC_SERVER; -use winapi::um::combaseapi::{CoCreateInstance, CoInitializeEx, CoUninitialize, CoInitializeSecurity, CoSetProxyBlanket}; +use winapi::um::combaseapi::{ + CoCreateInstance, CoInitializeEx, CoUninitialize, CoInitializeSecurity, CoSetProxyBlanket, +}; use winapi::um::objidl::EOAC_NONE; use winapi::um::oleauto::{SysAllocString, SysFreeString, VariantClear}; -use winapi::um::wbemcli::{CLSID_WbemLocator, IEnumWbemClassObject, IID_IWbemLocator, IWbemClassObject, IWbemLocator, IWbemServices, WBEM_FLAG_NONSYSTEM_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_FLAG_FORWARD_ONLY}; +use winapi::um::wbemcli::{ + CLSID_WbemLocator, IEnumWbemClassObject, IID_IWbemLocator, IWbemClassObject, IWbemLocator, + IWbemServices, WBEM_FLAG_NONSYSTEM_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_FLAG_FORWARD_ONLY, +}; use winapi::um::oaidl::VARIANT; use ComponentExt; From a5a524bafb759adb0d08196d12873809989a4850 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 10 Dec 2019 01:17:14 +0100 Subject: [PATCH 021/171] Upgrade version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 570835301..f0cde000f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sysinfo" -version = "0.10.1" +version = "0.10.2" authors = ["Guillaume Gomez "] description = "Library to handle processes" From f7cff91d4d6faf96c3c981e1833f8ee9d1be7ea4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 10 Dec 2019 18:33:14 +0100 Subject: [PATCH 022/171] Add more benchmarks --- benches/basic.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/benches/basic.rs b/benches/basic.rs index 407c8774b..6fae247dc 100644 --- a/benches/basic.rs +++ b/benches/basic.rs @@ -77,3 +77,30 @@ fn bench_refresh_network(b: &mut test::Bencher) { s.refresh_network(); }); } + +#[bench] +fn bench_refresh_memory(b: &mut test::Bencher) { + let mut s = sysinfo::System::new(); + + b.iter(move || { + s.refresh_memory(); + }); +} + +#[bench] +fn bench_refresh_cpu(b: &mut test::Bencher) { + let mut s = sysinfo::System::new(); + + b.iter(move || { + s.refresh_cpu(); + }); +} + +#[bench] +fn bench_refresh_temperatures(b: &mut test::Bencher) { + let mut s = sysinfo::System::new(); + + b.iter(move || { + s.refresh_temperatures(); + }); +} From cfcb35b569232251992b430a0428137fda9f3ab8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 10 Dec 2019 18:47:31 +0100 Subject: [PATCH 023/171] Add benchmarks results for linux --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/README.md b/README.md index a9a258d44..3baea5f66 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,51 @@ To build the C example, just run: > LD_LIBRARY_PATH=target/release/ ./simple ``` +### Benchmarks + +You can run the benchmarks locally with rust **nightly** by doing: + +```bash +> cargo bench +``` + +Here are the current results: + +**Linux** + +
+ +```text +test bench_new ... bench: 12,950,615 ns/iter (+/- 1,054,683) +test bench_refresh_all ... bench: 5,412,422 ns/iter (+/- 1,839,554) +test bench_refresh_cpu ... bench: 12,967 ns/iter (+/- 618) +test bench_refresh_disk_lists ... bench: 50,005 ns/iter (+/- 7,639) +test bench_refresh_disks ... bench: 2,314 ns/iter (+/- 45) +test bench_refresh_memory ... bench: 11,037 ns/iter (+/- 1,172) +test bench_refresh_network ... bench: 53,703 ns/iter (+/- 1,396) +test bench_refresh_process ... bench: 43,730 ns/iter (+/- 3,936) +test bench_refresh_processes ... bench: 4,673,568 ns/iter (+/- 494,504) +test bench_refresh_system ... bench: 48,861 ns/iter (+/- 3,433) +test bench_refresh_temperatures ... bench: 23,046 ns/iter (+/- 2,131) +``` +
+ +**Windows** + +
+ +```text +``` +
+ +**OSX** + +
+ +```text +``` +
+ ## Donations If you appreciate my work and want to support me, you can do it here: From f717b3b6606cde5d9abf83b1ff9fdbc740f39df9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 10 Dec 2019 19:05:14 +0100 Subject: [PATCH 024/171] Add benchmarks results for OSX --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 3baea5f66..dd187bb34 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,17 @@ test bench_refresh_temperatures ... bench: 23,046 ns/iter (+/- 2,131)
```text +test bench_new ... bench: 64,062,254 ns/iter (+/- 8,845,126) +test bench_refresh_all ... bench: 4,285,670 ns/iter (+/- 467,963) +test bench_refresh_cpu ... bench: 10,712 ns/iter (+/- 1,493) +test bench_refresh_disk_lists ... bench: 837,489 ns/iter (+/- 48,593) +test bench_refresh_disks ... bench: 956 ns/iter (+/- 128) +test bench_refresh_memory ... bench: 3,327 ns/iter (+/- 462) +test bench_refresh_network ... bench: 34,465 ns/iter (+/- 5,228) +test bench_refresh_process ... bench: 3,935 ns/iter (+/- 1,135) +test bench_refresh_processes ... bench: 2,489,203 ns/iter (+/- 140,567) +test bench_refresh_system ... bench: 741,774 ns/iter (+/- 335,431) +test bench_refresh_temperatures ... bench: 680,362 ns/iter (+/- 167,343) ```
From aa27e85c0145aa8da68272f6b379da6ba510a6b9 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 10 Dec 2019 20:48:11 +0100 Subject: [PATCH 025/171] Add benchmarks results for Windows --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index dd187bb34..51d6d2a1f 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,17 @@ test bench_refresh_temperatures ... bench: 23,046 ns/iter (+/- 2,131)
```text +test bench_new ... bench: 61,548,071 ns/iter (+/- 196,093,742) +test bench_refresh_all ... bench: 2,541,951 ns/iter (+/- 482,285) +test bench_refresh_cpu ... bench: 460 ns/iter (+/- 478) +test bench_refresh_disk_lists ... bench: 152,940 ns/iter (+/- 8,330) +test bench_refresh_disks ... bench: 55,597 ns/iter (+/- 9,629) +test bench_refresh_memory ... bench: 2,130 ns/iter (+/- 486) +test bench_refresh_network ... bench: 212 ns/iter (+/- 216) +test bench_refresh_process ... bench: 38 ns/iter (+/- 33) +test bench_refresh_processes ... bench: 2,175,034 ns/iter (+/- 315,585) +test bench_refresh_system ... bench: 2,508 ns/iter (+/- 224) +test bench_refresh_temperatures ... bench: 1 ns/iter (+/- 0) ```
From 522b1dca3494b8032a405d4ac81540d1b0da5e64 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 13 Dec 2019 19:11:31 +0100 Subject: [PATCH 026/171] Fix doc example --- src/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traits.rs b/src/traits.rs index e2773ae09..54f1447d4 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -138,7 +138,7 @@ pub trait SystemExt: Sized { /// // If you want the disks list afterwards, just call the corresponding /// // "refresh_disk_list": /// system.refresh_disk_list(); - /// assert!(system.get_disks().len() > 0); + /// let disks = system.get_disks(); /// ``` fn new_with_specifics(refreshes: RefreshKind) -> Self; From 6f523f82eac0a7266c72151b8088a0178f85fad8 Mon Sep 17 00:00:00 2001 From: Ashley Date: Sat, 14 Dec 2019 18:05:28 +0100 Subject: [PATCH 027/171] Support wasi --- Cargo.toml | 2 +- src/common.rs | 2 +- src/sysinfo.rs | 2 +- src/utils.rs | 16 ++++++++-------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f0cde000f..919af423e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ doc-comment = "0.3" winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase"] } ntapi = "0.3" -[target.'cfg(not(target_os = "unknown"))'.dependencies] +[target.'cfg(not(any(target_os = "unknown", target_arch = "wasm32")))'.dependencies] libc = "0.2" [lib] diff --git a/src/common.rs b/src/common.rs index a80b5963c..1ac80781b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -11,7 +11,7 @@ pub trait AsU32 { } cfg_if! { - if #[cfg(any(windows, target_os = "unknown"))] { + if #[cfg(any(windows, target_os = "unknown", target_arch = "wasm32"))] { /// Process id. pub type Pid = usize; diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 4ea6b634b..998909275 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -50,7 +50,7 @@ #[macro_use] extern crate cfg_if; -#[cfg(not(target_os = "unknown"))] +#[cfg(not(any(target_os = "unknown", target_arch = "wasm32")))] extern crate libc; extern crate rayon; diff --git a/src/utils.rs b/src/utils.rs index 66191e2f2..3520de01d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,19 +4,19 @@ // Copyright (c) 2017 Guillaume Gomez // -#[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] +#[cfg(not(any(target_os = "windows", target_os = "unknown", target_arch = "wasm32")))] use libc::{c_char, lstat, stat, S_IFLNK, S_IFMT}; -#[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] +#[cfg(not(any(target_os = "windows", target_os = "unknown", target_arch = "wasm32")))] use std::ffi::OsStr; -#[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] +#[cfg(not(any(target_os = "windows", target_os = "unknown", target_arch = "wasm32")))] use std::fs; -#[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] +#[cfg(not(any(target_os = "windows", target_os = "unknown", target_arch = "wasm32")))] use std::os::unix::ffi::OsStrExt; -#[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] +#[cfg(not(any(target_os = "windows", target_os = "unknown", target_arch = "wasm32")))] use std::path::{Path, PathBuf}; use Pid; -#[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] +#[cfg(not(any(target_os = "windows", target_os = "unknown", target_arch = "wasm32")))] pub fn realpath(original: &Path) -> PathBuf { use std::mem::MaybeUninit; @@ -51,7 +51,7 @@ pub fn realpath(original: &Path) -> PathBuf { } /* convert a path to a NUL-terminated Vec suitable for use with C functions */ -#[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] +#[cfg(not(any(target_os = "windows", target_os = "unknown", target_arch = "wasm32")))] pub fn to_cpath(path: &Path) -> Vec { let path_os: &OsStr = path.as_ref(); let mut cpath = path_os.as_bytes().to_vec(); @@ -64,7 +64,7 @@ pub fn to_cpath(path: &Path) -> Vec { /// `Err` is returned in case the platform isn't supported. pub fn get_current_pid() -> Result { cfg_if! { - if #[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] { + if #[cfg(not(any(target_os = "windows", target_os = "unknown", target_arch = "wasm32")))] { fn inner() -> Result { unsafe { Ok(::libc::getpid()) } } From d03a8a275475d108e71cf03d379e73ecced90dfd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 11 Dec 2019 23:37:56 +0100 Subject: [PATCH 028/171] Clean up linux code --- src/linux/system.rs | 283 ++++++++++++++++++++++---------------------- 1 file changed, 140 insertions(+), 143 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index 8213fda86..9464b44a3 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -54,7 +54,7 @@ impl System { if !self.processors.is_empty() { let (new, old) = get_raw_times(&self.processors[0]); let total_time = (if old > new { 1 } else { new - old }) as f32; - let mut to_delete = Vec::new(); + let mut to_delete = Vec::with_capacity(20); let nb_processors = self.processors.len() as u64 - 1; for (pid, proc_) in &mut self.process_list.tasks { @@ -134,10 +134,10 @@ impl SystemExt for System { mem_free: 0, swap_total: 0, swap_free: 0, - processors: Vec::new(), + processors: Vec::with_capacity(4), page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 }, temperatures: component::get_components(), - disks: Vec::new(), + disks: Vec::with_capacity(2), network: network::new(), uptime: get_uptime(), }; @@ -453,152 +453,149 @@ fn _get_process_data( uptime: u64, now: u64, ) -> Result, ()> { - if let Some(Ok(nb)) = path.file_name().and_then(|x| x.to_str()).map(Pid::from_str) { - if nb == pid { - return Err(()); + let nb = match path.file_name().and_then(|x| x.to_str()).map(Pid::from_str) { + Some(Ok(nb)) if nb != pid => nb, + _ => return Err(()), + }; + let mut tmp = PathBuf::from(path); + + tmp.push("stat"); + let data = get_all_data(&tmp).map_err(|_| ())?; + // The stat file is "interesting" to parse, because spaces cannot + // be used as delimiters. The second field stores the command name + // surrounded by parentheses. Unfortunately, whitespace and + // parentheses are legal parts of the command, so parsing has to + // proceed like this: The first field is delimited by the first + // whitespace, the second field is everything until the last ')' + // in the entire string. All other fields are delimited by + // whitespace. + + let mut parts = Vec::with_capacity(20); + let mut data_it = data.splitn(2, ' '); + parts.push(unwrap_or_return!(data_it.next())); + // The following loses the ) from the input, but that's ok because + // we're not using it anyway. + let mut data_it = unwrap_or_return!(data_it.next()).rsplitn(2, ')'); + let data = unwrap_or_return!(data_it.next()); + parts.push(unwrap_or_return!(data_it.next())); + parts.extend(data.split_whitespace()); + let parent_memory = proc_list.memory; + let parent_virtual_memory = proc_list.virtual_memory; + if let Some(ref mut entry) = proc_list.tasks.get_mut(&nb) { + update_time_and_memory( + path, + entry, + &parts, + page_size_kb, + parent_memory, + parent_virtual_memory, + nb, + uptime, + now, + ); + return Ok(None); + } + + let parent_pid = if proc_list.pid != 0 { + Some(proc_list.pid) + } else { + match Pid::from_str(parts[3]) { + Ok(p) if p != 0 => Some(p), + _ => None, } - let mut tmp = PathBuf::from(path); - - tmp.push("stat"); - if let Ok(data) = get_all_data(&tmp) { - // The stat file is "interesting" to parse, because spaces cannot - // be used as delimiters. The second field stores the command name - // sourrounded by parentheses. Unfortunately, whitespace and - // parentheses are legal parts of the command, so parsing has to - // proceed like this: The first field is delimited by the first - // whitespace, the second field is everything until the last ')' - // in the entire string. All other fields are delimited by - // whitespace. - - let mut parts = Vec::new(); - let mut data_it = data.splitn(2, ' '); - parts.push(unwrap_or_return!(data_it.next())); - // The following loses the ) from the input, but that's ok because - // we're not using it anyway. - let mut data_it = unwrap_or_return!(data_it.next()).rsplitn(2, ')'); - let data = unwrap_or_return!(data_it.next()); - parts.push(unwrap_or_return!(data_it.next())); - parts.extend(data.split_whitespace()); - let parent_memory = proc_list.memory; - let parent_virtual_memory = proc_list.virtual_memory; - if let Some(ref mut entry) = proc_list.tasks.get_mut(&nb) { - update_time_and_memory( - path, - entry, - &parts, - page_size_kb, - parent_memory, - parent_virtual_memory, - nb, - uptime, - now, - ); - return Ok(None); - } + }; - let parent_pid = if proc_list.pid != 0 { - Some(proc_list.pid) + let clock_cycle = unsafe { sysconf(_SC_CLK_TCK) } as u64; + let since_boot = u64::from_str(parts[21]).unwrap_or(0) / clock_cycle; + let start_time = now + .checked_sub(uptime.checked_sub(since_boot).unwrap_or_else(|| 0)) + .unwrap_or_else(|| 0); + let mut p = Process::new(nb, parent_pid, start_time); + + p.status = parts[2] + .chars() + .next() + .and_then(|c| Some(ProcessStatus::from(c))) + .unwrap_or(ProcessStatus::Unknown(0)); + + tmp = PathBuf::from(path); + tmp.push("status"); + if let Ok(status_data) = get_all_data(&tmp) { + // We're only interested in the lines starting with Uid: and Gid: + // here. From these lines, we're looking at the second entry to get + // the effective u/gid. + + let f = |h: &str, n: &str| -> Option { + if h.starts_with(n) { + h.split_whitespace().nth(2).unwrap_or("0").parse().ok() } else { - match Pid::from_str(parts[3]) { - Ok(p) if p != 0 => Some(p), - _ => None, - } - }; - - let clock_cycle = unsafe { sysconf(_SC_CLK_TCK) } as u64; - let since_boot = u64::from_str(parts[21]).unwrap_or(0) / clock_cycle; - let start_time = now - .checked_sub(uptime.checked_sub(since_boot).unwrap_or_else(|| 0)) - .unwrap_or_else(|| 0); - let mut p = Process::new(nb, parent_pid, start_time); - - p.status = parts[2] - .chars() - .next() - .and_then(|c| Some(ProcessStatus::from(c))) - .unwrap_or(ProcessStatus::Unknown(0)); - - tmp = PathBuf::from(path); - tmp.push("status"); - if let Ok(status_data) = get_all_data(&tmp) { - // We're only interested in the lines starting with Uid: and Gid: - // here. From these lines, we're looking at the second entry to get - // the effective u/gid. - - let f = |h: &str, n: &str| -> Option { - if h.starts_with(n) { - h.split_whitespace().nth(2).unwrap_or("0").parse().ok() - } else { - None - } - }; - let mut set_uid = false; - let mut set_gid = false; - for line in status_data.lines() { - if let Some(u) = f(line, "Uid:") { - assert!(!set_uid); - set_uid = true; - p.uid = u; - } - if let Some(g) = f(line, "Gid:") { - assert!(!set_gid); - set_gid = true; - p.gid = g; - } - } - assert!(set_uid && set_gid); + None } - - if proc_list.pid != 0 { - // If we're getting information for a child, no need to get those info since we - // already have them... - p.cmd = proc_list.cmd.clone(); - p.name = proc_list.name.clone(); - p.environ = proc_list.environ.clone(); - p.exe = proc_list.exe.clone(); - p.cwd = proc_list.cwd.clone(); - p.root = proc_list.root.clone(); - } else { - tmp = PathBuf::from(path); - tmp.push("cmdline"); - p.cmd = copy_from_file(&tmp); - p.name = p - .cmd - .get(0) - .map(|x| x.split('/').last().unwrap_or_else(|| "").to_owned()) - .unwrap_or_default(); - tmp = PathBuf::from(path); - tmp.push("environ"); - p.environ = copy_from_file(&tmp); - tmp = PathBuf::from(path); - tmp.push("exe"); - - p.exe = read_link(tmp.to_str().unwrap_or_else(|| "")) - .unwrap_or_else(|_| PathBuf::new()); - - tmp = PathBuf::from(path); - tmp.push("cwd"); - p.cwd = realpath(&tmp); - tmp = PathBuf::from(path); - tmp.push("root"); - p.root = realpath(&tmp); + }; + let mut set_uid = false; + let mut set_gid = false; + for line in status_data.lines() { + if let Some(u) = f(line, "Uid:") { + assert!(!set_uid); + set_uid = true; + p.uid = u; + } + if let Some(g) = f(line, "Gid:") { + assert!(!set_gid); + set_gid = true; + p.gid = g; } - - update_time_and_memory( - path, - &mut p, - &parts, - page_size_kb, - proc_list.memory, - proc_list.virtual_memory, - nb, - uptime, - now, - ); - return Ok(Some(p)); } - } - Err(()) + assert!(set_uid && set_gid); + } + + if proc_list.pid != 0 { + // If we're getting information for a child, no need to get those info since we + // already have them... + p.cmd = proc_list.cmd.clone(); + p.name = proc_list.name.clone(); + p.environ = proc_list.environ.clone(); + p.exe = proc_list.exe.clone(); + p.cwd = proc_list.cwd.clone(); + p.root = proc_list.root.clone(); + } else { + tmp = PathBuf::from(path); + tmp.push("cmdline"); + p.cmd = copy_from_file(&tmp); + p.name = p + .cmd + .get(0) + .map(|x| x.split('/').last().unwrap_or_else(|| "").to_owned()) + .unwrap_or_default(); + tmp = PathBuf::from(path); + tmp.push("environ"); + p.environ = copy_from_file(&tmp); + tmp = PathBuf::from(path); + tmp.push("exe"); + + p.exe = read_link(tmp.to_str().unwrap_or_else(|| "")) + .unwrap_or_else(|_| PathBuf::new()); + + tmp = PathBuf::from(path); + tmp.push("cwd"); + p.cwd = realpath(&tmp); + tmp = PathBuf::from(path); + tmp.push("root"); + p.root = realpath(&tmp); + } + + update_time_and_memory( + path, + &mut p, + &parts, + page_size_kb, + proc_list.memory, + proc_list.virtual_memory, + nb, + uptime, + now, + ); + Ok(Some(p)) } fn copy_from_file(entry: &Path) -> Vec { From b64eced5d0fce9ba4e3198f0a37f0dbab5e160af Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 12 Dec 2019 00:36:11 +0100 Subject: [PATCH 029/171] new attempt --- src/linux/system.rs | 153 ++++++++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 56 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index 9464b44a3..f2fd8c1fe 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -14,7 +14,7 @@ use sys::NetworkData; use Pid; use {DiskExt, ProcessExt, RefreshKind, SystemExt}; -use libc::{sysconf, uid_t, _SC_CLK_TCK, _SC_PAGESIZE}; +use libc::{sysconf, gid_t, uid_t, _SC_CLK_TCK, _SC_PAGESIZE}; use std::cell::UnsafeCell; use std::collections::HashMap; use std::fs::{self, read_link, File}; @@ -320,16 +320,16 @@ fn to_u64(v: &[u8]) -> u64 { x } -struct Wrap<'a>(UnsafeCell<&'a mut Process>); +struct Wrap<'a, T>(UnsafeCell<&'a mut T>); -impl<'a> Wrap<'a> { - fn get(&self) -> &'a mut Process { +impl<'a, T> Wrap<'a, T> { + fn get(&self) -> &'a mut T { unsafe { *(self.0.get()) } } } -unsafe impl<'a> Send for Wrap<'a> {} -unsafe impl<'a> Sync for Wrap<'a> {} +unsafe impl<'a, T> Send for Wrap<'a, T> {} +unsafe impl<'a, T> Sync for Wrap<'a, T> {} fn refresh_procs>( proc_list: &mut Process, @@ -445,6 +445,38 @@ macro_rules! unwrap_or_return { }}; } +fn _get_uid_and_gid(status_data: String) -> Option<(uid_t, gid_t)> { + // We're only interested in the lines starting with Uid: and Gid: + // here. From these lines, we're looking at the second entry to get + // the effective u/gid. + + let f = |h: &str, n: &str| -> Option { + if h.starts_with(n) { + h.split_whitespace().nth(2).unwrap_or("0").parse().ok() + } else { + None + } + }; + let mut uid = None; + let mut gid = None; + for line in status_data.lines() { + if let Some(u) = f(line, "Uid:") { + assert!(uid.is_none()); + uid = Some(u); + } else if let Some(g) = f(line, "Gid:") { + assert!(gid.is_none()); + gid = Some(g); + } else { + continue + } + if uid.is_some() && gid.is_some() { + break + } + } + assert!(uid.is_some() && gid.is_some()); + Some((uid.unwrap(), gid.unwrap())) +} + fn _get_process_data( path: &Path, proc_list: &mut Process, @@ -518,38 +550,10 @@ fn _get_process_data( .and_then(|c| Some(ProcessStatus::from(c))) .unwrap_or(ProcessStatus::Unknown(0)); - tmp = PathBuf::from(path); - tmp.push("status"); - if let Ok(status_data) = get_all_data(&tmp) { - // We're only interested in the lines starting with Uid: and Gid: - // here. From these lines, we're looking at the second entry to get - // the effective u/gid. - - let f = |h: &str, n: &str| -> Option { - if h.starts_with(n) { - h.split_whitespace().nth(2).unwrap_or("0").parse().ok() - } else { - None - } - }; - let mut set_uid = false; - let mut set_gid = false; - for line in status_data.lines() { - if let Some(u) = f(line, "Uid:") { - assert!(!set_uid); - set_uid = true; - p.uid = u; - } - if let Some(g) = f(line, "Gid:") { - assert!(!set_gid); - set_gid = true; - p.gid = g; - } - } - assert!(set_uid && set_gid); - } - if proc_list.pid != 0 { + tmp.pop(); + tmp.push("status"); + // If we're getting information for a child, no need to get those info since we // already have them... p.cmd = proc_list.cmd.clone(); @@ -558,28 +562,65 @@ fn _get_process_data( p.exe = proc_list.exe.clone(); p.cwd = proc_list.cwd.clone(); p.root = proc_list.root.clone(); + if let Ok(d) = get_all_data(&tmp) { + if let Some((uid, gid)) = _get_uid_and_gid(d) { + p.uid = uid; + p.gid = gid; + } + } } else { - tmp = PathBuf::from(path); - tmp.push("cmdline"); - p.cmd = copy_from_file(&tmp); - p.name = p - .cmd - .get(0) - .map(|x| x.split('/').last().unwrap_or_else(|| "").to_owned()) - .unwrap_or_default(); - tmp = PathBuf::from(path); - tmp.push("environ"); - p.environ = copy_from_file(&tmp); - tmp = PathBuf::from(path); - tmp.push("exe"); - - p.exe = read_link(tmp.to_str().unwrap_or_else(|| "")) - .unwrap_or_else(|_| PathBuf::new()); - - tmp = PathBuf::from(path); + #[derive(Clone, Copy)] + enum Kind { + Status, + Cmdline, + Environ, + Link, + } + { + let up = Wrap(UnsafeCell::new(&mut p)); + [ + (Kind::Status, "status"), + (Kind::Cmdline, "cmdline"), + (Kind::Environ, "environ"), + (Kind::Link, "exe"), + ].par_iter() + .for_each(|(k, s)| { + let mut tmp = PathBuf::from(path); + tmp.push(s); + match k { + Kind::Status => { + if let Ok(data) = get_all_data(&tmp) { + if let Some((uid, gid)) = _get_uid_and_gid(data) { + let p = up.get(); + p.uid = uid; + p.gid = gid; + } + } + } + Kind::Cmdline => { + let p = up.get(); + p.cmd = copy_from_file(&tmp); + p.name = p + .cmd + .get(0) + .map(|x| x.split('/').last().unwrap_or_else(|| "").to_owned()) + .unwrap_or_default();(k, copy_from_file(&tmp)); + } + Kind::Environ => { + up.get().environ = copy_from_file(&tmp); + } + Kind::Link => { + up.get().exe = read_link(tmp.to_str().unwrap_or_else(|| "")) + .unwrap_or_else(|_| PathBuf::new()); + } + } + }); + } + + tmp.pop(); tmp.push("cwd"); p.cwd = realpath(&tmp); - tmp = PathBuf::from(path); + tmp.pop(); tmp.push("root"); p.root = realpath(&tmp); } From 0e6f31071b0504204e9c651fcfc3e4fe55241335 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 13 Dec 2019 19:08:39 +0100 Subject: [PATCH 030/171] benches --- src/linux/system.rs | 185 +++++++++++++++++++++++++++----------------- src/sysinfo.rs | 2 + 2 files changed, 117 insertions(+), 70 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index f2fd8c1fe..fdcda287e 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -298,18 +298,6 @@ impl Default for System { } } -pub fn get_all_data>(file_path: P) -> io::Result { - use std::error::Error; - let mut file = File::open(file_path.as_ref())?; - let mut data = vec![0; 16_385]; - - let size = file.read(&mut data)?; - data.truncate(size); - let data = String::from_utf8(data) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.description()))?; - Ok(data) -} - fn to_u64(v: &[u8]) -> u64 { let mut x = 0; @@ -550,10 +538,16 @@ fn _get_process_data( .and_then(|c| Some(ProcessStatus::from(c))) .unwrap_or(ProcessStatus::Unknown(0)); - if proc_list.pid != 0 { - tmp.pop(); - tmp.push("status"); + tmp.pop(); + tmp.push("status"); + if let Ok(data) = get_all_data(&tmp) { + if let Some((uid, gid)) = _get_uid_and_gid(data) { + p.uid = uid; + p.gid = gid; + } + } + if proc_list.pid != 0 { // If we're getting information for a child, no need to get those info since we // already have them... p.cmd = proc_list.cmd.clone(); @@ -562,60 +556,22 @@ fn _get_process_data( p.exe = proc_list.exe.clone(); p.cwd = proc_list.cwd.clone(); p.root = proc_list.root.clone(); - if let Ok(d) = get_all_data(&tmp) { - if let Some((uid, gid)) = _get_uid_and_gid(d) { - p.uid = uid; - p.gid = gid; - } - } } else { - #[derive(Clone, Copy)] - enum Kind { - Status, - Cmdline, - Environ, - Link, - } - { - let up = Wrap(UnsafeCell::new(&mut p)); - [ - (Kind::Status, "status"), - (Kind::Cmdline, "cmdline"), - (Kind::Environ, "environ"), - (Kind::Link, "exe"), - ].par_iter() - .for_each(|(k, s)| { - let mut tmp = PathBuf::from(path); - tmp.push(s); - match k { - Kind::Status => { - if let Ok(data) = get_all_data(&tmp) { - if let Some((uid, gid)) = _get_uid_and_gid(data) { - let p = up.get(); - p.uid = uid; - p.gid = gid; - } - } - } - Kind::Cmdline => { - let p = up.get(); - p.cmd = copy_from_file(&tmp); - p.name = p - .cmd - .get(0) - .map(|x| x.split('/').last().unwrap_or_else(|| "").to_owned()) - .unwrap_or_default();(k, copy_from_file(&tmp)); - } - Kind::Environ => { - up.get().environ = copy_from_file(&tmp); - } - Kind::Link => { - up.get().exe = read_link(tmp.to_str().unwrap_or_else(|| "")) - .unwrap_or_else(|_| PathBuf::new()); - } - } - }); - } + tmp.pop(); + tmp.push("cmdline"); + p.cmd = copy_from_file(&tmp); + p.name = p + .cmd + .get(0) + .map(|x| x.split('/').last().unwrap_or_else(|| "").to_owned()) + .unwrap_or_default(); + tmp.pop(); + tmp.push("environ"); + p.environ = copy_from_file(&tmp); + tmp.pop(); + tmp.push("exe"); + p.exe = read_link(tmp.to_str().unwrap_or_else(|| "")) + .unwrap_or_else(|_| PathBuf::new()); tmp.pop(); tmp.push("cwd"); @@ -639,6 +595,70 @@ fn _get_process_data( Ok(Some(p)) } +#[bench] +fn bench_copy_from_file(b: &mut bench::Bencher) { + extern { fn getpid() -> ::libc::pid_t; } + let pid = unsafe { getpid() }; + let x = format!("/proc/{}/environ", pid); + let path = Path::new(&x); + b.iter(move || { + copy_from_file(path); + }); +} +#[bench] +fn bench_get_all_data(b: &mut bench::Bencher) { + extern { fn getpid() -> ::libc::pid_t; } + let pid = unsafe { getpid() }; + let x = format!("/proc/{}/status", pid); + let path = Path::new(&x); + b.iter(move || { + get_all_data(path); + }); +} +#[bench] +fn bench_read_file(b: &mut bench::Bencher) { + extern { fn getpid() -> ::libc::pid_t; } + let pid = unsafe { getpid() }; + let x = format!("/proc/{}/status", pid); + let path = Path::new(&x); + b.iter(move || { + if let Ok(mut file) = File::open(path) { + let mut data = vec![0; 16_385]; + file.read(&mut data); + } + }); +} +#[bench] +fn bench_read_file_no_reopen(b: &mut bench::Bencher) { + use std::io::Seek; + extern { fn getpid() -> ::libc::pid_t; } + let pid = unsafe { getpid() }; + let x = format!("/proc/{}/status", pid); + let path = Path::new(&x); + let mut file = File::open(path).expect("file"); + b.iter(move || { + file.seek(::std::io::SeekFrom::Start(0)).expect("seek begin"); + let mut data = vec![0; 16_385]; + file.read(&mut data); + }); +} +#[bench] +fn bench_read_file_seek(b: &mut bench::Bencher) { + use std::io::Seek; + extern { fn getpid() -> ::libc::pid_t; } + let pid = unsafe { getpid() }; + let x = format!("/proc/{}/status", pid); + let path = Path::new(&x); + b.iter(move || { + if let Ok(mut file) = File::open(path) { + let pos = file.seek(::std::io::SeekFrom::End(0)).expect("seek end"); + file.seek(::std::io::SeekFrom::Start(0)).expect("seek begin"); + let mut data = Vec::with_capacity(pos as _); + file.read_exact(&mut data); + } + }); +} + fn copy_from_file(entry: &Path) -> Vec { match File::open(entry.to_str().unwrap_or("/")) { Ok(mut f) => { @@ -646,10 +666,24 @@ fn copy_from_file(entry: &Path) -> Vec { if let Ok(size) = f.read(&mut data) { data.truncate(size); - data.split(|x| *x == b'\0') + let mut out = Vec::with_capacity(20); + let mut start = 0; + for (pos, x) in data.iter().enumerate() { + if *x == 0 { + if pos - start > 1 { + if let Ok(s) = ::std::str::from_utf8(&data[start..pos]) + .map(|x| x.trim().to_owned()) { + out.push(s); + } + } + start = pos; + } + } + out + /*data.split(|x| *x == b'\0') .filter_map(|x| ::std::str::from_utf8(x).map(|x| x.trim().to_owned()).ok()) .filter(|x| !x.is_empty()) - .collect() + .collect()*/ } else { Vec::new() } @@ -658,6 +692,17 @@ fn copy_from_file(entry: &Path) -> Vec { } } +pub fn get_all_data>(file_path: P) -> io::Result { + use std::error::Error; + let mut file = File::open(file_path.as_ref())?; + let mut data = vec![0; 16_385]; + + let size = file.read(&mut data)?; + data.truncate(size); + Ok(String::from_utf8(data) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.description()))?) +} + fn get_all_disks() -> Vec { let content = get_all_data("/proc/mounts").unwrap_or_default(); let disks = content.lines().filter(|line| { diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 998909275..390cea2fb 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -41,6 +41,7 @@ //! println!("used swap : {} kB", system.get_used_swap()); //! ``` +#![feature(test)] #![crate_name = "sysinfo"] #![crate_type = "lib"] #![crate_type = "rlib"] @@ -53,6 +54,7 @@ extern crate cfg_if; #[cfg(not(any(target_os = "unknown", target_arch = "wasm32")))] extern crate libc; extern crate rayon; +extern crate test as bench; #[macro_use] extern crate doc_comment; From c3461af63a8688e07811dd808e295c8b4baecba0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 16 Dec 2019 20:02:39 +0100 Subject: [PATCH 031/171] refresh status for existing processes as well --- src/linux/system.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index fdcda287e..3e93d200f 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -477,6 +477,15 @@ fn _get_process_data( Some(Ok(nb)) if nb != pid => nb, _ => return Err(()), }; + + let get_status = |p: &mut Process, part: &str| { + p.status = part + .chars() + .next() + .and_then(|c| Some(ProcessStatus::from(c))) + .unwrap_or_else(|| ProcessStatus::Unknown(0)); + }; + let mut tmp = PathBuf::from(path); tmp.push("stat"); @@ -502,6 +511,7 @@ fn _get_process_data( let parent_memory = proc_list.memory; let parent_virtual_memory = proc_list.virtual_memory; if let Some(ref mut entry) = proc_list.tasks.get_mut(&nb) { + get_status(entry, parts[2]); update_time_and_memory( path, entry, @@ -532,11 +542,7 @@ fn _get_process_data( .unwrap_or_else(|| 0); let mut p = Process::new(nb, parent_pid, start_time); - p.status = parts[2] - .chars() - .next() - .and_then(|c| Some(ProcessStatus::from(c))) - .unwrap_or(ProcessStatus::Unknown(0)); + get_status(&mut p, parts[2]); tmp.pop(); tmp.push("status"); From 6aa9a51cf206356f5338cd35d21f9218ee2b014a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 16 Dec 2019 21:18:10 +0100 Subject: [PATCH 032/171] more tests --- src/linux/disk.rs | 3 ++- src/linux/process.rs | 3 +++ src/linux/system.rs | 54 ++++++++++++++++++++------------------------ 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/linux/disk.rs b/src/linux/disk.rs index e3795dd67..9df169b16 100644 --- a/src/linux/disk.rs +++ b/src/linux/disk.rs @@ -51,7 +51,8 @@ fn find_type_for_name(name: &OsStr) -> DiskType { .to_owned() .join(trimmed) .join("queue/rotational"); - let rotational_int = get_all_data(path).unwrap_or_default().trim().parse(); + // Normally, this file only contains '0' or '1' but just in case, we get 8 bytes... + let rotational_int = get_all_data(path, 8).unwrap_or_default().trim().parse(); DiskType::from(rotational_int.unwrap_or(-1)) } diff --git a/src/linux/process.rs b/src/linux/process.rs index d57354c0c..202448ac4 100644 --- a/src/linux/process.rs +++ b/src/linux/process.rs @@ -6,6 +6,7 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; +use std::fs::File; use std::path::{Path, PathBuf}; use libc::{c_int, gid_t, kill, uid_t}; @@ -123,6 +124,7 @@ pub struct Process { pub(crate) status: ProcessStatus, /// Tasks run by this process. pub tasks: HashMap, + // pub(crate) stat_file: Option, } impl ProcessExt for Process { @@ -149,6 +151,7 @@ impl ProcessExt for Process { gid: 0, status: ProcessStatus::Unknown(0), tasks: HashMap::new(), + // stat_file: None, } } diff --git a/src/linux/system.rs b/src/linux/system.rs index 3e93d200f..67b78e2d9 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -147,7 +147,7 @@ impl SystemExt for System { fn refresh_memory(&mut self) { self.uptime = get_uptime(); - if let Ok(data) = get_all_data("/proc/meminfo") { + if let Ok(data) = get_all_data("/proc/meminfo", 16_385) { for line in data.split('\n') { let field = match line.split(':').next() { Some("MemTotal") => &mut self.mem_total, @@ -191,6 +191,8 @@ impl SystemExt for System { } fn refresh_process(&mut self, pid: Pid) -> bool { + use std::io::Write; + let mut f= ::std::fs::OpenOptions::new().append(true).create(true).open("/home/imperio/rust/fuck-me").expect("fuck"); self.uptime = get_uptime(); let found = match _get_process_data( &Path::new("/proc/").join(pid.to_string()), @@ -201,20 +203,27 @@ impl SystemExt for System { get_secs_since_epoch(), ) { Ok(Some(p)) => { + write!(f, "1").unwrap(); self.process_list.tasks.insert(p.pid(), p); false } Ok(_) => true, Err(_) => false, }; + write!(f, "2").unwrap(); if found && !self.processors.is_empty() { + write!(f, "3").unwrap(); self.refresh_processors(Some(1)); + write!(f, "4").unwrap(); let (new, old) = get_raw_times(&self.processors[0]); let total_time = (if old > new { 1 } else { new - old }) as f32; let nb_processors = self.processors.len() as u64 - 1; + write!(f, "5").unwrap(); if let Some(p) = self.process_list.tasks.get_mut(&pid) { + write!(f, "6").unwrap(); compute_cpu_usage(p, nb_processors, total_time); + write!(f, "7").unwrap(); } } found @@ -461,8 +470,10 @@ fn _get_uid_and_gid(status_data: String) -> Option<(uid_t, gid_t)> { break } } - assert!(uid.is_some() && gid.is_some()); - Some((uid.unwrap(), gid.unwrap())) + match (uid, gid) { + (Some(u), Some(g)) => Some(u, g), + _ => None, + } } fn _get_process_data( @@ -489,7 +500,7 @@ fn _get_process_data( let mut tmp = PathBuf::from(path); tmp.push("stat"); - let data = get_all_data(&tmp).map_err(|_| ())?; + let data = get_all_data(&tmp, 1024).map_err(|_| ())?; // The stat file is "interesting" to parse, because spaces cannot // be used as delimiters. The second field stores the command name // surrounded by parentheses. Unfortunately, whitespace and @@ -546,7 +557,7 @@ fn _get_process_data( tmp.pop(); tmp.push("status"); - if let Ok(data) = get_all_data(&tmp) { + if let Ok(data) = get_all_data(&tmp, 16_385) { if let Some((uid, gid)) = _get_uid_and_gid(data) { p.uid = uid; p.gid = gid; @@ -615,21 +626,21 @@ fn bench_copy_from_file(b: &mut bench::Bencher) { fn bench_get_all_data(b: &mut bench::Bencher) { extern { fn getpid() -> ::libc::pid_t; } let pid = unsafe { getpid() }; - let x = format!("/proc/{}/status", pid); + let x = format!("/proc/{}/stat", pid); let path = Path::new(&x); b.iter(move || { - get_all_data(path); + get_all_data(path, 1024); }); } #[bench] fn bench_read_file(b: &mut bench::Bencher) { extern { fn getpid() -> ::libc::pid_t; } let pid = unsafe { getpid() }; - let x = format!("/proc/{}/status", pid); + let x = format!("/proc/{}/stat", pid); let path = Path::new(&x); b.iter(move || { if let Ok(mut file) = File::open(path) { - let mut data = vec![0; 16_385]; + let mut data = Vec::with_capacity(1024); file.read(&mut data); } }); @@ -648,22 +659,6 @@ fn bench_read_file_no_reopen(b: &mut bench::Bencher) { file.read(&mut data); }); } -#[bench] -fn bench_read_file_seek(b: &mut bench::Bencher) { - use std::io::Seek; - extern { fn getpid() -> ::libc::pid_t; } - let pid = unsafe { getpid() }; - let x = format!("/proc/{}/status", pid); - let path = Path::new(&x); - b.iter(move || { - if let Ok(mut file) = File::open(path) { - let pos = file.seek(::std::io::SeekFrom::End(0)).expect("seek end"); - file.seek(::std::io::SeekFrom::Start(0)).expect("seek begin"); - let mut data = Vec::with_capacity(pos as _); - file.read_exact(&mut data); - } - }); -} fn copy_from_file(entry: &Path) -> Vec { match File::open(entry.to_str().unwrap_or("/")) { @@ -698,10 +693,11 @@ fn copy_from_file(entry: &Path) -> Vec { } } -pub fn get_all_data>(file_path: P) -> io::Result { +pub fn get_all_data>(file_path: P, size: usize) -> io::Result { use std::error::Error; let mut file = File::open(file_path.as_ref())?; - let mut data = vec![0; 16_385]; + let mut data = Vec::with_capacity(size); + //unsafe { data.set_len(size); } let size = file.read(&mut data)?; data.truncate(size); @@ -710,7 +706,7 @@ pub fn get_all_data>(file_path: P) -> io::Result { } fn get_all_disks() -> Vec { - let content = get_all_data("/proc/mounts").unwrap_or_default(); + let content = get_all_data("/proc/mounts", 16_385).unwrap_or_default(); let disks = content.lines().filter(|line| { let line = line.trim_start(); // While the `sd` prefix is most common, some disks instead use the `nvme` prefix. This @@ -744,7 +740,7 @@ fn get_all_disks() -> Vec { } fn get_uptime() -> u64 { - let content = get_all_data("/proc/uptime").unwrap_or_default(); + let content = get_all_data("/proc/uptime", 50).unwrap_or_default(); u64::from_str_radix(content.split('.').next().unwrap_or_else(|| "0"), 10).unwrap_or_else(|_| 0) } From c847d83305f38b392fc8e637e0d8163165179dc6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 16 Dec 2019 23:18:30 +0100 Subject: [PATCH 033/171] Keep stat File open and fix environment variables get --- src/linux/process.rs | 5 +- src/linux/system.rs | 143 +++++++++++++++++-------------------------- 2 files changed, 57 insertions(+), 91 deletions(-) diff --git a/src/linux/process.rs b/src/linux/process.rs index 202448ac4..390ef45ac 100644 --- a/src/linux/process.rs +++ b/src/linux/process.rs @@ -98,7 +98,6 @@ impl fmt::Display for ProcessStatus { } /// Struct containing a process' information. -#[derive(Clone)] pub struct Process { pub(crate) name: String, pub(crate) cmd: Vec, @@ -124,7 +123,7 @@ pub struct Process { pub(crate) status: ProcessStatus, /// Tasks run by this process. pub tasks: HashMap, - // pub(crate) stat_file: Option, + pub(crate) stat_file: Option, } impl ProcessExt for Process { @@ -151,7 +150,7 @@ impl ProcessExt for Process { gid: 0, status: ProcessStatus::Unknown(0), tasks: HashMap::new(), - // stat_file: None, + stat_file: None, } } diff --git a/src/linux/system.rs b/src/linux/system.rs index 67b78e2d9..7f24c05b7 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -17,6 +17,7 @@ use {DiskExt, ProcessExt, RefreshKind, SystemExt}; use libc::{sysconf, gid_t, uid_t, _SC_CLK_TCK, _SC_PAGESIZE}; use std::cell::UnsafeCell; use std::collections::HashMap; +use std::error::Error; use std::fs::{self, read_link, File}; use std::io::{self, BufRead, BufReader, Read}; use std::path::{Path, PathBuf}; @@ -191,8 +192,6 @@ impl SystemExt for System { } fn refresh_process(&mut self, pid: Pid) -> bool { - use std::io::Write; - let mut f= ::std::fs::OpenOptions::new().append(true).create(true).open("/home/imperio/rust/fuck-me").expect("fuck"); self.uptime = get_uptime(); let found = match _get_process_data( &Path::new("/proc/").join(pid.to_string()), @@ -203,27 +202,20 @@ impl SystemExt for System { get_secs_since_epoch(), ) { Ok(Some(p)) => { - write!(f, "1").unwrap(); self.process_list.tasks.insert(p.pid(), p); false } Ok(_) => true, Err(_) => false, }; - write!(f, "2").unwrap(); if found && !self.processors.is_empty() { - write!(f, "3").unwrap(); self.refresh_processors(Some(1)); - write!(f, "4").unwrap(); let (new, old) = get_raw_times(&self.processors[0]); let total_time = (if old > new { 1 } else { new - old }) as f32; let nb_processors = self.processors.len() as u64 - 1; - write!(f, "5").unwrap(); if let Some(p) = self.process_list.tasks.get_mut(&pid) { - write!(f, "6").unwrap(); compute_cpu_usage(p, nb_processors, total_time); - write!(f, "7").unwrap(); } } found @@ -471,11 +463,33 @@ fn _get_uid_and_gid(status_data: String) -> Option<(uid_t, gid_t)> { } } match (uid, gid) { - (Some(u), Some(g)) => Some(u, g), + (Some(u), Some(g)) => Some((u, g)), _ => None, } } +fn parse_stat_file(data: &str) -> Result, ()> { + // The stat file is "interesting" to parse, because spaces cannot + // be used as delimiters. The second field stores the command name + // surrounded by parentheses. Unfortunately, whitespace and + // parentheses are legal parts of the command, so parsing has to + // proceed like this: The first field is delimited by the first + // whitespace, the second field is everything until the last ')' + // in the entire string. All other fields are delimited by + // whitespace. + + let mut parts = Vec::with_capacity(52); + let mut data_it = data.splitn(2, ' '); + parts.push(unwrap_or_return!(data_it.next())); + // The following loses the ) from the input, but that's ok because + // we're not using it anyway. + let mut data_it = unwrap_or_return!(data_it.next()).rsplitn(2, ')'); + let data = unwrap_or_return!(data_it.next()); + parts.push(unwrap_or_return!(data_it.next())); + parts.extend(data.split_whitespace()); + Ok(parts) +} + fn _get_process_data( path: &Path, proc_list: &mut Process, @@ -496,32 +510,20 @@ fn _get_process_data( .and_then(|c| Some(ProcessStatus::from(c))) .unwrap_or_else(|| ProcessStatus::Unknown(0)); }; - - let mut tmp = PathBuf::from(path); - - tmp.push("stat"); - let data = get_all_data(&tmp, 1024).map_err(|_| ())?; - // The stat file is "interesting" to parse, because spaces cannot - // be used as delimiters. The second field stores the command name - // surrounded by parentheses. Unfortunately, whitespace and - // parentheses are legal parts of the command, so parsing has to - // proceed like this: The first field is delimited by the first - // whitespace, the second field is everything until the last ')' - // in the entire string. All other fields are delimited by - // whitespace. - - let mut parts = Vec::with_capacity(20); - let mut data_it = data.splitn(2, ' '); - parts.push(unwrap_or_return!(data_it.next())); - // The following loses the ) from the input, but that's ok because - // we're not using it anyway. - let mut data_it = unwrap_or_return!(data_it.next()).rsplitn(2, ')'); - let data = unwrap_or_return!(data_it.next()); - parts.push(unwrap_or_return!(data_it.next())); - parts.extend(data.split_whitespace()); let parent_memory = proc_list.memory; let parent_virtual_memory = proc_list.virtual_memory; if let Some(ref mut entry) = proc_list.tasks.get_mut(&nb) { + let data = if let Some(ref mut f) = entry.stat_file { + get_all_data_from_file(f, 1024).map_err(|_| ())? + } else { + let mut tmp = PathBuf::from(path); + tmp.push("stat"); + let mut file = ::std::fs::File::open(tmp).map_err(|_| ())?; + let data = get_all_data_from_file(&mut file, 1024).map_err(|_| ())?; + entry.stat_file = Some(file); + data + }; + let parts = parse_stat_file(&data)?; get_status(entry, parts[2]); update_time_and_memory( path, @@ -537,6 +539,13 @@ fn _get_process_data( return Ok(None); } + let mut tmp = PathBuf::from(path); + + tmp.push("stat"); + let mut file = ::std::fs::File::open(&tmp).map_err(|_| ())?; + let data = get_all_data_from_file(&mut file, 1024).map_err(|_| ())?; + let parts = parse_stat_file(&data)?; + let parent_pid = if proc_list.pid != 0 { Some(proc_list.pid) } else { @@ -553,6 +562,7 @@ fn _get_process_data( .unwrap_or_else(|| 0); let mut p = Process::new(nb, parent_pid, start_time); + p.stat_file = Some(file); get_status(&mut p, parts[2]); tmp.pop(); @@ -587,8 +597,7 @@ fn _get_process_data( p.environ = copy_from_file(&tmp); tmp.pop(); tmp.push("exe"); - p.exe = read_link(tmp.to_str().unwrap_or_else(|| "")) - .unwrap_or_else(|_| PathBuf::new()); + p.exe = read_link(tmp.to_str().unwrap_or_else(|| "")).unwrap_or_else(|_| PathBuf::new()); tmp.pop(); tmp.push("cwd"); @@ -612,54 +621,6 @@ fn _get_process_data( Ok(Some(p)) } -#[bench] -fn bench_copy_from_file(b: &mut bench::Bencher) { - extern { fn getpid() -> ::libc::pid_t; } - let pid = unsafe { getpid() }; - let x = format!("/proc/{}/environ", pid); - let path = Path::new(&x); - b.iter(move || { - copy_from_file(path); - }); -} -#[bench] -fn bench_get_all_data(b: &mut bench::Bencher) { - extern { fn getpid() -> ::libc::pid_t; } - let pid = unsafe { getpid() }; - let x = format!("/proc/{}/stat", pid); - let path = Path::new(&x); - b.iter(move || { - get_all_data(path, 1024); - }); -} -#[bench] -fn bench_read_file(b: &mut bench::Bencher) { - extern { fn getpid() -> ::libc::pid_t; } - let pid = unsafe { getpid() }; - let x = format!("/proc/{}/stat", pid); - let path = Path::new(&x); - b.iter(move || { - if let Ok(mut file) = File::open(path) { - let mut data = Vec::with_capacity(1024); - file.read(&mut data); - } - }); -} -#[bench] -fn bench_read_file_no_reopen(b: &mut bench::Bencher) { - use std::io::Seek; - extern { fn getpid() -> ::libc::pid_t; } - let pid = unsafe { getpid() }; - let x = format!("/proc/{}/status", pid); - let path = Path::new(&x); - let mut file = File::open(path).expect("file"); - b.iter(move || { - file.seek(::std::io::SeekFrom::Start(0)).expect("seek begin"); - let mut data = vec![0; 16_385]; - file.read(&mut data); - }); -} - fn copy_from_file(entry: &Path) -> Vec { match File::open(entry.to_str().unwrap_or("/")) { Ok(mut f) => { @@ -677,7 +638,7 @@ fn copy_from_file(entry: &Path) -> Vec { out.push(s); } } - start = pos; + start = pos + 1; // to keeping prevent '\0' } } out @@ -693,18 +654,24 @@ fn copy_from_file(entry: &Path) -> Vec { } } -pub fn get_all_data>(file_path: P, size: usize) -> io::Result { - use std::error::Error; - let mut file = File::open(file_path.as_ref())?; +fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result { + use std::io::Seek; + let mut data = Vec::with_capacity(size); - //unsafe { data.set_len(size); } + unsafe { data.set_len(size); } + file.seek(::std::io::SeekFrom::Start(0))?; let size = file.read(&mut data)?; data.truncate(size); Ok(String::from_utf8(data) .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.description()))?) } +pub fn get_all_data>(file_path: P, size: usize) -> io::Result { + let mut file = File::open(file_path.as_ref())?; + get_all_data_from_file(&mut file, size) +} + fn get_all_disks() -> Vec { let content = get_all_data("/proc/mounts", 16_385).unwrap_or_default(); let disks = content.lines().filter(|line| { From f6c775eabda26290336cd220c53d0190e4337c9e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 16 Dec 2019 23:19:25 +0100 Subject: [PATCH 034/171] remove commented code --- src/linux/system.rs | 4 ---- src/sysinfo.rs | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index 7f24c05b7..c7af4dc16 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -642,10 +642,6 @@ fn copy_from_file(entry: &Path) -> Vec { } } out - /*data.split(|x| *x == b'\0') - .filter_map(|x| ::std::str::from_utf8(x).map(|x| x.trim().to_owned()).ok()) - .filter(|x| !x.is_empty()) - .collect()*/ } else { Vec::new() } diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 390cea2fb..998909275 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -41,7 +41,6 @@ //! println!("used swap : {} kB", system.get_used_swap()); //! ``` -#![feature(test)] #![crate_name = "sysinfo"] #![crate_type = "lib"] #![crate_type = "rlib"] @@ -54,7 +53,6 @@ extern crate cfg_if; #[cfg(not(any(target_os = "unknown", target_arch = "wasm32")))] extern crate libc; extern crate rayon; -extern crate test as bench; #[macro_use] extern crate doc_comment; From f6750c417c67c03bdf5f690de2bb6ffe425b81b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 16 Dec 2019 23:23:35 +0100 Subject: [PATCH 035/171] Update benches --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 51d6d2a1f..78e82e4a4 100644 --- a/README.md +++ b/README.md @@ -95,17 +95,17 @@ Here are the current results:
```text -test bench_new ... bench: 12,950,615 ns/iter (+/- 1,054,683) -test bench_refresh_all ... bench: 5,412,422 ns/iter (+/- 1,839,554) -test bench_refresh_cpu ... bench: 12,967 ns/iter (+/- 618) -test bench_refresh_disk_lists ... bench: 50,005 ns/iter (+/- 7,639) -test bench_refresh_disks ... bench: 2,314 ns/iter (+/- 45) -test bench_refresh_memory ... bench: 11,037 ns/iter (+/- 1,172) -test bench_refresh_network ... bench: 53,703 ns/iter (+/- 1,396) -test bench_refresh_process ... bench: 43,730 ns/iter (+/- 3,936) -test bench_refresh_processes ... bench: 4,673,568 ns/iter (+/- 494,504) -test bench_refresh_system ... bench: 48,861 ns/iter (+/- 3,433) -test bench_refresh_temperatures ... bench: 23,046 ns/iter (+/- 2,131) +test bench_new ... bench: 12,610,204 ns/iter (+/- 453,957) +test bench_refresh_all ... bench: 3,339,360 ns/iter (+/- 400,590) +test bench_refresh_cpu ... bench: 12,785 ns/iter (+/- 603) +test bench_refresh_disk_lists ... bench: 49,465 ns/iter (+/- 3,516) +test bench_refresh_disks ... bench: 2,288 ns/iter (+/- 21) +test bench_refresh_memory ... bench: 11,252 ns/iter (+/- 801) +test bench_refresh_network ... bench: 21,960 ns/iter (+/- 3,423) +test bench_refresh_process ... bench: 20,526 ns/iter (+/- 703) +test bench_refresh_processes ... bench: 3,069,889 ns/iter (+/- 324,993) +test bench_refresh_system ... bench: 48,788 ns/iter (+/- 1,500) +test bench_refresh_temperatures ... bench: 23,076 ns/iter (+/- 1,371) ```
From 612729eae60f2027dc08020875625ee23fce253a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 16 Dec 2019 23:31:43 +0100 Subject: [PATCH 036/171] Update crate version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 919af423e..ed6a8decc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sysinfo" -version = "0.10.2" +version = "0.10.3" authors = ["Guillaume Gomez "] description = "Library to handle processes" From c8f0440d298f9fec2fe9032c4571fa5e1047d5c8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Jan 2020 17:52:25 +0100 Subject: [PATCH 037/171] Limit potential number of open files at the same time --- Cargo.toml | 3 ++ src/linux/process.rs | 10 +++++ src/linux/system.rs | 53 +++++++++++++++++++++++--- src/windows/component.rs | 80 ++++++++++++++++++++++++---------------- 4 files changed, 108 insertions(+), 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed6a8decc..9bb39fc61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,9 @@ ntapi = "0.3" [target.'cfg(not(any(target_os = "unknown", target_arch = "wasm32")))'.dependencies] libc = "0.2" +[target.'cfg(unix)'.dependencies] +once_cell = "1.0" + [lib] name = "sysinfo" crate_type = ["rlib", "cdylib"] diff --git a/src/linux/process.rs b/src/linux/process.rs index 390ef45ac..c9f8ab4d3 100644 --- a/src/linux/process.rs +++ b/src/linux/process.rs @@ -213,6 +213,16 @@ impl ProcessExt for Process { } } +impl Drop for Process { + fn drop(&mut self) { + if self.stat_file.is_some() { + if let Ok(ref mut x) = unsafe { ::linux::system::REMAINING_FILES.lock() } { + **x += 1; + } + } + } +} + #[allow(unused_must_use)] impl Debug for Process { fn fmt(&self, f: &mut Formatter) -> fmt::Result { diff --git a/src/linux/system.rs b/src/linux/system.rs index c7af4dc16..3cad8436c 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -14,7 +14,7 @@ use sys::NetworkData; use Pid; use {DiskExt, ProcessExt, RefreshKind, SystemExt}; -use libc::{sysconf, gid_t, uid_t, _SC_CLK_TCK, _SC_PAGESIZE}; +use libc::{self, gid_t, sysconf, uid_t, _SC_CLK_TCK, _SC_PAGESIZE}; use std::cell::UnsafeCell; use std::collections::HashMap; use std::error::Error; @@ -22,12 +22,39 @@ use std::fs::{self, read_link, File}; use std::io::{self, BufRead, BufReader, Read}; use std::path::{Path, PathBuf}; use std::str::FromStr; +use std::sync::{Arc, Mutex}; use std::time::SystemTime; use utils::realpath; use rayon::prelude::*; +// This whole thing is to prevent having too much files open at once. It could be problematic +// for processes using a lot of files and using sysinfo at the same time. +pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy>> = + once_cell::sync::Lazy::new(|| unsafe { + let mut limits = libc::rlimit { + rlim_cur: 0, + rlim_max: 0, + }; + if libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) != 0 { + // Most linux system now defaults to 1024. + return Arc::new(Mutex::new(1024 - 1024 / 10)); + } + // We save the value in case the update fails. + let current = limits.rlim_cur; + + // The set the soft limit to the hard one. + limits.rlim_cur = limits.rlim_max; + // In this part, we leave minimum 10% of the available file descriptors to the process + // using sysinfo. + Arc::new(Mutex::new(if libc::setrlimit(libc::RLIMIT_NOFILE, &limits) == 0 { + limits.rlim_cur - limits.rlim_cur / 10 + } else { + current - current / 10 + } as _)) + }); + macro_rules! to_str { ($e:expr) => { unsafe { ::std::str::from_utf8_unchecked($e) } @@ -456,10 +483,10 @@ fn _get_uid_and_gid(status_data: String) -> Option<(uid_t, gid_t)> { assert!(gid.is_none()); gid = Some(g); } else { - continue + continue; } if uid.is_some() && gid.is_some() { - break + break; } } match (uid, gid) { @@ -490,6 +517,17 @@ fn parse_stat_file(data: &str) -> Result, ()> { Ok(parts) } +fn check_nb_open_files(f: File) -> Option { + if let Ok(ref mut x) = unsafe { REMAINING_FILES.lock() } { + if **x > 0 { + **x += 1; + return Some(f); + } + } + // Something bad happened... + return None; +} + fn _get_process_data( path: &Path, proc_list: &mut Process, @@ -520,7 +558,7 @@ fn _get_process_data( tmp.push("stat"); let mut file = ::std::fs::File::open(tmp).map_err(|_| ())?; let data = get_all_data_from_file(&mut file, 1024).map_err(|_| ())?; - entry.stat_file = Some(file); + entry.stat_file = check_nb_open_files(file); data }; let parts = parse_stat_file(&data)?; @@ -634,7 +672,8 @@ fn copy_from_file(entry: &Path) -> Vec { if *x == 0 { if pos - start > 1 { if let Ok(s) = ::std::str::from_utf8(&data[start..pos]) - .map(|x| x.trim().to_owned()) { + .map(|x| x.trim().to_owned()) + { out.push(s); } } @@ -654,7 +693,9 @@ fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result { use std::io::Seek; let mut data = Vec::with_capacity(size); - unsafe { data.set_len(size); } + unsafe { + data.set_len(size); + } file.seek(::std::io::SeekFrom::Start(0))?; let size = file.read(&mut data)?; diff --git a/src/windows/component.rs b/src/windows/component.rs index 8d0efd630..b9d2c5dca 100644 --- a/src/windows/component.rs +++ b/src/windows/component.rs @@ -7,21 +7,21 @@ use std::ptr::null_mut; use winapi::shared::rpcdce::{ - RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, - RPC_C_AUTHN_LEVEL_CALL, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + RPC_C_IMP_LEVEL_IMPERSONATE, }; use winapi::shared::winerror::{FAILED, SUCCEEDED}; use winapi::shared::wtypesbase::CLSCTX_INPROC_SERVER; use winapi::um::combaseapi::{ - CoCreateInstance, CoInitializeEx, CoUninitialize, CoInitializeSecurity, CoSetProxyBlanket, + CoCreateInstance, CoInitializeEx, CoInitializeSecurity, CoSetProxyBlanket, CoUninitialize, }; +use winapi::um::oaidl::VARIANT; use winapi::um::objidl::EOAC_NONE; use winapi::um::oleauto::{SysAllocString, SysFreeString, VariantClear}; use winapi::um::wbemcli::{ CLSID_WbemLocator, IEnumWbemClassObject, IID_IWbemLocator, IWbemClassObject, IWbemLocator, - IWbemServices, WBEM_FLAG_NONSYSTEM_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_FLAG_FORWARD_ONLY, + IWbemServices, WBEM_FLAG_FORWARD_ONLY, WBEM_FLAG_NONSYSTEM_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, }; -use winapi::um::oaidl::VARIANT; use ComponentExt; @@ -45,15 +45,16 @@ impl Component { .and_then(|x| x.create_instance()) .and_then(|x| x.connect_server()) .and_then(|x| x.set_proxy_blanket()) - .and_then(|x| x.exec_query()) { + .and_then(|x| x.exec_query()) + { Some(mut c) => match c.get_temperature(true) { Some((temperature, critical)) => Some(Component { - temperature, - label: "Computer".to_owned(), - max: temperature, - critical, - connection: Some(c), - }), + temperature, + label: "Computer".to_owned(), + max: temperature, + critical, + connection: Some(c), + }), None => None, }, None => None, @@ -114,7 +115,9 @@ struct Instance(*mut IWbemLocator); impl Drop for Instance { fn drop(&mut self) { if !self.0.is_null() { - unsafe { (*self.0).Release(); } + unsafe { + (*self.0).Release(); + } } } } @@ -124,7 +127,9 @@ struct ServerConnection(*mut IWbemServices); impl Drop for ServerConnection { fn drop(&mut self) { if !self.0.is_null() { - unsafe { (*self.0).Release(); } + unsafe { + (*self.0).Release(); + } } } } @@ -134,7 +139,9 @@ struct Enumerator(*mut IEnumWbemClassObject); impl Drop for Enumerator { fn drop(&mut self) { if !self.0.is_null() { - unsafe { (*self.0).Release(); } + unsafe { + (*self.0).Release(); + } } } } @@ -157,7 +164,7 @@ impl Connection { // "Funnily", this function returns ok, false or "this function has already been called". // So whatever, let's just ignore whatever it might return then! unsafe { CoInitializeEx(null_mut(), 0) }; - Some(Connection { + Some(Connection { instance: None, server_connection: None, enumerator: None, @@ -236,14 +243,14 @@ impl Connection { if let Some(ref server_connection) = self.server_connection { unsafe { if FAILED(CoSetProxyBlanket( - server_connection.0 as *mut _, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - null_mut(), - RPC_C_AUTHN_LEVEL_CALL, - RPC_C_IMP_LEVEL_IMPERSONATE, - null_mut(), - EOAC_NONE, + server_connection.0 as *mut _, + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + null_mut(), + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, + null_mut(), + EOAC_NONE, )) { return None; } @@ -261,11 +268,12 @@ impl Connection { unsafe { // "WQL" let s = bstr!('W', 'Q', 'L'); // query kind - // "SELECT * FROM MSAcpi_ThermalZoneTemperature" - let query = bstr!('S','E','L','E','C','T',' ', - '*',' ', - 'F','R','O','M',' ', - 'M','S','A','c','p','i','_','T','h','e','r','m','a','l','Z','o','n','e','T','e','m','p','e','r','a','t','u','r','e'); + // "SELECT * FROM MSAcpi_ThermalZoneTemperature" + let query = bstr!( + 'S', 'E', 'L', 'E', 'C', 'T', ' ', '*', ' ', 'F', 'R', 'O', 'M', ' ', 'M', 'S', + 'A', 'c', 'p', 'i', '_', 'T', 'h', 'e', 'r', 'm', 'a', 'l', 'Z', 'o', 'n', 'e', + 'T', 'e', 'm', 'p', 'e', 'r', 'a', 't', 'u', 'r', 'e' + ); let hres = (*server_connection.0).ExecQuery( s, query, @@ -315,7 +323,10 @@ impl Connection { let mut p_val: VARIANT = ::std::mem::MaybeUninit::uninit().assume_init(); // "CurrentTemperature" - let temp = bstr!('C','u','r','r','e','n','t','T','e','m','p','e','r','a','t','u','r','e'); + let temp = bstr!( + 'C', 'u', 'r', 'r', 'e', 'n', 't', 'T', 'e', 'm', 'p', 'e', 'r', 'a', 't', 'u', + 'r', 'e' + ); let res = (*p_obj).Get(temp, 0, &mut p_val, null_mut(), null_mut()); SysFreeString(temp); @@ -332,7 +343,10 @@ impl Connection { let mut critical = None; if get_critical { // "CriticalPoint" - let crit = bstr!('C','r','i','t','i','c','a','l','T','r','i','p','P','o','i','n','t'); + let crit = bstr!( + 'C', 'r', 'i', 't', 'i', 'c', 'a', 'l', 'T', 'r', 'i', 'p', 'P', 'o', 'i', 'n', + 't' + ); let res = (*p_obj).Get(crit, 0, &mut p_val, null_mut(), null_mut()); SysFreeString(crit); @@ -355,6 +369,8 @@ impl Drop for Connection { self.enumerator.take(); self.server_connection.take(); self.instance.take(); - unsafe { CoUninitialize(); } + unsafe { + CoUninitialize(); + } } } From 137ea0d7c66df61f9efdf42fb789ecceb35a64e3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Jan 2020 18:07:10 +0100 Subject: [PATCH 038/171] Replace Vec::new and HashMap::new calls with with_capacity when possible --- src/linux/component.rs | 16 +++++++++------- src/linux/process.rs | 8 ++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/linux/component.rs b/src/linux/component.rs index f23b738bb..ce2b51701 100644 --- a/src/linux/component.rs +++ b/src/linux/component.rs @@ -44,7 +44,7 @@ fn is_file>(path: T) -> bool { } fn append_files(components: &mut Vec, folder: &Path) { - let mut matchings: HashMap> = HashMap::new(); + let mut matchings: HashMap> = HashMap::with_capacity(10); if let Ok(dir) = read_dir(folder) { for entry in dir { @@ -177,9 +177,9 @@ impl ComponentExt for Component { } pub fn get_components() -> Vec { - let mut components = Vec::new(); - if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) { + let mut components = Vec::with_capacity(10); + for entry in dir { if let Ok(entry) = entry { let entry = entry.path(); @@ -196,15 +196,17 @@ pub fn get_components() -> Vec { append_files(&mut components, &entry); } } + components.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase())); + components } else if is_file("/sys/class/thermal/thermal_zone0/temp") { // Specfic to raspberry pi. - components.push(Component::new( + vec![Component::new( "CPU".to_owned(), Path::new("/sys/class/thermal/thermal_zone0/temp"), None, None, - )); + )] + } else { + Vec::new() } - components.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase())); - components } diff --git a/src/linux/process.rs b/src/linux/process.rs index c9f8ab4d3..4ef0f82d5 100644 --- a/src/linux/process.rs +++ b/src/linux/process.rs @@ -129,11 +129,11 @@ pub struct Process { impl ProcessExt for Process { fn new(pid: Pid, parent: Option, start_time: u64) -> Process { Process { - name: String::new(), + name: String::with_capacity(20), pid, parent, - cmd: Vec::new(), - environ: Vec::new(), + cmd: Vec::with_capacity(2), + environ: Vec::with_capacity(10), exe: PathBuf::new(), cwd: PathBuf::new(), root: PathBuf::new(), @@ -149,7 +149,7 @@ impl ProcessExt for Process { uid: 0, gid: 0, status: ProcessStatus::Unknown(0), - tasks: HashMap::new(), + tasks: if pid == 0 { HashMap::with_capacity(1000) } else { HashMap::new() }, stat_file: None, } } From b0272a1c96e00d31ac6386ec1a1a20bc6d5c723e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Jan 2020 18:07:22 +0100 Subject: [PATCH 039/171] Update linux benchmark results --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 78e82e4a4..7a9b976f3 100644 --- a/README.md +++ b/README.md @@ -95,17 +95,17 @@ Here are the current results:
```text -test bench_new ... bench: 12,610,204 ns/iter (+/- 453,957) -test bench_refresh_all ... bench: 3,339,360 ns/iter (+/- 400,590) -test bench_refresh_cpu ... bench: 12,785 ns/iter (+/- 603) -test bench_refresh_disk_lists ... bench: 49,465 ns/iter (+/- 3,516) -test bench_refresh_disks ... bench: 2,288 ns/iter (+/- 21) -test bench_refresh_memory ... bench: 11,252 ns/iter (+/- 801) -test bench_refresh_network ... bench: 21,960 ns/iter (+/- 3,423) -test bench_refresh_process ... bench: 20,526 ns/iter (+/- 703) -test bench_refresh_processes ... bench: 3,069,889 ns/iter (+/- 324,993) -test bench_refresh_system ... bench: 48,788 ns/iter (+/- 1,500) -test bench_refresh_temperatures ... bench: 23,076 ns/iter (+/- 1,371) +test bench_new ... bench: 10,437,759 ns/iter (+/- 531,424) +test bench_refresh_all ... bench: 2,658,946 ns/iter (+/- 189,612) +test bench_refresh_cpu ... bench: 13,429 ns/iter (+/- 537) +test bench_refresh_disk_lists ... bench: 50,688 ns/iter (+/- 8,032) +test bench_refresh_disks ... bench: 2,582 ns/iter (+/- 226) +test bench_refresh_memory ... bench: 12,015 ns/iter (+/- 537) +test bench_refresh_network ... bench: 23,661 ns/iter (+/- 617) +test bench_refresh_process ... bench: 56,157 ns/iter (+/- 2,445) +test bench_refresh_processes ... bench: 2,486,534 ns/iter (+/- 121,187) +test bench_refresh_system ... bench: 53,739 ns/iter (+/- 6,793) +test bench_refresh_temperatures ... bench: 25,770 ns/iter (+/- 1,164) ```
From ca15f6c3f41927cb1e0a36be2f2f469daf8d1a5f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Jan 2020 18:59:01 +0100 Subject: [PATCH 040/171] Handle Android separately for REMANING_FILES initialization --- src/linux/system.rs | 49 +++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index 3cad8436c..4c30d2e6b 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -32,27 +32,36 @@ use rayon::prelude::*; // This whole thing is to prevent having too much files open at once. It could be problematic // for processes using a lot of files and using sysinfo at the same time. pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy>> = - once_cell::sync::Lazy::new(|| unsafe { - let mut limits = libc::rlimit { - rlim_cur: 0, - rlim_max: 0, - }; - if libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) != 0 { - // Most linux system now defaults to 1024. - return Arc::new(Mutex::new(1024 - 1024 / 10)); + once_cell::sync::Lazy::new(|| { + #[cfg(target_os = "android")] + { + // The constant "RLIMIT_NOFILE" doesn't exist on Android so we have to return a value. + // The default value seems to be 1024 so let's return 90% of it... + Arc::new(Mutex::new(1024 - 1024 / 10)) + } + #[cfg(not(target_os = "android"))] + unsafe { + let mut limits = libc::rlimit { + rlim_cur: 0, + rlim_max: 0, + }; + if libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) != 0 { + // Most linux system now defaults to 1024. + return Arc::new(Mutex::new(1024 - 1024 / 10)); + } + // We save the value in case the update fails. + let current = limits.rlim_cur; + + // The set the soft limit to the hard one. + limits.rlim_cur = limits.rlim_max; + // In this part, we leave minimum 10% of the available file descriptors to the process + // using sysinfo. + Arc::new(Mutex::new(if libc::setrlimit(libc::RLIMIT_NOFILE, &limits) == 0 { + limits.rlim_cur - limits.rlim_cur / 10 + } else { + current - current / 10 + } as _)) } - // We save the value in case the update fails. - let current = limits.rlim_cur; - - // The set the soft limit to the hard one. - limits.rlim_cur = limits.rlim_max; - // In this part, we leave minimum 10% of the available file descriptors to the process - // using sysinfo. - Arc::new(Mutex::new(if libc::setrlimit(libc::RLIMIT_NOFILE, &limits) == 0 { - limits.rlim_cur - limits.rlim_cur / 10 - } else { - current - current / 10 - } as _)) }); macro_rules! to_str { From cf1c188b44fa975dad369f91f01e58ac9c5e788b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Jan 2020 19:03:43 +0100 Subject: [PATCH 041/171] Add Android to the list of supported platforms --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7a9b976f3..662c34650 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Support the following platforms: * Linux * Raspberry + * Android * Mac OSX * Windows From 041d57df202b7708c9ea90c54e4d75562fd9136f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Jan 2020 22:47:15 +0100 Subject: [PATCH 042/171] Only add once_cell dependency for linux --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9bb39fc61..886563236 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ ntapi = "0.3" [target.'cfg(not(any(target_os = "unknown", target_arch = "wasm32")))'.dependencies] libc = "0.2" -[target.'cfg(unix)'.dependencies] +[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies] once_cell = "1.0" [lib] From a1805b144197fddb7021db5c4c59c14e162c5a94 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Jan 2020 14:31:41 +0100 Subject: [PATCH 043/171] Code cleanup and great performance improvement on refresh_disk_list --- src/linux/process.rs | 6 +- src/linux/system.rs | 12 +- src/mac/process.rs | 70 +++++++++ src/mac/system.rs | 352 +++++++++++++++++++++++++------------------ 4 files changed, 285 insertions(+), 155 deletions(-) diff --git a/src/linux/process.rs b/src/linux/process.rs index 4ef0f82d5..e61b35082 100644 --- a/src/linux/process.rs +++ b/src/linux/process.rs @@ -149,7 +149,11 @@ impl ProcessExt for Process { uid: 0, gid: 0, status: ProcessStatus::Unknown(0), - tasks: if pid == 0 { HashMap::with_capacity(1000) } else { HashMap::new() }, + tasks: if pid == 0 { + HashMap::with_capacity(1000) + } else { + HashMap::new() + }, stat_file: None, } } diff --git a/src/linux/system.rs b/src/linux/system.rs index 4c30d2e6b..ce21a58bd 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -56,11 +56,13 @@ pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy>> limits.rlim_cur = limits.rlim_max; // In this part, we leave minimum 10% of the available file descriptors to the process // using sysinfo. - Arc::new(Mutex::new(if libc::setrlimit(libc::RLIMIT_NOFILE, &limits) == 0 { - limits.rlim_cur - limits.rlim_cur / 10 - } else { - current - current / 10 - } as _)) + Arc::new(Mutex::new( + if libc::setrlimit(libc::RLIMIT_NOFILE, &limits) == 0 { + limits.rlim_cur - limits.rlim_cur / 10 + } else { + current - current / 10 + } as _, + )) } }); diff --git a/src/mac/process.rs b/src/mac/process.rs index ae587306f..a8271c684 100644 --- a/src/mac/process.rs +++ b/src/mac/process.rs @@ -144,6 +144,76 @@ pub struct Process { pub status: Option, } +impl Process { + pub(crate) fn new_with( + pid: Pid, + parent: Option, + start_time: u64, + exe: PathBuf, + name: String, + cmd: Vec, + ) -> Process { + Process { + name, + pid, + parent, + cmd, + environ: Vec::new(), + exe, + cwd: PathBuf::new(), + root: PathBuf::new(), + memory: 0, + virtual_memory: 0, + cpu_usage: 0., + utime: 0, + stime: 0, + old_utime: 0, + old_stime: 0, + updated: true, + start_time, + uid: 0, + gid: 0, + process_status: ProcessStatus::Unknown(0), + status: None, + } + } + + pub(crate) fn new_with2( + pid: Pid, + parent: Option, + start_time: u64, + exe: PathBuf, + name: String, + cmd: Vec, + environ: Vec, + root: PathBuf, + ) -> Process { + Process { + name, + pid, + parent, + cmd, + environ, + exe, + cwd: PathBuf::new(), + root, + memory: 0, + virtual_memory: 0, + cpu_usage: 0., + utime: 0, + stime: 0, + old_utime: 0, + old_stime: 0, + updated: true, + start_time, + uid: 0, + gid: 0, + process_status: ProcessStatus::Unknown(0), + status: None, + } + } +} + impl ProcessExt for Process { fn new(pid: Pid, parent: Option, start_time: u64) -> Process { Process { diff --git a/src/mac/system.rs b/src/mac/system.rs index 80071bce0..76d611db7 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -14,7 +14,7 @@ use sys::processor::*; use {ComponentExt, DiskExt, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; use std::borrow::Borrow; -use std::cell::UnsafeCell; +use std::cell::{UnsafeCell, RefCell}; use std::collections::HashMap; use std::ffi::{OsStr, OsString}; use std::mem::MaybeUninit; @@ -34,6 +34,79 @@ use std::process::Command; use rayon::prelude::*; +struct Syncer(RefCell>>); + +impl Syncer { + fn get_disk_types) -> Vec>(&self, callback: F) -> Vec { + if self.0.borrow().is_none() { + *self.0.borrow_mut() = Some(get_disk_types()); + } + match &*self.0.borrow() { + Some(x) => callback(x), + None => Vec::new(), + } + } +} + +unsafe impl Sync for Syncer {} + +static DISK_TYPES: Syncer = Syncer(RefCell::new(None)); + +fn get_disk_types() -> HashMap { + let mut master_port: ffi::mach_port_t = 0; + let mut media_iterator: ffi::io_iterator_t = 0; + let mut ret = HashMap::with_capacity(1); + + unsafe { + ffi::IOMasterPort(ffi::MACH_PORT_NULL, &mut master_port); + + let matching_dictionary = ffi::IOServiceMatching(b"IOMedia\0".as_ptr() as *const i8); + let result = ffi::IOServiceGetMatchingServices( + master_port, + matching_dictionary, + &mut media_iterator, + ); + if result != ffi::KERN_SUCCESS as i32 { + //println!("Error: IOServiceGetMatchingServices() = {}", result); + return ret; + } + + loop { + let next_media = ffi::IOIteratorNext(media_iterator); + if next_media == 0 { + break; + } + let mut props = MaybeUninit::::uninit(); + let result = ffi::IORegistryEntryCreateCFProperties( + next_media, + props.as_mut_ptr(), + ffi::kCFAllocatorDefault, + 0, + ); + let props = props.assume_init(); + if result == ffi::KERN_SUCCESS as i32 && check_value(props, b"Whole\0") { + let mut name: ffi::io_name_t = mem::zeroed(); + if ffi::IORegistryEntryGetName(next_media, name.as_mut_ptr() as *mut c_char) + == ffi::KERN_SUCCESS as i32 + { + ret.insert( + make_name(&name), + if check_value(props, b"RAID\0") { + DiskType::Unknown(-1) + } else { + DiskType::SSD + }, + ); + } + ffi::CFRelease(props as *mut _); + } + ffi::IOObjectRelease(next_media); + } + ffi::IOObjectRelease(media_iterator); + } + ret +} + /// Structs containing system's information. pub struct System { process_list: HashMap, @@ -237,87 +310,31 @@ fn make_name(v: &[u8]) -> OsString { OsStringExt::from_vec(v.to_vec()) } -fn get_disk_types() -> HashMap { - let mut master_port: ffi::mach_port_t = 0; - let mut media_iterator: ffi::io_iterator_t = 0; - let mut ret = HashMap::new(); - - unsafe { - ffi::IOMasterPort(ffi::MACH_PORT_NULL, &mut master_port); - - let matching_dictionary = ffi::IOServiceMatching(b"IOMedia\0".as_ptr() as *const i8); - let result = ffi::IOServiceGetMatchingServices( - master_port, - matching_dictionary, - &mut media_iterator, - ); - if result != ffi::KERN_SUCCESS as i32 { - //println!("Error: IOServiceGetMatchingServices() = {}", result); - return ret; - } - - loop { - let next_media = ffi::IOIteratorNext(media_iterator); - if next_media == 0 { - break; - } - let mut props = MaybeUninit::::uninit(); - let result = ffi::IORegistryEntryCreateCFProperties( - next_media, - props.as_mut_ptr(), - ffi::kCFAllocatorDefault, - 0, - ); - let props = props.assume_init(); - if result == ffi::KERN_SUCCESS as i32 && check_value(props, b"Whole\0") { - let mut name: ffi::io_name_t = mem::zeroed(); - if ffi::IORegistryEntryGetName(next_media, name.as_mut_ptr() as *mut c_char) - == ffi::KERN_SUCCESS as i32 - { - ret.insert( - make_name(&name), - if check_value(props, b"RAID\0") { - DiskType::Unknown(-1) - } else { - DiskType::SSD - }, - ); - } - ffi::CFRelease(props as *mut _); - } - ffi::IOObjectRelease(next_media); - } - ffi::IOObjectRelease(media_iterator); - } - ret -} - fn get_disks() -> Vec { - let disk_types = get_disk_types(); - - unwrapper!(fs::read_dir("/Volumes"), Vec::new()) - .flat_map(|x| { - if let Ok(ref entry) = x { - let mount_point = utils::realpath(&entry.path()); - if mount_point.as_os_str().is_empty() { - None + DISK_TYPES.get_disk_types(|disk_types| { + unwrapper!(fs::read_dir("/Volumes"), Vec::new()) + .flat_map(|x| { + if let Ok(ref entry) = x { + let mount_point = utils::realpath(&entry.path()); + if mount_point.as_os_str().is_empty() { + None + } else { + let name = entry + .path() + .file_name()? + .to_owned(); + let type_ = disk_types + .get(&name) + .cloned() + .unwrap_or(DiskType::Unknown(-2)); + Some(disk::new(name, &mount_point, type_)) + } } else { - let name = entry - .path() - .file_name() - .unwrap_or_else(|| OsStr::new("")) - .to_owned(); - let type_ = disk_types - .get(&name) - .cloned() - .unwrap_or(DiskType::Unknown(-2)); - Some(disk::new(name, &mount_point, type_)) + None } - } else { - None - } - }) - .collect() + }) + .collect() + }) } fn get_uptime() -> u64 { @@ -454,14 +471,19 @@ fn update_process( Ok(x) => x, _ => return Err(()), }; - let mut p = Process::new(pid, if p == 0 { None } else { Some(p) }, 0); - p.exe = PathBuf::from(&command[0]); - p.name = match p.exe.file_name() { + let exe = PathBuf::from(&command[0]); + let name = match exe.file_name() { Some(x) => x.to_str().unwrap_or_else(|| "").to_owned(), None => String::new(), }; - p.cmd = command; - return Ok(Some(p)); + return Ok(Some(Process::new_with( + pid, + if p == 0 { None } else { Some(p) }, + 0, + exe, + name, + command, + ))); } _ => { return Err(()); @@ -474,14 +496,6 @@ fn update_process( p => Some(p), }; - let mut p = Process::new(pid, parent, task_info.pbsd.pbi_start_tvsec); - p.memory = task_info.ptinfo.pti_resident_size >> 10; // divide by 1024 - p.virtual_memory = task_info.ptinfo.pti_virtual_size >> 10; // divide by 1024 - - p.uid = task_info.pbsd.pbi_uid; - p.gid = task_info.pbsd.pbi_gid; - p.process_status = ProcessStatus::from(task_info.pbsd.pbi_status); - let ptr: *mut u8 = proc_args.as_mut_slice().as_mut_ptr(); mib[0] = libc::CTL_KERN; mib[1] = libc::KERN_PROCARGS2; @@ -523,73 +537,113 @@ fn update_process( &mut size, ::std::ptr::null_mut(), 0, - ) != -1 + ) == -1 { - let mut n_args: c_int = 0; - libc::memcpy( - (&mut n_args) as *mut c_int as *mut c_void, - ptr as *const c_void, - mem::size_of::(), - ); - let mut cp = ptr.add(mem::size_of::()); - let mut start = cp; - if cp < ptr.add(size) { - while cp < ptr.add(size) && *cp != 0 { - cp = cp.offset(1); - } - p.exe = Path::new(get_unchecked_str(cp, start).as_str()).to_path_buf(); - p.name = p - .exe - .file_name() - .unwrap_or_else(|| OsStr::new("")) - .to_str() - .unwrap_or_else(|| "") - .to_owned(); - let mut need_root = true; - if p.exe.is_absolute() { - if let Some(parent) = p.exe.parent() { - p.root = parent.to_path_buf(); - need_root = false; - } - } - while cp < ptr.add(size) && *cp == 0 { - cp = cp.offset(1); + return Err(()); // not enough rights I assume? + } + let mut n_args: c_int = 0; + libc::memcpy( + (&mut n_args) as *mut c_int as *mut c_void, + ptr as *const c_void, + mem::size_of::(), + ); + + let mut cp = ptr.add(mem::size_of::()); + let mut start = cp; + + let mut p = if cp < ptr.add(size) { + while cp < ptr.add(size) && *cp != 0 { + cp = cp.offset(1); + } + let exe = Path::new(get_unchecked_str(cp, start).as_str()).to_path_buf(); + let name = exe + .file_name() + .unwrap_or_else(|| OsStr::new("")) + .to_str() + .unwrap_or_else(|| "") + .to_owned(); + while cp < ptr.add(size) && *cp == 0 { + cp = cp.offset(1); + } + start = cp; + let mut c = 0; + let mut cmd = Vec::with_capacity(n_args as usize); + while c < n_args && cp < ptr.add(size) { + if *cp == 0 { + c += 1; + cmd.push(get_unchecked_str(cp, start)); + start = cp.offset(1); } - start = cp; - let mut c = 0; - let mut cmd = Vec::new(); - while c < n_args && cp < ptr.add(size) { - if *cp == 0 { - c += 1; - cmd.push(get_unchecked_str(cp, start)); - start = cp.offset(1); - } - cp = cp.offset(1); + cp = cp.offset(1); + } + + #[inline] + fn do_nothing(_: &str, _: &mut PathBuf, _: &mut bool) {} + #[inline] + fn do_something(env: &str, root: &mut PathBuf, check: &mut bool) { + if *check && env.starts_with("PATH=") { + *check = false; + *root = Path::new(&env[6..]).to_path_buf(); } - p.cmd = parse_command_line(&cmd); - start = cp; + } + + #[inline] + unsafe fn get_environ( + ptr: *mut u8, + mut cp: *mut u8, + size: size_t, + mut root: PathBuf, + callback: F, + ) -> (Vec, PathBuf) { + let mut environ = Vec::with_capacity(10); + let mut start = cp; + let mut check = true; while cp < ptr.add(size) { if *cp == 0 { if cp == start { break; } - p.environ.push(get_unchecked_str(cp, start)); + let e = get_unchecked_str(cp, start); + callback(&e, &mut root, &mut check); + environ.push(e); start = cp.offset(1); } cp = cp.offset(1); } - if need_root { - for env in p.environ.iter() { - if env.starts_with("PATH=") { - p.root = Path::new(&env[6..]).to_path_buf(); - break; - } - } - } + (environ, root) } + + let (environ, root) = if exe.is_absolute() { + if let Some(parent) = exe.parent() { + get_environ(ptr, cp, size, parent.to_path_buf(), do_nothing) + } else { + get_environ(ptr, cp, size, PathBuf::new(), do_something) + } + } else { + get_environ(ptr, cp, size, PathBuf::new(), do_something) + }; + + Process::new_with2( + pid, + parent, + task_info.pbsd.pbi_start_tvsec, + exe, + name, + parse_command_line(&cmd), + environ, + root, + ) } else { - return Err(()); // not enough rights I assume? - } + Process::new(pid, parent, task_info.pbsd.pbi_start_tvsec) + }; + + p.memory = task_info.ptinfo.pti_resident_size >> 10; // divide by 1024 + p.virtual_memory = task_info.ptinfo.pti_virtual_size >> 10; // divide by 1024 + + p.uid = task_info.pbsd.pbi_uid; + p.gid = task_info.pbsd.pbi_gid; + p.process_status = ProcessStatus::from(task_info.pbsd.pbi_status); + Ok(Some(p)) } } @@ -674,16 +728,16 @@ impl System { impl SystemExt for System { fn new_with_specifics(refreshes: RefreshKind) -> System { let mut s = System { - process_list: HashMap::new(), + process_list: HashMap::with_capacity(200), mem_total: 0, mem_free: 0, swap_total: 0, swap_free: 0, - processors: Vec::new(), + processors: Vec::with_capacity(4), page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 >> 10 }, // divide by 1024 - temperatures: Vec::new(), + temperatures: Vec::with_capacity(2), connection: get_io_service_connection(), - disks: Vec::new(), + disks: Vec::with_capacity(1), network: network::new(), uptime: get_uptime(), port: unsafe { ffi::mach_host_self() }, From aa47aa9b9c7844aed3d3de3fc1f75db6d0ec7bd3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Jan 2020 15:05:33 +0100 Subject: [PATCH 044/171] Create FUNDING.yml --- .github/FUNDING.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..c86b850e2 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +github: [GuillaumeGomez] +patreon: GuillaumeGomez From 0053c90c076228fd4899498212c29fd322aaf9b6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Jan 2020 17:08:14 +0100 Subject: [PATCH 045/171] Code cleanup --- src/mac/component.rs | 126 ++++++++++++++++++++++++++-- src/mac/ffi.rs | 3 +- src/mac/system.rs | 191 ++++++------------------------------------- 3 files changed, 145 insertions(+), 175 deletions(-) diff --git a/src/mac/component.rs b/src/mac/component.rs index 8694f42fa..90fba0b8e 100644 --- a/src/mac/component.rs +++ b/src/mac/component.rs @@ -4,24 +4,50 @@ // Copyright (c) 2018 Guillaume Gomez // +use libc::{c_char, c_int, c_void}; +use std::mem; +use sys::ffi; use ComponentExt; +pub(crate) const COMPONENTS_TEMPERATURE_IDS: &[(&str, &[i8])] = &[ + ("CPU", &['T' as i8, 'C' as i8, '0' as i8, 'P' as i8, 0]), // CPU "TC0P" + ("GPU", &['T' as i8, 'G' as i8, '0' as i8, 'P' as i8, 0]), // GPU "TG0P" + ("Battery", &['T' as i8, 'B' as i8, '0' as i8, 'T' as i8, 0]), // Battery "TB0T" +]; + /// Struct containing a component information (temperature and name for the moment). pub struct Component { temperature: f32, max: f32, critical: Option, label: String, + key: Vec, } impl Component { /// Creates a new `Component` with the given information. - pub fn new(label: String, max: Option, critical: Option) -> Component { - Component { - temperature: 0f32, + pub(crate) fn new( + label: String, + max: Option, + critical: Option, + key: Vec, + con: ffi::io_connect_t, + ) -> Option { + get_temperature(con, &key).map(|temperature| Component { + temperature, label, max: max.unwrap_or(0.0), critical, + key, + }) + } + + pub(crate) fn update(&mut self, con: ffi::io_connect_t) { + if let Some(temp) = get_temperature(con, &self.key) { + self.temperature = temp; + if self.temperature > self.max { + self.max = self.temperature; + } } } } @@ -44,9 +70,95 @@ impl ComponentExt for Component { } } -pub fn update_component(comp: &mut Component, temperature: f32) { - comp.temperature = temperature; - if comp.temperature > comp.max { - comp.max = comp.temperature; +unsafe fn perform_call( + conn: ffi::io_connect_t, + index: c_int, + input_structure: *mut ffi::KeyData_t, + output_structure: *mut ffi::KeyData_t, +) -> i32 { + let mut structure_output_size = mem::size_of::(); + + ffi::IOConnectCallStructMethod( + conn, + index as u32, + input_structure, + mem::size_of::(), + output_structure, + &mut structure_output_size, + ) +} + +// Adapted from https://github.com/lavoiesl/osx-cpu-temp/blob/master/smc.c#L28 +#[inline] +unsafe fn strtoul(s: *const c_char) -> u32 { + ((*s.offset(0) as u32) << (3u32 << 3)) + + ((*s.offset(1) as u32) << (2u32 << 3)) + + ((*s.offset(2) as u32) << (1u32 << 3)) + + ((*s.offset(3) as u32) << (0u32 << 3)) +} + +#[inline] +unsafe fn ultostr(s: *mut c_char, val: u32) { + *s.offset(0) = ((val >> 24) % 128) as i8; + *s.offset(1) = ((val >> 16) % 128) as i8; + *s.offset(2) = ((val >> 8) % 128) as i8; + *s.offset(3) = (val % 128) as i8; + *s.offset(4) = 0; +} + +unsafe fn read_key(con: ffi::io_connect_t, key: *const c_char) -> Result { + let mut input_structure: ffi::KeyData_t = mem::zeroed::(); + let mut output_structure: ffi::KeyData_t = mem::zeroed::(); + let mut val: ffi::Val_t = mem::zeroed::(); + + input_structure.key = strtoul(key); + input_structure.data8 = ffi::SMC_CMD_READ_KEYINFO; + + let result = perform_call( + con, + ffi::KERNEL_INDEX_SMC, + &mut input_structure, + &mut output_structure, + ); + if result != ffi::KIO_RETURN_SUCCESS { + return Err(result); + } + + val.data_size = output_structure.key_info.data_size; + ultostr( + val.data_type.as_mut_ptr(), + output_structure.key_info.data_type, + ); + input_structure.key_info.data_size = val.data_size; + input_structure.data8 = ffi::SMC_CMD_READ_BYTES; + + match perform_call( + con, + ffi::KERNEL_INDEX_SMC, + &mut input_structure, + &mut output_structure, + ) { + ffi::KIO_RETURN_SUCCESS => { + libc::memcpy( + val.bytes.as_mut_ptr() as *mut c_void, + output_structure.bytes.as_mut_ptr() as *mut c_void, + mem::size_of::<[u8; 32]>(), + ); + Ok(val) + } + result => Err(result), + } +} + +pub(crate) fn get_temperature(con: ffi::io_connect_t, v: &[i8]) -> Option { + if let Ok(val) = unsafe { read_key(con, v.as_ptr()) } { + if val.data_size > 0 + && unsafe { libc::strcmp(val.data_type.as_ptr(), b"sp78\0".as_ptr() as *const i8) } == 0 + { + // convert sp78 value to temperature + let x = (i32::from(val.bytes[0]) << 6) + (i32::from(val.bytes[1]) >> 2); + return Some(x as f32 / 64f32); + } } + None } diff --git a/src/mac/ffi.rs b/src/mac/ffi.rs index 016ce6d5f..610ad1457 100644 --- a/src/mac/ffi.rs +++ b/src/mac/ffi.rs @@ -279,7 +279,8 @@ pub struct vm_statistics64 { pub total_uncompressed_pages_in_compressor: u64, } -#[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] +#[cfg_attr(feature = "debug", derive(Eq, Hash, PartialEq))] +#[derive(Debug)] #[repr(C)] pub struct Val_t { pub key: [i8; 5], diff --git a/src/mac/system.rs b/src/mac/system.rs index 76d611db7..f775b9632 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -11,10 +11,10 @@ use sys::network::{self, NetworkData}; use sys::process::*; use sys::processor::*; -use {ComponentExt, DiskExt, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; +use {DiskExt, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; use std::borrow::Borrow; -use std::cell::{UnsafeCell, RefCell}; +use std::cell::{RefCell, UnsafeCell}; use std::collections::HashMap; use std::ffi::{OsStr, OsString}; use std::mem::MaybeUninit; @@ -37,7 +37,10 @@ use rayon::prelude::*; struct Syncer(RefCell>>); impl Syncer { - fn get_disk_types) -> Vec>(&self, callback: F) -> Vec { + fn get_disk_types) -> Vec>( + &self, + callback: F, + ) -> Vec { if self.0.borrow().is_none() { *self.0.borrow_mut() = Some(get_disk_types()); } @@ -169,106 +172,6 @@ fn get_io_service_connection() -> Option { } } -unsafe fn strtoul(s: *mut c_char, size: c_int, base: c_int) -> u32 { - let mut total = 0u32; - - for i in 0..size { - total += if base == 16 { - (*s.offset(i as isize) as u32) << (((size - 1 - i) as u32) << 3) - } else { - (*s.offset(i as isize) as u32) << ((size - 1 - i) << 3) as u32 - }; - } - total -} - -unsafe fn ultostr(s: *mut c_char, val: u32) { - *s = 0; - libc::sprintf( - s, - b"%c%c%c%c\0".as_ptr() as *const i8, - val >> 24, - val >> 16, - val >> 8, - val, - ); -} - -unsafe fn perform_call( - conn: ffi::io_connect_t, - index: c_int, - input_structure: *mut ffi::KeyData_t, - output_structure: *mut ffi::KeyData_t, -) -> i32 { - let mut structure_output_size = mem::size_of::(); - - ffi::IOConnectCallStructMethod( - conn, - index as u32, - input_structure, - mem::size_of::(), - output_structure, - &mut structure_output_size, - ) -} - -unsafe fn read_key(con: ffi::io_connect_t, key: *mut c_char) -> Result { - let mut input_structure: ffi::KeyData_t = mem::zeroed::(); - let mut output_structure: ffi::KeyData_t = mem::zeroed::(); - let mut val: ffi::Val_t = mem::zeroed::(); - - input_structure.key = strtoul(key, 4, 16); - input_structure.data8 = ffi::SMC_CMD_READ_KEYINFO; - - let result = perform_call( - con, - ffi::KERNEL_INDEX_SMC, - &mut input_structure, - &mut output_structure, - ); - if result != ffi::KIO_RETURN_SUCCESS { - return Err(result); - } - - val.data_size = output_structure.key_info.data_size; - ultostr( - val.data_type.as_mut_ptr(), - output_structure.key_info.data_type, - ); - input_structure.key_info.data_size = val.data_size; - input_structure.data8 = ffi::SMC_CMD_READ_BYTES; - - let result = perform_call( - con, - ffi::KERNEL_INDEX_SMC, - &mut input_structure, - &mut output_structure, - ); - if result != ffi::KIO_RETURN_SUCCESS { - Err(result) - } else { - libc::memcpy( - val.bytes.as_mut_ptr() as *mut c_void, - output_structure.bytes.as_mut_ptr() as *mut c_void, - mem::size_of::<[u8; 32]>(), - ); - Ok(val) - } -} - -unsafe fn get_temperature(con: ffi::io_connect_t, key: *mut c_char) -> f32 { - if let Ok(val) = read_key(con, key) { - if val.data_size > 0 - && libc::strcmp(val.data_type.as_ptr(), b"sp78\0".as_ptr() as *const i8) == 0 - { - // convert fp78 value to temperature - let x = (i32::from(val.bytes[0]) << 6) + (i32::from(val.bytes[1]) >> 2); - return x as f32 / 64f32; - } - } - 0f32 -} - unsafe fn get_unchecked_str(cp: *mut u8, start: *mut u8) -> String { let len = cp as usize - start as usize; let part = Vec::from_raw_parts(start, len, len); @@ -319,10 +222,7 @@ fn get_disks() -> Vec { if mount_point.as_os_str().is_empty() { None } else { - let name = entry - .path() - .file_name()? - .to_owned(); + let name = entry.path().file_name()?.to_owned(); let type_ = disk_types .get(&name) .cloned() @@ -805,68 +705,25 @@ impl SystemExt for System { } fn refresh_temperatures(&mut self) { - unsafe { - if let Some(con) = self.connection { - if self.temperatures.is_empty() { - // getting CPU critical temperature - let mut v = vec!['T' as i8, 'C' as i8, '0' as i8, 'D' as i8, 0]; - let tmp = get_temperature(con, v.as_mut_ptr()); - let critical_temp = if tmp > 0f32 { Some(tmp) } else { None }; - // getting CPU temperature - // "TC0P" - v[3] = 'P' as i8; - let temp = get_temperature(con, v.as_mut_ptr() as *mut i8); - if temp > 0f32 { - self.temperatures.push(Component::new( - "CPU".to_owned(), - None, - critical_temp, - )); - } - // getting GPU temperature - // "TG0P" - v[1] = 'G' as i8; - let temp = get_temperature(con, v.as_mut_ptr() as *mut i8); - if temp > 0f32 { - self.temperatures.push(Component::new( - "GPU".to_owned(), - None, - critical_temp, - )); - } - // getting battery temperature - // "TB0T" - v[1] = 'B' as i8; - v[3] = 'T' as i8; - let temp = get_temperature(con, v.as_mut_ptr() as *mut i8); - if temp > 0f32 { - self.temperatures.push(Component::new( - "Battery".to_owned(), - None, - critical_temp, - )); - } - } else { - let mut v = vec!['T' as i8, 'C' as i8, '0' as i8, 'P' as i8, 0]; - for comp in &mut self.temperatures { - match &*comp.get_label() { - "CPU" => { - v[1] = 'C' as i8; - v[3] = 'P' as i8; - } - "GPU" => { - v[1] = 'G' as i8; - v[3] = 'P' as i8; - } - _ => { - v[1] = 'B' as i8; - v[3] = 'T' as i8; - } - }; - let temp = get_temperature(con, v.as_mut_ptr() as *mut i8); - ::sys::component::update_component(comp, temp); + if let Some(con) = self.connection { + if self.temperatures.is_empty() { + // getting CPU critical temperature + let critical_temp = crate::mac::component::get_temperature( + con, + &['T' as i8, 'C' as i8, '0' as i8, 'D' as i8, 0], + ); + + for (id, v) in crate::mac::component::COMPONENTS_TEMPERATURE_IDS.iter() { + if let Some(c) = + Component::new(id.to_string(), None, critical_temp, (*v).into(), con) + { + self.temperatures.push(c); } } + } else { + for comp in &mut self.temperatures { + comp.update(con); + } } } } From 36a134aaf2cb7ea4b12e79d46a0417ed961f67ae Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Jan 2020 18:45:17 +0100 Subject: [PATCH 046/171] Greatly improve refresh_temperatures --- src/mac/component.rs | 59 ++++++++++++++++++++++++++++++-------------- src/mac/ffi.rs | 4 +-- src/mac/system.rs | 2 +- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/mac/component.rs b/src/mac/component.rs index 90fba0b8e..b180cf22e 100644 --- a/src/mac/component.rs +++ b/src/mac/component.rs @@ -10,9 +10,9 @@ use sys::ffi; use ComponentExt; pub(crate) const COMPONENTS_TEMPERATURE_IDS: &[(&str, &[i8])] = &[ - ("CPU", &['T' as i8, 'C' as i8, '0' as i8, 'P' as i8, 0]), // CPU "TC0P" - ("GPU", &['T' as i8, 'G' as i8, '0' as i8, 'P' as i8, 0]), // GPU "TG0P" - ("Battery", &['T' as i8, 'B' as i8, '0' as i8, 'T' as i8, 0]), // Battery "TB0T" + ("CPU", &['T' as i8, 'C' as i8, '0' as i8, 'P' as i8]), // CPU "TC0P" + ("GPU", &['T' as i8, 'G' as i8, '0' as i8, 'P' as i8]), // GPU "TG0P" + ("Battery", &['T' as i8, 'B' as i8, '0' as i8, 'T' as i8]), // Battery "TB0T" ]; /// Struct containing a component information (temperature and name for the moment). @@ -21,7 +21,8 @@ pub struct Component { max: f32, critical: Option, label: String, - key: Vec, + input_structure: ffi::KeyData_t, + val: ffi::Val_t, } impl Component { @@ -30,20 +31,22 @@ impl Component { label: String, max: Option, critical: Option, - key: Vec, + key: &[i8], con: ffi::io_connect_t, ) -> Option { - get_temperature(con, &key).map(|temperature| Component { + let (input_structure, val) = unsafe { get_key_size(con, key) }.ok()?; + get_temperature_inner(con, &input_structure, &val).map(|temperature| Component { temperature, label, max: max.unwrap_or(0.0), critical, - key, + input_structure, + val, }) } pub(crate) fn update(&mut self, con: ffi::io_connect_t) { - if let Some(temp) = get_temperature(con, &self.key) { + if let Some(temp) = get_temperature_inner(con, &self.input_structure, &self.val) { self.temperature = temp; if self.temperature > self.max { self.max = self.temperature; @@ -73,7 +76,7 @@ impl ComponentExt for Component { unsafe fn perform_call( conn: ffi::io_connect_t, index: c_int, - input_structure: *mut ffi::KeyData_t, + input_structure: *const ffi::KeyData_t, output_structure: *mut ffi::KeyData_t, ) -> i32 { let mut structure_output_size = mem::size_of::(); @@ -90,11 +93,11 @@ unsafe fn perform_call( // Adapted from https://github.com/lavoiesl/osx-cpu-temp/blob/master/smc.c#L28 #[inline] -unsafe fn strtoul(s: *const c_char) -> u32 { - ((*s.offset(0) as u32) << (3u32 << 3)) - + ((*s.offset(1) as u32) << (2u32 << 3)) - + ((*s.offset(2) as u32) << (1u32 << 3)) - + ((*s.offset(3) as u32) << (0u32 << 3)) +fn strtoul(s: &[i8]) -> u32 { + ((s[0] as u32) << (3u32 << 3)) + + ((s[1] as u32) << (2u32 << 3)) + + ((s[2] as u32) << (1u32 << 3)) + + ((s[3] as u32) << (0u32 << 3)) } #[inline] @@ -106,7 +109,7 @@ unsafe fn ultostr(s: *mut c_char, val: u32) { *s.offset(4) = 0; } -unsafe fn read_key(con: ffi::io_connect_t, key: *const c_char) -> Result { +unsafe fn get_key_size(con: ffi::io_connect_t, key: &[i8]) -> Result<(ffi::KeyData_t, ffi::Val_t), i32> { let mut input_structure: ffi::KeyData_t = mem::zeroed::(); let mut output_structure: ffi::KeyData_t = mem::zeroed::(); let mut val: ffi::Val_t = mem::zeroed::(); @@ -117,7 +120,7 @@ unsafe fn read_key(con: ffi::io_connect_t, key: *const c_char) -> Result Result Result { + let mut output_structure: ffi::KeyData_t = mem::zeroed::(); match perform_call( con, ffi::KERNEL_INDEX_SMC, - &mut input_structure, + input_structure, &mut output_structure, ) { ffi::KIO_RETURN_SUCCESS => { @@ -150,8 +162,12 @@ unsafe fn read_key(con: ffi::io_connect_t, key: *const c_char) -> Result Option { - if let Ok(val) = unsafe { read_key(con, v.as_ptr()) } { +fn get_temperature_inner( + con: ffi::io_connect_t, + input_structure: &ffi::KeyData_t, + original_val: &ffi::Val_t, +) -> Option { + if let Ok(val) = unsafe { read_key(con, input_structure, (*original_val).clone()) } { if val.data_size > 0 && unsafe { libc::strcmp(val.data_type.as_ptr(), b"sp78\0".as_ptr() as *const i8) } == 0 { @@ -162,3 +178,8 @@ pub(crate) fn get_temperature(con: ffi::io_connect_t, v: &[i8]) -> Option { } None } + +pub(crate) fn get_temperature(con: ffi::io_connect_t, key: &[i8]) -> Option { + let (input_structure, val) = unsafe { get_key_size(con, &key) }.ok()?; + get_temperature_inner(con, &input_structure, &val) +} diff --git a/src/mac/ffi.rs b/src/mac/ffi.rs index 610ad1457..b53c24b3e 100644 --- a/src/mac/ffi.rs +++ b/src/mac/ffi.rs @@ -36,7 +36,7 @@ extern "C" { pub fn IOConnectCallStructMethod( connection: mach_port_t, selector: u32, - inputStruct: *mut KeyData_t, + inputStruct: *const KeyData_t, inputStructCnt: size_t, outputStruct: *mut KeyData_t, outputStructCnt: *mut size_t, @@ -280,7 +280,7 @@ pub struct vm_statistics64 { } #[cfg_attr(feature = "debug", derive(Eq, Hash, PartialEq))] -#[derive(Debug)] +#[derive(Clone)] #[repr(C)] pub struct Val_t { pub key: [i8; 5], diff --git a/src/mac/system.rs b/src/mac/system.rs index f775b9632..d400a9031 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -715,7 +715,7 @@ impl SystemExt for System { for (id, v) in crate::mac::component::COMPONENTS_TEMPERATURE_IDS.iter() { if let Some(c) = - Component::new(id.to_string(), None, critical_temp, (*v).into(), con) + Component::new(id.to_string(), None, critical_temp, v, con) { self.temperatures.push(c); } From 6c8c5d4ba7c01dc2f2a8f5af163fe54b30bf0df9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Jan 2020 18:51:31 +0100 Subject: [PATCH 047/171] Clean up temperature source code --- src/mac/component.rs | 37 +++++++++++++++++++++++++++++-------- src/mac/system.rs | 4 +--- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/mac/component.rs b/src/mac/component.rs index b180cf22e..85c9ac326 100644 --- a/src/mac/component.rs +++ b/src/mac/component.rs @@ -15,14 +15,33 @@ pub(crate) const COMPONENTS_TEMPERATURE_IDS: &[(&str, &[i8])] = &[ ("Battery", &['T' as i8, 'B' as i8, '0' as i8, 'T' as i8]), // Battery "TB0T" ]; +pub struct ComponentFFI { + input_structure: ffi::KeyData_t, + val: ffi::Val_t, +} + +impl ComponentFFI { + fn new(key: &[i8], con: ffi::io_connect_t) -> Option { + unsafe { get_key_size(con, key) } + .ok() + .map(|(input_structure, val)| ComponentFFI { + input_structure, + val, + }) + } + + fn get_temperature(&self, con: ffi::io_connect_t) -> Option { + get_temperature_inner(con, &self.input_structure, &self.val) + } +} + /// Struct containing a component information (temperature and name for the moment). pub struct Component { temperature: f32, max: f32, critical: Option, label: String, - input_structure: ffi::KeyData_t, - val: ffi::Val_t, + ffi_part: ComponentFFI, } impl Component { @@ -34,19 +53,18 @@ impl Component { key: &[i8], con: ffi::io_connect_t, ) -> Option { - let (input_structure, val) = unsafe { get_key_size(con, key) }.ok()?; - get_temperature_inner(con, &input_structure, &val).map(|temperature| Component { + let ffi_part = ComponentFFI::new(key, con)?; + ffi_part.get_temperature(con).map(|temperature| Component { temperature, label, max: max.unwrap_or(0.0), critical, - input_structure, - val, + ffi_part, }) } pub(crate) fn update(&mut self, con: ffi::io_connect_t) { - if let Some(temp) = get_temperature_inner(con, &self.input_structure, &self.val) { + if let Some(temp) = self.ffi_part.get_temperature(con) { self.temperature = temp; if self.temperature > self.max { self.max = self.temperature; @@ -109,7 +127,10 @@ unsafe fn ultostr(s: *mut c_char, val: u32) { *s.offset(4) = 0; } -unsafe fn get_key_size(con: ffi::io_connect_t, key: &[i8]) -> Result<(ffi::KeyData_t, ffi::Val_t), i32> { +unsafe fn get_key_size( + con: ffi::io_connect_t, + key: &[i8], +) -> Result<(ffi::KeyData_t, ffi::Val_t), i32> { let mut input_structure: ffi::KeyData_t = mem::zeroed::(); let mut output_structure: ffi::KeyData_t = mem::zeroed::(); let mut val: ffi::Val_t = mem::zeroed::(); diff --git a/src/mac/system.rs b/src/mac/system.rs index d400a9031..310d6e73a 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -714,9 +714,7 @@ impl SystemExt for System { ); for (id, v) in crate::mac::component::COMPONENTS_TEMPERATURE_IDS.iter() { - if let Some(c) = - Component::new(id.to_string(), None, critical_temp, v, con) - { + if let Some(c) = Component::new(id.to_string(), None, critical_temp, v, con) { self.temperatures.push(c); } } From a82f57488a69a4d756fb3294770b53261dab8806 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Jan 2020 19:00:49 +0100 Subject: [PATCH 048/171] Move disk code into its own file --- src/mac/disk.rs | 202 +++++++++++++++++++++++++++++++++++++++------- src/mac/system.rs | 155 ++--------------------------------- 2 files changed, 179 insertions(+), 178 deletions(-) diff --git a/src/mac/disk.rs b/src/mac/disk.rs index 5a1d6d6df..70d0261c7 100644 --- a/src/mac/disk.rs +++ b/src/mac/disk.rs @@ -7,11 +7,18 @@ use utils; use DiskExt; -use libc::statfs; +use libc::{c_char, c_void, statfs}; +use std::cell::RefCell; +use std::collections::HashMap; use std::ffi::{OsStr, OsString}; use std::fmt::{Debug, Error, Formatter}; +use std::fs; use std::mem; +use std::mem::MaybeUninit; +use std::os::unix::ffi::OsStringExt; use std::path::{Path, PathBuf}; +use std::ptr; +use sys::ffi; /// Enum containing the different handled disks types. #[derive(Debug, PartialEq, Clone, Copy)] @@ -34,36 +41,6 @@ impl From for DiskType { } } -pub fn new(name: OsString, mount_point: &Path, type_: DiskType) -> Disk { - let mount_point_cpath = utils::to_cpath(mount_point); - let mut total_space = 0; - let mut available_space = 0; - let mut file_system = None; - unsafe { - let mut stat: statfs = mem::zeroed(); - if statfs(mount_point_cpath.as_ptr() as *const i8, &mut stat) == 0 { - total_space = u64::from(stat.f_bsize) * stat.f_blocks; - available_space = stat.f_bfree * stat.f_blocks; - let mut vec = Vec::with_capacity(stat.f_fstypename.len()); - for x in &stat.f_fstypename { - if *x == 0 { - break; - } - vec.push(*x as u8); - } - file_system = Some(vec); - } - } - Disk { - type_, - name, - file_system: file_system.unwrap_or_else(|| b"".to_vec()), - mount_point: mount_point.to_owned(), - total_space, - available_space, - } -} - /// Struct containing a disk information. pub struct Disk { type_: DiskType, @@ -127,3 +104,166 @@ impl DiskExt for Disk { } } } + +macro_rules! unwrapper { + ($b:expr, $ret:expr) => {{ + match $b { + Ok(x) => x, + _ => return $ret, + } + }}; +} + +struct Syncer(RefCell>>); + +impl Syncer { + fn get_disk_types) -> Vec>( + &self, + callback: F, + ) -> Vec { + if self.0.borrow().is_none() { + *self.0.borrow_mut() = Some(get_disk_types()); + } + match &*self.0.borrow() { + Some(x) => callback(x), + None => Vec::new(), + } + } +} + +unsafe impl Sync for Syncer {} + +static DISK_TYPES: Syncer = Syncer(RefCell::new(None)); + +fn get_disk_types() -> HashMap { + let mut master_port: ffi::mach_port_t = 0; + let mut media_iterator: ffi::io_iterator_t = 0; + let mut ret = HashMap::with_capacity(1); + + unsafe { + ffi::IOMasterPort(ffi::MACH_PORT_NULL, &mut master_port); + + let matching_dictionary = ffi::IOServiceMatching(b"IOMedia\0".as_ptr() as *const i8); + let result = ffi::IOServiceGetMatchingServices( + master_port, + matching_dictionary, + &mut media_iterator, + ); + if result != ffi::KERN_SUCCESS as i32 { + //println!("Error: IOServiceGetMatchingServices() = {}", result); + return ret; + } + + loop { + let next_media = ffi::IOIteratorNext(media_iterator); + if next_media == 0 { + break; + } + let mut props = MaybeUninit::::uninit(); + let result = ffi::IORegistryEntryCreateCFProperties( + next_media, + props.as_mut_ptr(), + ffi::kCFAllocatorDefault, + 0, + ); + let props = props.assume_init(); + if result == ffi::KERN_SUCCESS as i32 && check_value(props, b"Whole\0") { + let mut name: ffi::io_name_t = mem::zeroed(); + if ffi::IORegistryEntryGetName(next_media, name.as_mut_ptr() as *mut c_char) + == ffi::KERN_SUCCESS as i32 + { + ret.insert( + make_name(&name), + if check_value(props, b"RAID\0") { + DiskType::Unknown(-1) + } else { + DiskType::SSD + }, + ); + } + ffi::CFRelease(props as *mut _); + } + ffi::IOObjectRelease(next_media); + } + ffi::IOObjectRelease(media_iterator); + } + ret +} + +fn make_name(v: &[u8]) -> OsString { + for (pos, x) in v.iter().enumerate() { + if *x == 0 { + return OsStringExt::from_vec(v[0..pos].to_vec()); + } + } + OsStringExt::from_vec(v.to_vec()) +} + +pub(crate) fn get_disks() -> Vec { + DISK_TYPES.get_disk_types(|disk_types| { + unwrapper!(fs::read_dir("/Volumes"), Vec::new()) + .flat_map(|x| { + if let Ok(ref entry) = x { + let mount_point = utils::realpath(&entry.path()); + if mount_point.as_os_str().is_empty() { + None + } else { + let name = entry.path().file_name()?.to_owned(); + let type_ = disk_types + .get(&name) + .cloned() + .unwrap_or(DiskType::Unknown(-2)); + Some(new_disk(name, &mount_point, type_)) + } + } else { + None + } + }) + .collect() + }) +} + +unsafe fn check_value(dict: ffi::CFMutableDictionaryRef, key: &[u8]) -> bool { + let key = ffi::CFStringCreateWithCStringNoCopy( + ptr::null_mut(), + key.as_ptr() as *const c_char, + ffi::kCFStringEncodingMacRoman, + ffi::kCFAllocatorNull as *mut c_void, + ); + let ret = ffi::CFDictionaryContainsKey(dict as ffi::CFDictionaryRef, key as *const c_void) != 0 + && *(ffi::CFDictionaryGetValue(dict as ffi::CFDictionaryRef, key as *const c_void) + as *const ffi::Boolean) + != 0; + ffi::CFRelease(key as *const c_void); + ret +} + +fn new_disk(name: OsString, mount_point: &Path, type_: DiskType) -> Disk { + let mount_point_cpath = utils::to_cpath(mount_point); + let mut total_space = 0; + let mut available_space = 0; + let mut file_system = None; + unsafe { + let mut stat: statfs = mem::zeroed(); + if statfs(mount_point_cpath.as_ptr() as *const i8, &mut stat) == 0 { + total_space = u64::from(stat.f_bsize) * stat.f_blocks; + available_space = stat.f_bfree * stat.f_blocks; + let mut vec = Vec::with_capacity(stat.f_fstypename.len()); + for x in &stat.f_fstypename { + if *x == 0 { + break; + } + vec.push(*x as u8); + } + file_system = Some(vec); + } + } + Disk { + type_, + name, + file_system: file_system.unwrap_or_else(|| b"".to_vec()), + mount_point: mount_point.to_owned(), + total_space, + available_space, + } +} diff --git a/src/mac/system.rs b/src/mac/system.rs index 310d6e73a..455c0a80e 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -5,111 +5,29 @@ // use sys::component::Component; -use sys::disk::{self, Disk, DiskType}; +use sys::disk::Disk; use sys::ffi; use sys::network::{self, NetworkData}; use sys::process::*; use sys::processor::*; -use {DiskExt, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; +use {DiskExt, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; use std::borrow::Borrow; -use std::cell::{RefCell, UnsafeCell}; +use std::cell::UnsafeCell; use std::collections::HashMap; -use std::ffi::{OsStr, OsString}; -use std::mem::MaybeUninit; +use std::ffi::OsStr; +use std::mem; use std::ops::Deref; -use std::os::unix::ffi::OsStringExt; use std::path::{Path, PathBuf}; +use std::process::Command; use std::sync::Arc; -use std::{fs, mem, ptr}; use sys::processor; -use libc::{self, c_char, c_int, c_void, size_t, sysconf, _SC_PAGESIZE}; - -use utils; -use Pid; - -use std::process::Command; +use libc::{self, c_int, c_void, size_t, sysconf, _SC_PAGESIZE}; use rayon::prelude::*; -struct Syncer(RefCell>>); - -impl Syncer { - fn get_disk_types) -> Vec>( - &self, - callback: F, - ) -> Vec { - if self.0.borrow().is_none() { - *self.0.borrow_mut() = Some(get_disk_types()); - } - match &*self.0.borrow() { - Some(x) => callback(x), - None => Vec::new(), - } - } -} - -unsafe impl Sync for Syncer {} - -static DISK_TYPES: Syncer = Syncer(RefCell::new(None)); - -fn get_disk_types() -> HashMap { - let mut master_port: ffi::mach_port_t = 0; - let mut media_iterator: ffi::io_iterator_t = 0; - let mut ret = HashMap::with_capacity(1); - - unsafe { - ffi::IOMasterPort(ffi::MACH_PORT_NULL, &mut master_port); - - let matching_dictionary = ffi::IOServiceMatching(b"IOMedia\0".as_ptr() as *const i8); - let result = ffi::IOServiceGetMatchingServices( - master_port, - matching_dictionary, - &mut media_iterator, - ); - if result != ffi::KERN_SUCCESS as i32 { - //println!("Error: IOServiceGetMatchingServices() = {}", result); - return ret; - } - - loop { - let next_media = ffi::IOIteratorNext(media_iterator); - if next_media == 0 { - break; - } - let mut props = MaybeUninit::::uninit(); - let result = ffi::IORegistryEntryCreateCFProperties( - next_media, - props.as_mut_ptr(), - ffi::kCFAllocatorDefault, - 0, - ); - let props = props.assume_init(); - if result == ffi::KERN_SUCCESS as i32 && check_value(props, b"Whole\0") { - let mut name: ffi::io_name_t = mem::zeroed(); - if ffi::IORegistryEntryGetName(next_media, name.as_mut_ptr() as *mut c_char) - == ffi::KERN_SUCCESS as i32 - { - ret.insert( - make_name(&name), - if check_value(props, b"RAID\0") { - DiskType::Unknown(-1) - } else { - DiskType::SSD - }, - ); - } - ffi::CFRelease(props as *mut _); - } - ffi::IOObjectRelease(next_media); - } - ffi::IOObjectRelease(media_iterator); - } - ret -} - /// Structs containing system's information. pub struct System { process_list: HashMap, @@ -180,63 +98,6 @@ unsafe fn get_unchecked_str(cp: *mut u8, start: *mut u8) -> String { tmp } -macro_rules! unwrapper { - ($b:expr, $ret:expr) => {{ - match $b { - Ok(x) => x, - _ => return $ret, - } - }}; -} - -unsafe fn check_value(dict: ffi::CFMutableDictionaryRef, key: &[u8]) -> bool { - let key = ffi::CFStringCreateWithCStringNoCopy( - ptr::null_mut(), - key.as_ptr() as *const c_char, - ffi::kCFStringEncodingMacRoman, - ffi::kCFAllocatorNull as *mut c_void, - ); - let ret = ffi::CFDictionaryContainsKey(dict as ffi::CFDictionaryRef, key as *const c_void) != 0 - && *(ffi::CFDictionaryGetValue(dict as ffi::CFDictionaryRef, key as *const c_void) - as *const ffi::Boolean) - != 0; - ffi::CFRelease(key as *const c_void); - ret -} - -fn make_name(v: &[u8]) -> OsString { - for (pos, x) in v.iter().enumerate() { - if *x == 0 { - return OsStringExt::from_vec(v[0..pos].to_vec()); - } - } - OsStringExt::from_vec(v.to_vec()) -} - -fn get_disks() -> Vec { - DISK_TYPES.get_disk_types(|disk_types| { - unwrapper!(fs::read_dir("/Volumes"), Vec::new()) - .flat_map(|x| { - if let Ok(ref entry) = x { - let mount_point = utils::realpath(&entry.path()); - if mount_point.as_os_str().is_empty() { - None - } else { - let name = entry.path().file_name()?.to_owned(); - let type_ = disk_types - .get(&name) - .cloned() - .unwrap_or(DiskType::Unknown(-2)); - Some(disk::new(name, &mount_point, type_)) - } - } else { - None - } - }) - .collect() - }) -} - fn get_uptime() -> u64 { let mut boottime: libc::timeval = unsafe { mem::zeroed() }; let mut len = mem::size_of::(); @@ -906,7 +767,7 @@ impl SystemExt for System { } fn refresh_disk_list(&mut self) { - self.disks = get_disks(); + self.disks = crate::mac::disk::get_disks(); } // COMMON PART From a08d67d303571f3674f46ce6795ca683e1e24f3b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Jan 2020 22:37:03 +0100 Subject: [PATCH 049/171] Clean up process source code --- src/mac/process.rs | 329 ++++++++++++++++++++++++++++++++++++++++++++- src/mac/system.rs | 320 +------------------------------------------ 2 files changed, 326 insertions(+), 323 deletions(-) diff --git a/src/mac/process.rs b/src/mac/process.rs index a8271c684..2b6cbc1de 100644 --- a/src/mac/process.rs +++ b/src/mac/process.rs @@ -4,14 +4,22 @@ // Copyright (c) 2015 Guillaume Gomez // +use std::borrow::Borrow; +use std::ffi::OsStr; use std::fmt::{self, Debug, Formatter}; +use std::mem; +use std::ops::Deref; use std::path::{Path, PathBuf}; +use std::process::Command; -use libc::{c_int, gid_t, kill, uid_t}; +use libc::{c_int, c_void, gid_t, kill, size_t, uid_t}; use Pid; use ProcessExt; +use sys::system::Wrap; +use sys::ffi; + /// Enum describing the different status of a process. #[derive(Clone, Copy, Debug)] pub enum ProcessStatus { @@ -332,7 +340,7 @@ impl Debug for Process { } } -pub fn compute_cpu_usage(p: &mut Process, time: u64, task_time: u64) { +pub(crate) fn compute_cpu_usage(p: &mut Process, time: u64, task_time: u64) { let system_time_delta = task_time - p.old_utime; let time_delta = time - p.old_stime; p.old_utime = task_time; @@ -353,12 +361,325 @@ pub fn compute_cpu_usage(p: &mut Process, time: u64, task_time: u64) { p.updated = true; }*/ -pub fn has_been_updated(p: &mut Process) -> bool { +pub(crate) fn has_been_updated(p: &mut Process) -> bool { let old = p.updated; p.updated = false; old } -pub fn force_update(p: &mut Process) { +pub(crate) fn force_update(p: &mut Process) { p.updated = true; } + +pub(crate) fn update_process( + wrap: &Wrap, + pid: Pid, + taskallinfo_size: i32, + taskinfo_size: i32, + threadinfo_size: i32, + mib: &mut [c_int], + mut size: size_t, +) -> Result, ()> { + let mut proc_args = Vec::with_capacity(size as usize); + unsafe { + let mut thread_info = mem::zeroed::(); + let (user_time, system_time, thread_status) = if ffi::proc_pidinfo( + pid, + libc::PROC_PIDTHREADINFO, + 0, + &mut thread_info as *mut libc::proc_threadinfo as *mut c_void, + threadinfo_size, + ) != 0 + { + ( + thread_info.pth_user_time, + thread_info.pth_system_time, + Some(ThreadStatus::from(thread_info.pth_run_state)), + ) + } else { + (0, 0, None) + }; + if let Some(ref mut p) = (*wrap.0.get()).get_mut(&pid) { + if p.memory == 0 { + // We don't have access to this process' information. + force_update(p); + return Ok(None); + } + p.status = thread_status; + let mut task_info = mem::zeroed::(); + if ffi::proc_pidinfo( + pid, + libc::PROC_PIDTASKINFO, + 0, + &mut task_info as *mut libc::proc_taskinfo as *mut c_void, + taskinfo_size, + ) != taskinfo_size + { + return Err(()); + } + let task_time = + user_time + system_time + task_info.pti_total_user + task_info.pti_total_system; + let time = ffi::mach_absolute_time(); + compute_cpu_usage(p, time, task_time); + + p.memory = task_info.pti_resident_size >> 10; // divide by 1024 + p.virtual_memory = task_info.pti_virtual_size >> 10; // divide by 1024 + return Ok(None); + } + + let mut task_info = mem::zeroed::(); + if ffi::proc_pidinfo( + pid, + libc::PROC_PIDTASKALLINFO, + 0, + &mut task_info as *mut libc::proc_taskallinfo as *mut c_void, + taskallinfo_size as i32, + ) != taskallinfo_size as i32 + { + match Command::new("/bin/ps") // not very nice, might be worth running a which first. + .arg("wwwe") + .arg("-o") + .arg("ppid=,command=") + .arg(pid.to_string().as_str()) + .output() + { + Ok(o) => { + let o = String::from_utf8(o.stdout).unwrap_or_else(|_| String::new()); + let o = o.split(' ').filter(|c| !c.is_empty()).collect::>(); + if o.len() < 2 { + return Err(()); + } + let mut command = parse_command_line(&o[1..]); + if let Some(ref mut x) = command.last_mut() { + **x = x.replace("\n", ""); + } + let p = match i32::from_str_radix(&o[0].replace("\n", ""), 10) { + Ok(x) => x, + _ => return Err(()), + }; + let exe = PathBuf::from(&command[0]); + let name = match exe.file_name() { + Some(x) => x.to_str().unwrap_or_else(|| "").to_owned(), + None => String::new(), + }; + return Ok(Some(Process::new_with( + pid, + if p == 0 { None } else { Some(p) }, + 0, + exe, + name, + command, + ))); + } + _ => { + return Err(()); + } + } + } + + let parent = match task_info.pbsd.pbi_ppid as Pid { + 0 => None, + p => Some(p), + }; + + let ptr: *mut u8 = proc_args.as_mut_slice().as_mut_ptr(); + mib[0] = libc::CTL_KERN; + mib[1] = libc::KERN_PROCARGS2; + mib[2] = pid as c_int; + /* + * /---------------\ 0x00000000 + * | ::::::::::::: | + * |---------------| <-- Beginning of data returned by sysctl() is here. + * | argc | + * |---------------| + * | exec_path | + * |---------------| + * | 0 | + * |---------------| + * | arg[0] | + * |---------------| + * | 0 | + * |---------------| + * | arg[n] | + * |---------------| + * | 0 | + * |---------------| + * | env[0] | + * |---------------| + * | 0 | + * |---------------| + * | env[n] | + * |---------------| + * | ::::::::::::: | + * |---------------| <-- Top of stack. + * : : + * : : + * \---------------/ 0xffffffff + */ + if libc::sysctl( + mib.as_mut_ptr(), + 3, + ptr as *mut c_void, + &mut size, + ::std::ptr::null_mut(), + 0, + ) == -1 + { + return Err(()); // not enough rights I assume? + } + let mut n_args: c_int = 0; + libc::memcpy( + (&mut n_args) as *mut c_int as *mut c_void, + ptr as *const c_void, + mem::size_of::(), + ); + + let mut cp = ptr.add(mem::size_of::()); + let mut start = cp; + + let mut p = if cp < ptr.add(size) { + while cp < ptr.add(size) && *cp != 0 { + cp = cp.offset(1); + } + let exe = Path::new(get_unchecked_str(cp, start).as_str()).to_path_buf(); + let name = exe + .file_name() + .unwrap_or_else(|| OsStr::new("")) + .to_str() + .unwrap_or_else(|| "") + .to_owned(); + while cp < ptr.add(size) && *cp == 0 { + cp = cp.offset(1); + } + start = cp; + let mut c = 0; + let mut cmd = Vec::with_capacity(n_args as usize); + while c < n_args && cp < ptr.add(size) { + if *cp == 0 { + c += 1; + cmd.push(get_unchecked_str(cp, start)); + start = cp.offset(1); + } + cp = cp.offset(1); + } + + #[inline] + fn do_nothing(_: &str, _: &mut PathBuf, _: &mut bool) {} + #[inline] + fn do_something(env: &str, root: &mut PathBuf, check: &mut bool) { + if *check && env.starts_with("PATH=") { + *check = false; + *root = Path::new(&env[6..]).to_path_buf(); + } + } + + #[inline] + unsafe fn get_environ( + ptr: *mut u8, + mut cp: *mut u8, + size: size_t, + mut root: PathBuf, + callback: F, + ) -> (Vec, PathBuf) { + let mut environ = Vec::with_capacity(10); + let mut start = cp; + let mut check = true; + while cp < ptr.add(size) { + if *cp == 0 { + if cp == start { + break; + } + let e = get_unchecked_str(cp, start); + callback(&e, &mut root, &mut check); + environ.push(e); + start = cp.offset(1); + } + cp = cp.offset(1); + } + (environ, root) + } + + let (environ, root) = if exe.is_absolute() { + if let Some(parent) = exe.parent() { + get_environ(ptr, cp, size, parent.to_path_buf(), do_nothing) + } else { + get_environ(ptr, cp, size, PathBuf::new(), do_something) + } + } else { + get_environ(ptr, cp, size, PathBuf::new(), do_something) + }; + + Process::new_with2( + pid, + parent, + task_info.pbsd.pbi_start_tvsec, + exe, + name, + parse_command_line(&cmd), + environ, + root, + ) + } else { + Process::new(pid, parent, task_info.pbsd.pbi_start_tvsec) + }; + + p.memory = task_info.ptinfo.pti_resident_size >> 10; // divide by 1024 + p.virtual_memory = task_info.ptinfo.pti_virtual_size >> 10; // divide by 1024 + + p.uid = task_info.pbsd.pbi_uid; + p.gid = task_info.pbsd.pbi_gid; + p.process_status = ProcessStatus::from(task_info.pbsd.pbi_status); + + Ok(Some(p)) + } +} + +pub(crate) fn get_proc_list() -> Option> { + let count = unsafe { ffi::proc_listallpids(::std::ptr::null_mut(), 0) }; + if count < 1 { + return None; + } + let mut pids: Vec = Vec::with_capacity(count as usize); + unsafe { + pids.set_len(count as usize); + } + let count = count * mem::size_of::() as i32; + let x = unsafe { ffi::proc_listallpids(pids.as_mut_ptr() as *mut c_void, count) }; + + if x < 1 || x as usize >= pids.len() { + None + } else { + unsafe { + pids.set_len(x as usize); + } + Some(pids) + } +} + +unsafe fn get_unchecked_str(cp: *mut u8, start: *mut u8) -> String { + let len = cp as usize - start as usize; + let part = Vec::from_raw_parts(start, len, len); + let tmp = String::from_utf8_unchecked(part.clone()); + mem::forget(part); + tmp +} + +fn parse_command_line + Borrow>(cmd: &[T]) -> Vec { + let mut x = 0; + let mut command = Vec::with_capacity(cmd.len()); + while x < cmd.len() { + let mut y = x; + if cmd[y].starts_with('\'') || cmd[y].starts_with('"') { + let c = if cmd[y].starts_with('\'') { '\'' } else { '"' }; + while y < cmd.len() && !cmd[y].ends_with(c) { + y += 1; + } + command.push(cmd[x..y].join(" ")); + x = y; + } else { + command.push(cmd[x].to_owned()); + } + x += 1; + } + command +} diff --git a/src/mac/system.rs b/src/mac/system.rs index 455c0a80e..c1f5cf217 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -13,14 +13,9 @@ use sys::processor::*; use {DiskExt, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; -use std::borrow::Borrow; use std::cell::UnsafeCell; use std::collections::HashMap; -use std::ffi::OsStr; use std::mem; -use std::ops::Deref; -use std::path::{Path, PathBuf}; -use std::process::Command; use std::sync::Arc; use sys::processor; @@ -90,14 +85,6 @@ fn get_io_service_connection() -> Option { } } -unsafe fn get_unchecked_str(cp: *mut u8, start: *mut u8) -> String { - let len = cp as usize - start as usize; - let part = Vec::from_raw_parts(start, len, len); - let tmp = String::from_utf8_unchecked(part.clone()); - mem::forget(part); - tmp -} - fn get_uptime() -> u64 { let mut boottime: libc::timeval = unsafe { mem::zeroed() }; let mut len = mem::size_of::(); @@ -121,316 +108,11 @@ fn get_uptime() -> u64 { unsafe { libc::difftime(csec, bsec) as u64 } } -fn parse_command_line + Borrow>(cmd: &[T]) -> Vec { - let mut x = 0; - let mut command = Vec::with_capacity(cmd.len()); - while x < cmd.len() { - let mut y = x; - if cmd[y].starts_with('\'') || cmd[y].starts_with('"') { - let c = if cmd[y].starts_with('\'') { '\'' } else { '"' }; - while y < cmd.len() && !cmd[y].ends_with(c) { - y += 1; - } - command.push(cmd[x..y].join(" ")); - x = y; - } else { - command.push(cmd[x].to_owned()); - } - x += 1; - } - command -} - -struct Wrap<'a>(UnsafeCell<&'a mut HashMap>); +pub(crate) struct Wrap<'a>(pub UnsafeCell<&'a mut HashMap>); unsafe impl<'a> Send for Wrap<'a> {} unsafe impl<'a> Sync for Wrap<'a> {} -fn update_process( - wrap: &Wrap, - pid: Pid, - taskallinfo_size: i32, - taskinfo_size: i32, - threadinfo_size: i32, - mib: &mut [c_int], - mut size: size_t, -) -> Result, ()> { - let mut proc_args = Vec::with_capacity(size as usize); - unsafe { - let mut thread_info = mem::zeroed::(); - let (user_time, system_time, thread_status) = if ffi::proc_pidinfo( - pid, - libc::PROC_PIDTHREADINFO, - 0, - &mut thread_info as *mut libc::proc_threadinfo as *mut c_void, - threadinfo_size, - ) != 0 - { - ( - thread_info.pth_user_time, - thread_info.pth_system_time, - Some(ThreadStatus::from(thread_info.pth_run_state)), - ) - } else { - (0, 0, None) - }; - if let Some(ref mut p) = (*wrap.0.get()).get_mut(&pid) { - if p.memory == 0 { - // We don't have access to this process' information. - force_update(p); - return Ok(None); - } - p.status = thread_status; - let mut task_info = mem::zeroed::(); - if ffi::proc_pidinfo( - pid, - libc::PROC_PIDTASKINFO, - 0, - &mut task_info as *mut libc::proc_taskinfo as *mut c_void, - taskinfo_size, - ) != taskinfo_size - { - return Err(()); - } - let task_time = - user_time + system_time + task_info.pti_total_user + task_info.pti_total_system; - let time = ffi::mach_absolute_time(); - compute_cpu_usage(p, time, task_time); - - p.memory = task_info.pti_resident_size >> 10; // divide by 1024 - p.virtual_memory = task_info.pti_virtual_size >> 10; // divide by 1024 - return Ok(None); - } - - let mut task_info = mem::zeroed::(); - if ffi::proc_pidinfo( - pid, - libc::PROC_PIDTASKALLINFO, - 0, - &mut task_info as *mut libc::proc_taskallinfo as *mut c_void, - taskallinfo_size as i32, - ) != taskallinfo_size as i32 - { - match Command::new("/bin/ps") // not very nice, might be worth running a which first. - .arg("wwwe") - .arg("-o") - .arg("ppid=,command=") - .arg(pid.to_string().as_str()) - .output() - { - Ok(o) => { - let o = String::from_utf8(o.stdout).unwrap_or_else(|_| String::new()); - let o = o.split(' ').filter(|c| !c.is_empty()).collect::>(); - if o.len() < 2 { - return Err(()); - } - let mut command = parse_command_line(&o[1..]); - if let Some(ref mut x) = command.last_mut() { - **x = x.replace("\n", ""); - } - let p = match i32::from_str_radix(&o[0].replace("\n", ""), 10) { - Ok(x) => x, - _ => return Err(()), - }; - let exe = PathBuf::from(&command[0]); - let name = match exe.file_name() { - Some(x) => x.to_str().unwrap_or_else(|| "").to_owned(), - None => String::new(), - }; - return Ok(Some(Process::new_with( - pid, - if p == 0 { None } else { Some(p) }, - 0, - exe, - name, - command, - ))); - } - _ => { - return Err(()); - } - } - } - - let parent = match task_info.pbsd.pbi_ppid as Pid { - 0 => None, - p => Some(p), - }; - - let ptr: *mut u8 = proc_args.as_mut_slice().as_mut_ptr(); - mib[0] = libc::CTL_KERN; - mib[1] = libc::KERN_PROCARGS2; - mib[2] = pid as c_int; - /* - * /---------------\ 0x00000000 - * | ::::::::::::: | - * |---------------| <-- Beginning of data returned by sysctl() is here. - * | argc | - * |---------------| - * | exec_path | - * |---------------| - * | 0 | - * |---------------| - * | arg[0] | - * |---------------| - * | 0 | - * |---------------| - * | arg[n] | - * |---------------| - * | 0 | - * |---------------| - * | env[0] | - * |---------------| - * | 0 | - * |---------------| - * | env[n] | - * |---------------| - * | ::::::::::::: | - * |---------------| <-- Top of stack. - * : : - * : : - * \---------------/ 0xffffffff - */ - if libc::sysctl( - mib.as_mut_ptr(), - 3, - ptr as *mut c_void, - &mut size, - ::std::ptr::null_mut(), - 0, - ) == -1 - { - return Err(()); // not enough rights I assume? - } - let mut n_args: c_int = 0; - libc::memcpy( - (&mut n_args) as *mut c_int as *mut c_void, - ptr as *const c_void, - mem::size_of::(), - ); - - let mut cp = ptr.add(mem::size_of::()); - let mut start = cp; - - let mut p = if cp < ptr.add(size) { - while cp < ptr.add(size) && *cp != 0 { - cp = cp.offset(1); - } - let exe = Path::new(get_unchecked_str(cp, start).as_str()).to_path_buf(); - let name = exe - .file_name() - .unwrap_or_else(|| OsStr::new("")) - .to_str() - .unwrap_or_else(|| "") - .to_owned(); - while cp < ptr.add(size) && *cp == 0 { - cp = cp.offset(1); - } - start = cp; - let mut c = 0; - let mut cmd = Vec::with_capacity(n_args as usize); - while c < n_args && cp < ptr.add(size) { - if *cp == 0 { - c += 1; - cmd.push(get_unchecked_str(cp, start)); - start = cp.offset(1); - } - cp = cp.offset(1); - } - - #[inline] - fn do_nothing(_: &str, _: &mut PathBuf, _: &mut bool) {} - #[inline] - fn do_something(env: &str, root: &mut PathBuf, check: &mut bool) { - if *check && env.starts_with("PATH=") { - *check = false; - *root = Path::new(&env[6..]).to_path_buf(); - } - } - - #[inline] - unsafe fn get_environ( - ptr: *mut u8, - mut cp: *mut u8, - size: size_t, - mut root: PathBuf, - callback: F, - ) -> (Vec, PathBuf) { - let mut environ = Vec::with_capacity(10); - let mut start = cp; - let mut check = true; - while cp < ptr.add(size) { - if *cp == 0 { - if cp == start { - break; - } - let e = get_unchecked_str(cp, start); - callback(&e, &mut root, &mut check); - environ.push(e); - start = cp.offset(1); - } - cp = cp.offset(1); - } - (environ, root) - } - - let (environ, root) = if exe.is_absolute() { - if let Some(parent) = exe.parent() { - get_environ(ptr, cp, size, parent.to_path_buf(), do_nothing) - } else { - get_environ(ptr, cp, size, PathBuf::new(), do_something) - } - } else { - get_environ(ptr, cp, size, PathBuf::new(), do_something) - }; - - Process::new_with2( - pid, - parent, - task_info.pbsd.pbi_start_tvsec, - exe, - name, - parse_command_line(&cmd), - environ, - root, - ) - } else { - Process::new(pid, parent, task_info.pbsd.pbi_start_tvsec) - }; - - p.memory = task_info.ptinfo.pti_resident_size >> 10; // divide by 1024 - p.virtual_memory = task_info.ptinfo.pti_virtual_size >> 10; // divide by 1024 - - p.uid = task_info.pbsd.pbi_uid; - p.gid = task_info.pbsd.pbi_gid; - p.process_status = ProcessStatus::from(task_info.pbsd.pbi_status); - - Ok(Some(p)) - } -} - -fn get_proc_list() -> Option> { - let count = unsafe { ffi::proc_listallpids(::std::ptr::null_mut(), 0) }; - if count < 1 { - return None; - } - let mut pids: Vec = Vec::with_capacity(count as usize); - unsafe { - pids.set_len(count as usize); - } - let count = count * mem::size_of::() as i32; - let x = unsafe { ffi::proc_listallpids(pids.as_mut_ptr() as *mut c_void, count) }; - - if x < 1 || x as usize >= pids.len() { - None - } else { - unsafe { - pids.set_len(x as usize); - } - Some(pids) - } -} - fn get_arg_max() -> usize { let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_ARGMAX, 0]; let mut arg_max = 0i32; From ed3d68d4f5e2bfa46893fbcba8546b26d8844227 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Jan 2020 22:44:14 +0100 Subject: [PATCH 050/171] Move functions after struct declaration --- src/mac/process.rs | 2 +- src/mac/system.rs | 196 ++++++++++++++++++++++----------------------- 2 files changed, 99 insertions(+), 99 deletions(-) diff --git a/src/mac/process.rs b/src/mac/process.rs index 2b6cbc1de..004e607b2 100644 --- a/src/mac/process.rs +++ b/src/mac/process.rs @@ -17,8 +17,8 @@ use libc::{c_int, c_void, gid_t, kill, size_t, uid_t}; use Pid; use ProcessExt; -use sys::system::Wrap; use sys::ffi; +use sys::system::Wrap; /// Enum describing the different status of a process. #[derive(Clone, Copy, Debug)] diff --git a/src/mac/system.rs b/src/mac/system.rs index c1f5cf217..2469362af 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -50,109 +50,11 @@ impl Drop for System { } } -// code from https://github.com/Chris911/iStats -fn get_io_service_connection() -> Option { - let mut master_port: ffi::mach_port_t = 0; - let mut iterator: ffi::io_iterator_t = 0; - - unsafe { - ffi::IOMasterPort(ffi::MACH_PORT_NULL, &mut master_port); - - let matching_dictionary = ffi::IOServiceMatching(b"AppleSMC\0".as_ptr() as *const i8); - let result = - ffi::IOServiceGetMatchingServices(master_port, matching_dictionary, &mut iterator); - if result != ffi::KIO_RETURN_SUCCESS { - //println!("Error: IOServiceGetMatchingServices() = {}", result); - return None; - } - - let device = ffi::IOIteratorNext(iterator); - ffi::IOObjectRelease(iterator); - if device == 0 { - //println!("Error: no SMC found"); - return None; - } - - let mut conn = 0; - let result = ffi::IOServiceOpen(device, ffi::mach_task_self(), 0, &mut conn); - ffi::IOObjectRelease(device); - if result != ffi::KIO_RETURN_SUCCESS { - //println!("Error: IOServiceOpen() = {}", result); - return None; - } - - Some(conn) - } -} - -fn get_uptime() -> u64 { - let mut boottime: libc::timeval = unsafe { mem::zeroed() }; - let mut len = mem::size_of::(); - let mut mib: [c_int; 2] = [libc::CTL_KERN, libc::KERN_BOOTTIME]; - unsafe { - if libc::sysctl( - mib.as_mut_ptr(), - 2, - &mut boottime as *mut libc::timeval as *mut _, - &mut len, - ::std::ptr::null_mut(), - 0, - ) < 0 - { - return 0; - } - } - let bsec = boottime.tv_sec; - let csec = unsafe { libc::time(::std::ptr::null_mut()) }; - - unsafe { libc::difftime(csec, bsec) as u64 } -} - pub(crate) struct Wrap<'a>(pub UnsafeCell<&'a mut HashMap>); unsafe impl<'a> Send for Wrap<'a> {} unsafe impl<'a> Sync for Wrap<'a> {} -fn get_arg_max() -> usize { - let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_ARGMAX, 0]; - let mut arg_max = 0i32; - let mut size = mem::size_of::(); - unsafe { - if libc::sysctl( - mib.as_mut_ptr(), - 2, - (&mut arg_max) as *mut i32 as *mut c_void, - &mut size, - ::std::ptr::null_mut(), - 0, - ) == -1 - { - 4096 // We default to this value - } else { - arg_max as usize - } - } -} - -unsafe fn get_sys_value( - high: u32, - low: u32, - mut len: usize, - value: *mut c_void, - mib: &mut [i32; 2], -) -> bool { - mib[0] = high as i32; - mib[1] = low as i32; - libc::sysctl( - mib.as_mut_ptr(), - 2, - value, - &mut len as *mut usize, - ::std::ptr::null_mut(), - 0, - ) == 0 -} - impl System { fn clear_procs(&mut self) { let mut to_delete = Vec::new(); @@ -515,3 +417,101 @@ impl Default for System { System::new() } } + +// code from https://github.com/Chris911/iStats +fn get_io_service_connection() -> Option { + let mut master_port: ffi::mach_port_t = 0; + let mut iterator: ffi::io_iterator_t = 0; + + unsafe { + ffi::IOMasterPort(ffi::MACH_PORT_NULL, &mut master_port); + + let matching_dictionary = ffi::IOServiceMatching(b"AppleSMC\0".as_ptr() as *const i8); + let result = + ffi::IOServiceGetMatchingServices(master_port, matching_dictionary, &mut iterator); + if result != ffi::KIO_RETURN_SUCCESS { + //println!("Error: IOServiceGetMatchingServices() = {}", result); + return None; + } + + let device = ffi::IOIteratorNext(iterator); + ffi::IOObjectRelease(iterator); + if device == 0 { + //println!("Error: no SMC found"); + return None; + } + + let mut conn = 0; + let result = ffi::IOServiceOpen(device, ffi::mach_task_self(), 0, &mut conn); + ffi::IOObjectRelease(device); + if result != ffi::KIO_RETURN_SUCCESS { + //println!("Error: IOServiceOpen() = {}", result); + return None; + } + + Some(conn) + } +} + +fn get_uptime() -> u64 { + let mut boottime: libc::timeval = unsafe { mem::zeroed() }; + let mut len = mem::size_of::(); + let mut mib: [c_int; 2] = [libc::CTL_KERN, libc::KERN_BOOTTIME]; + unsafe { + if libc::sysctl( + mib.as_mut_ptr(), + 2, + &mut boottime as *mut libc::timeval as *mut _, + &mut len, + ::std::ptr::null_mut(), + 0, + ) < 0 + { + return 0; + } + } + let bsec = boottime.tv_sec; + let csec = unsafe { libc::time(::std::ptr::null_mut()) }; + + unsafe { libc::difftime(csec, bsec) as u64 } +} + +fn get_arg_max() -> usize { + let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_ARGMAX, 0]; + let mut arg_max = 0i32; + let mut size = mem::size_of::(); + unsafe { + if libc::sysctl( + mib.as_mut_ptr(), + 2, + (&mut arg_max) as *mut i32 as *mut c_void, + &mut size, + ::std::ptr::null_mut(), + 0, + ) == -1 + { + 4096 // We default to this value + } else { + arg_max as usize + } + } +} + +unsafe fn get_sys_value( + high: u32, + low: u32, + mut len: usize, + value: *mut c_void, + mib: &mut [i32; 2], +) -> bool { + mib[0] = high as i32; + mib[1] = low as i32; + libc::sysctl( + mib.as_mut_ptr(), + 2, + value, + &mut len as *mut usize, + ::std::ptr::null_mut(), + 0, + ) == 0 +} From 4a8e0f897c39af309390166b32026ea1268b0457 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 6 Jan 2020 01:35:01 +0100 Subject: [PATCH 051/171] Greatly improve refresh_processes performance and get more processes info --- src/mac/ffi.rs | 8 ++- src/mac/process.rs | 159 +++++++++++++++++++-------------------------- src/mac/system.rs | 18 ----- 3 files changed, 74 insertions(+), 111 deletions(-) diff --git a/src/mac/ffi.rs b/src/mac/ffi.rs index b53c24b3e..73a82df26 100644 --- a/src/mac/ffi.rs +++ b/src/mac/ffi.rs @@ -17,10 +17,11 @@ extern "C" { buffersize: c_int, ) -> c_int; pub fn proc_listallpids(buffer: *mut c_void, buffersize: c_int) -> c_int; + //pub fn proc_listpids(kind: u32, x: u32, buffer: *mut c_void, buffersize: c_int) -> c_int; //pub fn proc_name(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; //pub fn proc_regionfilename(pid: c_int, address: u64, buffer: *mut c_void, // buffersize: u32) -> c_int; - //pub fn proc_pidpath(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; + pub fn proc_pidpath(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; pub fn IOMasterPort(a: i32, b: *mut mach_port_t) -> i32; pub fn IOServiceMatching(a: *const c_char) -> *mut c_void; @@ -357,6 +358,9 @@ pub const CPU_STATE_NICE: u32 = 3; pub const CPU_STATE_MAX: usize = 4; pub const HW_MEMSIZE: u32 = 24; +//pub const PROC_ALL_PIDS: c_uint = 1; +pub const PROC_PIDTBSDINFO: c_int = 3; + //pub const TASK_THREAD_TIMES_INFO: u32 = 3; //pub const TASK_THREAD_TIMES_INFO_COUNT: u32 = 4; //pub const TASK_BASIC_INFO_64: u32 = 5; @@ -369,7 +373,7 @@ pub const KERNEL_INDEX_SMC: i32 = 2; pub const SMC_CMD_READ_KEYINFO: u8 = 9; pub const SMC_CMD_READ_BYTES: u8 = 5; -// pub const PROC_PIDPATHINFO_MAXSIZE: usize = 4096; +pub const PROC_PIDPATHINFO_MAXSIZE: u32 = 4096; pub const KIO_RETURN_SUCCESS: i32 = 0; #[allow(non_upper_case_globals)] diff --git a/src/mac/process.rs b/src/mac/process.rs index 004e607b2..11fe5ad6a 100644 --- a/src/mac/process.rs +++ b/src/mac/process.rs @@ -10,7 +10,6 @@ use std::fmt::{self, Debug, Formatter}; use std::mem; use std::ops::Deref; use std::path::{Path, PathBuf}; -use std::process::Command; use libc::{c_int, c_void, gid_t, kill, size_t, uid_t}; @@ -153,19 +152,16 @@ pub struct Process { } impl Process { - pub(crate) fn new_with( + pub(crate) fn new_empty( pid: Pid, - parent: Option, - start_time: u64, exe: PathBuf, name: String, - cmd: Vec, ) -> Process { Process { name, pid, - parent, - cmd, + parent: None, + cmd: Vec::new(), environ: Vec::new(), exe, cwd: PathBuf::new(), @@ -178,7 +174,7 @@ impl Process { old_utime: 0, old_stime: 0, updated: true, - start_time, + start_time: 0, uid: 0, gid: 0, process_status: ProcessStatus::Unknown(0), @@ -186,7 +182,7 @@ impl Process { } } - pub(crate) fn new_with2( + pub(crate) fn new_with( pid: Pid, parent: Option, start_time: u64, @@ -371,52 +367,54 @@ pub(crate) fn force_update(p: &mut Process) { p.updated = true; } +unsafe fn get_task_info(pid: Pid) -> libc::proc_taskinfo { + let mut task_info = mem::zeroed::(); + // If it doesn't work, we just don't have memory information for this process + // so it's "fine". + ffi::proc_pidinfo( + pid, + libc::PROC_PIDTASKINFO, + 0, + &mut task_info as *mut libc::proc_taskinfo as *mut c_void, + mem::size_of::() as _, + ); + task_info +} + pub(crate) fn update_process( wrap: &Wrap, pid: Pid, - taskallinfo_size: i32, - taskinfo_size: i32, - threadinfo_size: i32, - mib: &mut [c_int], mut size: size_t, ) -> Result, ()> { + let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_ARGMAX, 0]; let mut proc_args = Vec::with_capacity(size as usize); + unsafe { - let mut thread_info = mem::zeroed::(); - let (user_time, system_time, thread_status) = if ffi::proc_pidinfo( - pid, - libc::PROC_PIDTHREADINFO, - 0, - &mut thread_info as *mut libc::proc_threadinfo as *mut c_void, - threadinfo_size, - ) != 0 - { - ( - thread_info.pth_user_time, - thread_info.pth_system_time, - Some(ThreadStatus::from(thread_info.pth_run_state)), - ) - } else { - (0, 0, None) - }; if let Some(ref mut p) = (*wrap.0.get()).get_mut(&pid) { if p.memory == 0 { // We don't have access to this process' information. force_update(p); return Ok(None); } - p.status = thread_status; - let mut task_info = mem::zeroed::(); - if ffi::proc_pidinfo( + let task_info = get_task_info(pid); + let mut thread_info = mem::zeroed::(); + let (user_time, system_time, thread_status) = if ffi::proc_pidinfo( pid, - libc::PROC_PIDTASKINFO, + libc::PROC_PIDTHREADINFO, 0, - &mut task_info as *mut libc::proc_taskinfo as *mut c_void, - taskinfo_size, - ) != taskinfo_size + &mut thread_info as *mut libc::proc_threadinfo as *mut c_void, + mem::size_of::() as _, + ) != 0 { - return Err(()); - } + ( + thread_info.pth_user_time, + thread_info.pth_system_time, + Some(ThreadStatus::from(thread_info.pth_run_state)), + ) + } else { + (0, 0, None) + }; + p.status = thread_status; let task_time = user_time + system_time + task_info.pti_total_user + task_info.pti_total_system; let time = ffi::mach_absolute_time(); @@ -427,57 +425,34 @@ pub(crate) fn update_process( return Ok(None); } - let mut task_info = mem::zeroed::(); + let mut info = mem::zeroed::(); if ffi::proc_pidinfo( pid, - libc::PROC_PIDTASKALLINFO, + ffi::PROC_PIDTBSDINFO, 0, - &mut task_info as *mut libc::proc_taskallinfo as *mut c_void, - taskallinfo_size as i32, - ) != taskallinfo_size as i32 + &mut info as *mut _ as *mut _, + mem::size_of::() as _, + ) != mem::size_of::() as _ { - match Command::new("/bin/ps") // not very nice, might be worth running a which first. - .arg("wwwe") - .arg("-o") - .arg("ppid=,command=") - .arg(pid.to_string().as_str()) - .output() - { - Ok(o) => { - let o = String::from_utf8(o.stdout).unwrap_or_else(|_| String::new()); - let o = o.split(' ').filter(|c| !c.is_empty()).collect::>(); - if o.len() < 2 { - return Err(()); - } - let mut command = parse_command_line(&o[1..]); - if let Some(ref mut x) = command.last_mut() { - **x = x.replace("\n", ""); - } - let p = match i32::from_str_radix(&o[0].replace("\n", ""), 10) { - Ok(x) => x, - _ => return Err(()), - }; - let exe = PathBuf::from(&command[0]); - let name = match exe.file_name() { - Some(x) => x.to_str().unwrap_or_else(|| "").to_owned(), - None => String::new(), - }; - return Ok(Some(Process::new_with( - pid, - if p == 0 { None } else { Some(p) }, - 0, - exe, - name, - command, - ))); - } - _ => { - return Err(()); + let mut buffer: Vec = Vec::with_capacity(ffi::PROC_PIDPATHINFO_MAXSIZE as _); + match ffi::proc_pidpath(pid, buffer.as_mut_ptr() as *mut _, ffi::PROC_PIDPATHINFO_MAXSIZE) { + x if x > 0 => { + buffer.set_len(x as _); + let tmp = String::from_utf8_unchecked(buffer); + let exe = PathBuf::from(tmp); + let name = exe + .file_name() + .unwrap_or_else(|| OsStr::new("")) + .to_str() + .unwrap_or_else(|| "") + .to_owned(); + return Ok(Some(Process::new_empty(pid, exe, name))); } + _ => {} } + return Err(()); } - - let parent = match task_info.pbsd.pbi_ppid as Pid { + let parent = match info.pbi_ppid as i32 { 0 => None, p => Some(p), }; @@ -609,10 +584,10 @@ pub(crate) fn update_process( get_environ(ptr, cp, size, PathBuf::new(), do_something) }; - Process::new_with2( + Process::new_with( pid, parent, - task_info.pbsd.pbi_start_tvsec, + info.pbi_start_tvsec, exe, name, parse_command_line(&cmd), @@ -620,15 +595,17 @@ pub(crate) fn update_process( root, ) } else { - Process::new(pid, parent, task_info.pbsd.pbi_start_tvsec) + Process::new(pid, parent, info.pbi_start_tvsec) }; - p.memory = task_info.ptinfo.pti_resident_size >> 10; // divide by 1024 - p.virtual_memory = task_info.ptinfo.pti_virtual_size >> 10; // divide by 1024 + let task_info = get_task_info(pid); + + p.memory = task_info.pti_resident_size >> 10; // divide by 1024 + p.virtual_memory = task_info.pti_virtual_size >> 10; // divide by 1024 - p.uid = task_info.pbsd.pbi_uid; - p.gid = task_info.pbsd.pbi_gid; - p.process_status = ProcessStatus::from(task_info.pbsd.pbi_status); + p.uid = info.pbi_uid; + p.gid = info.pbi_gid; + p.process_status = ProcessStatus::from(info.pbi_status); Ok(Some(p)) } diff --git a/src/mac/system.rs b/src/mac/system.rs index 2469362af..2e5610fe9 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -284,23 +284,14 @@ impl SystemExt for System { return; } if let Some(pids) = get_proc_list() { - let taskallinfo_size = mem::size_of::() as i32; - let taskinfo_size = mem::size_of::() as i32; - let threadinfo_size = mem::size_of::() as i32; let arg_max = get_arg_max(); - let entries: Vec = { let wrap = &Wrap(UnsafeCell::new(&mut self.process_list)); pids.par_iter() .flat_map(|pid| { - let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_ARGMAX, 0]; match update_process( wrap, *pid, - taskallinfo_size, - taskinfo_size, - threadinfo_size, - &mut mib, arg_max as size_t, ) { Ok(x) => x, @@ -317,21 +308,12 @@ impl SystemExt for System { } fn refresh_process(&mut self, pid: Pid) -> bool { - let taskallinfo_size = mem::size_of::() as i32; - let taskinfo_size = mem::size_of::() as i32; - let threadinfo_size = mem::size_of::() as i32; - - let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_ARGMAX, 0]; let arg_max = get_arg_max(); match { let wrap = Wrap(UnsafeCell::new(&mut self.process_list)); update_process( &wrap, pid, - taskallinfo_size, - taskinfo_size, - threadinfo_size, - &mut mib, arg_max as size_t, ) } { From e85f719eaa0ac5fa01fe1481ad7299a696a34591 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 6 Jan 2020 01:41:49 +0100 Subject: [PATCH 052/171] Fix race condition on disk types --- Cargo.toml | 2 +- src/mac/disk.rs | 59 ++++++++++++++++--------------------------------- 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 886563236..9bb39fc61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ ntapi = "0.3" [target.'cfg(not(any(target_os = "unknown", target_arch = "wasm32")))'.dependencies] libc = "0.2" -[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies] +[target.'cfg(unix)'.dependencies] once_cell = "1.0" [lib] diff --git a/src/mac/disk.rs b/src/mac/disk.rs index 70d0261c7..00ba4c7d6 100644 --- a/src/mac/disk.rs +++ b/src/mac/disk.rs @@ -8,7 +8,6 @@ use utils; use DiskExt; use libc::{c_char, c_void, statfs}; -use std::cell::RefCell; use std::collections::HashMap; use std::ffi::{OsStr, OsString}; use std::fmt::{Debug, Error, Formatter}; @@ -114,26 +113,8 @@ macro_rules! unwrapper { }}; } -struct Syncer(RefCell>>); - -impl Syncer { - fn get_disk_types) -> Vec>( - &self, - callback: F, - ) -> Vec { - if self.0.borrow().is_none() { - *self.0.borrow_mut() = Some(get_disk_types()); - } - match &*self.0.borrow() { - Some(x) => callback(x), - None => Vec::new(), - } - } -} - -unsafe impl Sync for Syncer {} - -static DISK_TYPES: Syncer = Syncer(RefCell::new(None)); +static DISK_TYPES: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| get_disk_types()); fn get_disk_types() -> HashMap { let mut master_port: ffi::mach_port_t = 0; @@ -200,27 +181,25 @@ fn make_name(v: &[u8]) -> OsString { } pub(crate) fn get_disks() -> Vec { - DISK_TYPES.get_disk_types(|disk_types| { - unwrapper!(fs::read_dir("/Volumes"), Vec::new()) - .flat_map(|x| { - if let Ok(ref entry) = x { - let mount_point = utils::realpath(&entry.path()); - if mount_point.as_os_str().is_empty() { - None - } else { - let name = entry.path().file_name()?.to_owned(); - let type_ = disk_types - .get(&name) - .cloned() - .unwrap_or(DiskType::Unknown(-2)); - Some(new_disk(name, &mount_point, type_)) - } - } else { + unwrapper!(fs::read_dir("/Volumes"), Vec::new()) + .flat_map(|x| { + if let Ok(ref entry) = x { + let mount_point = utils::realpath(&entry.path()); + if mount_point.as_os_str().is_empty() { None + } else { + let name = entry.path().file_name()?.to_owned(); + let type_ = DISK_TYPES + .get(&name) + .cloned() + .unwrap_or(DiskType::Unknown(-2)); + Some(new_disk(name, &mount_point, type_)) } - }) - .collect() - }) + } else { + None + } + }) + .collect() } unsafe fn check_value(dict: ffi::CFMutableDictionaryRef, key: &[u8]) -> bool { From 8ffb4b564ae39cd8768068bdf694b1f6aa47b96b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 6 Jan 2020 01:49:30 +0100 Subject: [PATCH 053/171] Update OSX benchmark results --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 662c34650..74c56f8ee 100644 --- a/README.md +++ b/README.md @@ -134,17 +134,17 @@ test bench_refresh_temperatures ... bench: 1 ns/iter (+/- 0)
```text -test bench_new ... bench: 64,062,254 ns/iter (+/- 8,845,126) -test bench_refresh_all ... bench: 4,285,670 ns/iter (+/- 467,963) -test bench_refresh_cpu ... bench: 10,712 ns/iter (+/- 1,493) -test bench_refresh_disk_lists ... bench: 837,489 ns/iter (+/- 48,593) -test bench_refresh_disks ... bench: 956 ns/iter (+/- 128) -test bench_refresh_memory ... bench: 3,327 ns/iter (+/- 462) -test bench_refresh_network ... bench: 34,465 ns/iter (+/- 5,228) -test bench_refresh_process ... bench: 3,935 ns/iter (+/- 1,135) -test bench_refresh_processes ... bench: 2,489,203 ns/iter (+/- 140,567) -test bench_refresh_system ... bench: 741,774 ns/iter (+/- 335,431) -test bench_refresh_temperatures ... bench: 680,362 ns/iter (+/- 167,343) +test bench_new ... bench: 4,713,851 ns/iter (+/- 1,080,986) +test bench_refresh_all ... bench: 1,639,098 ns/iter (+/- 191,147) +test bench_refresh_cpu ... bench: 10,651 ns/iter (+/- 1,635) +test bench_refresh_disk_lists ... bench: 29,327 ns/iter (+/- 3,104) +test bench_refresh_disks ... bench: 942 ns/iter (+/- 79) +test bench_refresh_memory ... bench: 3,417 ns/iter (+/- 654) +test bench_refresh_network ... bench: 34,497 ns/iter (+/- 2,681) +test bench_refresh_process ... bench: 4,272 ns/iter (+/- 549) +test bench_refresh_processes ... bench: 782,977 ns/iter (+/- 30,958) +test bench_refresh_system ... bench: 336,008 ns/iter (+/- 43,015) +test bench_refresh_temperatures ... bench: 294,323 ns/iter (+/- 41,612) ```
From 223a5f5e1fcad115206097042800c2732d41e5af Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 6 Jan 2020 03:40:27 +0100 Subject: [PATCH 054/171] Update crate version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9bb39fc61..504960f24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sysinfo" -version = "0.10.3" +version = "0.10.4" authors = ["Guillaume Gomez "] description = "Library to handle processes" From 5aac788bf5e5db67c38e9dca83da2a6510eac842 Mon Sep 17 00:00:00 2001 From: Simon Smith Date: Thu, 9 Jan 2020 16:57:53 +0100 Subject: [PATCH 055/171] Replace all "kB" with "KiB" (not including the variable `page_size_kb`) This should be the correct unit, but I have not verified it for sysinfo::ProcessExt::virtual_memory. --- README.md | 10 ++++------ examples/src/simple.rs | 8 ++++---- src/linux/process.rs | 4 ++-- src/mac/process.rs | 4 ++-- src/sysinfo.rs | 8 ++++---- src/traits.rs | 4 ++-- src/windows/process.rs | 4 ++-- src/windows/system.rs | 2 +- 8 files changed, 21 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 74c56f8ee..3368c3f35 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,6 @@ cargo build --target=armv7-unknown-linux-gnueabihf You have an example into the `examples` folder. Just run `cargo run` inside the `examples` folder to start it. Otherwise, here is a little code sample: ```rust -extern crate sysinfo; - use sysinfo::{NetworkExt, System, SystemExt}; let mut sys = System::new(); @@ -56,10 +54,10 @@ for component in sys.get_components_list() { } // Memory information: -println!("total memory: {} kB", sys.get_total_memory()); -println!("used memory : {} kB", sys.get_used_memory()); -println!("total swap : {} kB", sys.get_total_swap()); -println!("used swap : {} kB", sys.get_used_swap()); +println!("total memory: {} KiB", sys.get_total_memory()); +println!("used memory : {} KiB", sys.get_used_memory()); +println!("total swap : {} KiB", sys.get_total_swap()); +println!("used swap : {} KiB", sys.get_used_swap()); // Number of processors println!("NB processors: {}", sys.get_processor_list().len()); diff --git a/examples/src/simple.rs b/examples/src/simple.rs index d16b488ae..a623ce9ab 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -67,10 +67,10 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { } } "memory" => { - writeln!(&mut io::stdout(), "total memory: {} kB", sys.get_total_memory()); - writeln!(&mut io::stdout(), "used memory : {} kB", sys.get_used_memory()); - writeln!(&mut io::stdout(), "total swap : {} kB", sys.get_total_swap()); - writeln!(&mut io::stdout(), "used swap : {} kB", sys.get_used_swap()); + writeln!(&mut io::stdout(), "total memory: {} KiB", sys.get_total_memory()); + writeln!(&mut io::stdout(), "used memory : {} KiB", sys.get_used_memory()); + writeln!(&mut io::stdout(), "total swap : {} KiB", sys.get_total_swap()); + writeln!(&mut io::stdout(), "used swap : {} KiB", sys.get_used_swap()); } "quit" | "exit" => return true, "all" => { diff --git a/src/linux/process.rs b/src/linux/process.rs index e61b35082..c15543e41 100644 --- a/src/linux/process.rs +++ b/src/linux/process.rs @@ -246,8 +246,8 @@ impl Debug for Process { writeln!(f, "executable path: {:?}", self.exe); writeln!(f, "current working directory: {:?}", self.cwd); writeln!(f, "owner/group: {}:{}", self.uid, self.gid); - writeln!(f, "memory usage: {} kB", self.memory); - writeln!(f, "virtual memory usage: {} kB", self.virtual_memory); + writeln!(f, "memory usage: {} KiB", self.memory); + writeln!(f, "virtual memory usage: {} KiB", self.virtual_memory); writeln!(f, "cpu usage: {}%", self.cpu_usage); writeln!(f, "status: {}", self.status); write!(f, "root path: {:?}", self.root) diff --git a/src/mac/process.rs b/src/mac/process.rs index 11fe5ad6a..b36796ad6 100644 --- a/src/mac/process.rs +++ b/src/mac/process.rs @@ -321,8 +321,8 @@ impl Debug for Process { writeln!(f, "executable path: {:?}", self.exe); writeln!(f, "current working directory: {:?}", self.cwd); writeln!(f, "owner/group: {}:{}", self.uid, self.gid); - writeln!(f, "memory usage: {} kB", self.memory); - writeln!(f, "virtual memory usage: {} kB", self.virtual_memory); + writeln!(f, "memory usage: {} KiB", self.memory); + writeln!(f, "virtual memory usage: {} KiB", self.virtual_memory); writeln!(f, "cpu usage: {}%", self.cpu_usage); writeln!( f, diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 998909275..8a4ab3426 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -35,10 +35,10 @@ //! } //! //! // And finally the RAM and SWAP information: -//! println!("total memory: {} kB", system.get_total_memory()); -//! println!("used memory : {} kB", system.get_used_memory()); -//! println!("total swap : {} kB", system.get_total_swap()); -//! println!("used swap : {} kB", system.get_used_swap()); +//! println!("total memory: {} KiB", system.get_total_memory()); +//! println!("used memory : {} KiB", system.get_used_memory()); +//! println!("total swap : {} KiB", system.get_total_swap()); +//! println!("used swap : {} KiB", system.get_used_swap()); //! ``` #![crate_name = "sysinfo"] diff --git a/src/traits.rs b/src/traits.rs index 54f1447d4..b65fbf8ee 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -76,10 +76,10 @@ pub trait ProcessExt { /// Always empty on Windows. fn root(&self) -> &Path; - /// Returns the memory usage (in kB). + /// Returns the memory usage (in KiB). fn memory(&self) -> u64; - /// Returns the virtual memory usage (in kB). + /// Returns the virtual memory usage (in KiB). fn virtual_memory(&self) -> u64; /// Returns the parent pid. diff --git a/src/windows/process.rs b/src/windows/process.rs index 8b6ac646e..fbb0b02ab 100644 --- a/src/windows/process.rs +++ b/src/windows/process.rs @@ -374,8 +374,8 @@ impl Debug for Process { } writeln!(f, "executable path: {:?}", self.exe); writeln!(f, "current working directory: {:?}", self.cwd); - writeln!(f, "memory usage: {} kB", self.memory); - writeln!(f, "virtual memory usage: {} kB", self.virtual_memory); + writeln!(f, "memory usage: {} KiB", self.memory); + writeln!(f, "virtual memory usage: {} KiB", self.virtual_memory); writeln!(f, "cpu usage: {}", self.cpu_usage); writeln!(f, "root path: {:?}", self.root) } diff --git a/src/windows/system.rs b/src/windows/system.rs index 35ba37cc9..40dc3f961 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -272,7 +272,7 @@ impl SystemExt for System { } fn refresh_processes(&mut self) { - // Windows 10 notebook requires at least 512kb of memory to make it in one go + // Windows 10 notebook requires at least 512KiB of memory to make it in one go let mut buffer_size: usize = 512 * 1024; loop { From 289636e2d8c876639962df5e537755efbacf2b7a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 14 Jan 2020 10:59:24 +0100 Subject: [PATCH 056/171] Allow to set the open files limit, reduce the limit of maximum open files to half of the system maximum --- src/linux/system.rs | 38 ++++++++++++++++++++++++++++++-------- src/sysinfo.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index ce21a58bd..42b9e79f9 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -31,13 +31,13 @@ use rayon::prelude::*; // This whole thing is to prevent having too much files open at once. It could be problematic // for processes using a lot of files and using sysinfo at the same time. -pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy>> = +pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy>> = once_cell::sync::Lazy::new(|| { #[cfg(target_os = "android")] { // The constant "RLIMIT_NOFILE" doesn't exist on Android so we have to return a value. - // The default value seems to be 1024 so let's return 90% of it... - Arc::new(Mutex::new(1024 - 1024 / 10)) + // The default value seems to be 1024 so let's return 50% of it... + Arc::new(Mutex::new(1024 - 1024 / 2)) } #[cfg(not(target_os = "android"))] unsafe { @@ -47,25 +47,47 @@ pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy>> }; if libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) != 0 { // Most linux system now defaults to 1024. - return Arc::new(Mutex::new(1024 - 1024 / 10)); + return Arc::new(Mutex::new(1024 - 1024 / 2)); } // We save the value in case the update fails. let current = limits.rlim_cur; // The set the soft limit to the hard one. limits.rlim_cur = limits.rlim_max; - // In this part, we leave minimum 10% of the available file descriptors to the process + // In this part, we leave minimum 50% of the available file descriptors to the process // using sysinfo. Arc::new(Mutex::new( if libc::setrlimit(libc::RLIMIT_NOFILE, &limits) == 0 { - limits.rlim_cur - limits.rlim_cur / 10 + limits.rlim_cur - limits.rlim_cur / 2 } else { - current - current / 10 + current - current / 2 } as _, )) } }); +pub(crate) fn get_max_nb_fds() -> isize { + #[cfg(target_os = "android")] + { + // The constant "RLIMIT_NOFILE" doesn't exist on Android so we have to return a value. + // The default value seems to be 1024... + 1024 + } + #[cfg(not(target_os = "android"))] + unsafe { + let mut limits = libc::rlimit { + rlim_cur: 0, + rlim_max: 0, + }; + if libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) != 0 { + // Most linux system now defaults to 1024. + 1024 + } else { + limits.rlim_max as _ + } + } +} + macro_rules! to_str { ($e:expr) => { unsafe { ::std::str::from_utf8_unchecked($e) } @@ -531,7 +553,7 @@ fn parse_stat_file(data: &str) -> Result, ()> { fn check_nb_open_files(f: File) -> Option { if let Ok(ref mut x) = unsafe { REMAINING_FILES.lock() } { if **x > 0 { - **x += 1; + **x -= 1; return Some(f); } } diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 998909275..10e3b6174 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -96,6 +96,43 @@ mod system; mod traits; mod utils; +/// This function is only used on linux targets, on the other platforms it does nothing. +/// +/// On linux, to improve performance, we keep a `/proc` file open for each process we index with +/// a maximum number of files open equivalent to half of the system limit. +/// +/// The problem is that some users might need all the available file descriptors so we need to +/// allow them to change this limit. Reducing +/// +/// Note that if you set a limit bigger than the system limit, the system limit will be set. +/// +/// Returns `true` if the new value has been set. +pub fn set_open_files_limit(mut new_limit: isize) -> bool { + #[cfg(all(not(target_os = "macos"), unix))] + { + if new_limit < 0 { + new_limit = 0; + } + let max = sys::system::get_max_nb_fds(); + if new_limit > max { + new_limit = max; + } + return if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } { + // If files are already open, to be sure that the number won't be bigger when those + // files are closed, we subtract the current number of opened files to the new limit. + let diff = max - **x; + **x = new_limit - diff; + true + } else { + false + }; + } + #[cfg(any(not(unix), target_os = "macos"))] + { + return false; + } +} + /// An enum representing signal on UNIX-like systems. #[repr(C)] #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)] From d5e47eaa1fca510a442f966cb13e1313dcf87b3f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 15 Jan 2020 10:45:12 +0100 Subject: [PATCH 057/171] Update crate version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 504960f24..dfdf9be6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sysinfo" -version = "0.10.4" +version = "0.10.5" authors = ["Guillaume Gomez "] description = "Library to handle processes" From 34bba033fe8dc23410fdc3bec02e6e95f3e11132 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jan 2020 10:51:21 +0100 Subject: [PATCH 058/171] Fix FD limiter --- src/linux/system.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index 42b9e79f9..9002ed24e 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -37,7 +37,7 @@ pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy>> { // The constant "RLIMIT_NOFILE" doesn't exist on Android so we have to return a value. // The default value seems to be 1024 so let's return 50% of it... - Arc::new(Mutex::new(1024 - 1024 / 2)) + Arc::new(Mutex::new(1024 / 2)) } #[cfg(not(target_os = "android"))] unsafe { @@ -47,7 +47,7 @@ pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy>> }; if libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) != 0 { // Most linux system now defaults to 1024. - return Arc::new(Mutex::new(1024 - 1024 / 2)); + return Arc::new(Mutex::new(1024 / 2)); } // We save the value in case the update fails. let current = limits.rlim_cur; @@ -58,9 +58,9 @@ pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy>> // using sysinfo. Arc::new(Mutex::new( if libc::setrlimit(libc::RLIMIT_NOFILE, &limits) == 0 { - limits.rlim_cur - limits.rlim_cur / 2 + limits.rlim_cur / 2 } else { - current - current / 2 + current / 2 } as _, )) } @@ -71,7 +71,7 @@ pub(crate) fn get_max_nb_fds() -> isize { { // The constant "RLIMIT_NOFILE" doesn't exist on Android so we have to return a value. // The default value seems to be 1024... - 1024 + 1024 / 2 } #[cfg(not(target_os = "android"))] unsafe { @@ -81,9 +81,9 @@ pub(crate) fn get_max_nb_fds() -> isize { }; if libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) != 0 { // Most linux system now defaults to 1024. - 1024 + 1024 / 2 } else { - limits.rlim_max as _ + limits.rlim_max as isize / 2 } } } @@ -615,6 +615,7 @@ fn _get_process_data( tmp.push("stat"); let mut file = ::std::fs::File::open(&tmp).map_err(|_| ())?; let data = get_all_data_from_file(&mut file, 1024).map_err(|_| ())?; + let stat_file = check_nb_open_files(file); let parts = parse_stat_file(&data)?; let parent_pid = if proc_list.pid != 0 { @@ -633,7 +634,7 @@ fn _get_process_data( .unwrap_or_else(|| 0); let mut p = Process::new(nb, parent_pid, start_time); - p.stat_file = Some(file); + p.stat_file = stat_file; get_status(&mut p, parts[2]); tmp.pop(); From c7e69467d6e65edc6d3590eb936923ffa0e47932 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Jan 2020 21:34:11 +0100 Subject: [PATCH 059/171] Update FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c86b850e2..2c6fa9336 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,3 +2,4 @@ github: [GuillaumeGomez] patreon: GuillaumeGomez +custom: ["https://paypal.me/imperioland"] From db1f7acb3c99e990d66356e13d635014c3768545 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Jan 2020 21:34:29 +0100 Subject: [PATCH 060/171] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 2c6fa9336..5b47c269a 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,4 +2,4 @@ github: [GuillaumeGomez] patreon: GuillaumeGomez -custom: ["https://paypal.me/imperioland"] +custom: ["https://paypal.me/imperioland", paypal] From 4ae1791d21f84f911ca8a77e3ebc19996b7de808 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Jan 2020 21:35:26 +0100 Subject: [PATCH 061/171] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 5b47c269a..2c6fa9336 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,4 +2,4 @@ github: [GuillaumeGomez] patreon: GuillaumeGomez -custom: ["https://paypal.me/imperioland", paypal] +custom: ["https://paypal.me/imperioland"] From 7300479663d6985e6c7d910f065f42df086d643a Mon Sep 17 00:00:00 2001 From: Lonng Date: Tue, 3 Dec 2019 14:40:39 +0800 Subject: [PATCH 062/171] add functions get_cpu_frequency/get_avg_load Signed-off-by: Lonng --- src/linux/mod.rs | 2 +- src/linux/processor.rs | 46 ++++++++++++++++++++++++++++++++++++++++ src/mac/ffi.rs | 8 +++++++ src/mac/mod.rs | 2 +- src/mac/processor.rs | 32 ++++++++++++++++++++++++++++ src/sysinfo.rs | 27 ++++++++++++++++++++++- src/unknown/mod.rs | 2 +- src/unknown/processor.rs | 12 +++++++++++ src/windows/mod.rs | 2 +- src/windows/processor.rs | 12 +++++++++++ 10 files changed, 140 insertions(+), 5 deletions(-) diff --git a/src/linux/mod.rs b/src/linux/mod.rs index 9238248b9..913a1c977 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::Processor; +pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; pub use self::system::System; diff --git a/src/linux/processor.rs b/src/linux/processor.rs index e7d988465..94d6e10c9 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -6,6 +6,11 @@ #![allow(clippy::too_many_arguments)] +use std::default::Default; +use std::fs::File; +use std::io::Read; + +use LoadAvg; use ProcessorExt; /// Struct containing values to compute a CPU usage. @@ -249,3 +254,44 @@ pub fn set_processor( pub fn get_raw_times(p: &Processor) -> (u64, u64) { (p.new_values.total_time(), p.old_values.total_time()) } + +/// get_cpu_frequency returns the CPU frequency in MHz +pub fn get_cpu_frequency() -> u64 { + // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq + let mut s = String::new(); + if let Err(_) = File::open("/proc/cpuinfo").and_then(|mut f| f.read_to_string(&mut s)) { + return 0; + } + + let find_cpu_mhz = s.split('\n').find(|line| { + line.starts_with("cpu MHz\t") + || line.starts_with("BogoMIPS") + || line.starts_with("clock\t") + || line.starts_with("bogomips per cpu") + }); + + find_cpu_mhz + .and_then(|line| line.split(':').last()) + .and_then(|val| val.replace("MHz", "").trim().parse::().ok()) + .map(|speed| speed as u64) + .unwrap_or_default() +} + +/// get_avg_load returns the system load average value. +pub fn get_avg_load() -> LoadAvg { + let mut s = String::new(); + if let Err(_) = File::open("/proc/loadavg").and_then(|mut f| f.read_to_string(&mut s)) { + return LoadAvg::default(); + } + let loads = s + .trim() + .split(' ') + .take(3) + .map(|val| val.parse::().unwrap()) + .collect::>(); + LoadAvg { + one: loads[0], + five: loads[1], + fifteen: loads[2], + } +} diff --git a/src/mac/ffi.rs b/src/mac/ffi.rs index 73a82df26..eabc5f4d0 100644 --- a/src/mac/ffi.rs +++ b/src/mac/ffi.rs @@ -82,6 +82,14 @@ extern "C" { //pub fn host_statistics(host_priv: u32, flavor: u32, host_info: *mut c_void, // host_count: *const u32) -> u32; pub fn vm_deallocate(target_task: u32, address: *mut i32, size: u32) -> kern_return_t; + pub fn sysctlbyname( + name: *const c_char, + oldp: *mut u64, + oldlenp: *mut usize, + newp: *mut c_void, + newlen: usize, + ) -> kern_return_t; + pub fn getloadavg(loads: *const f64, size: c_int); // pub fn proc_pidpath(pid: i32, buf: *mut i8, bufsize: u32) -> i32; // pub fn proc_name(pid: i32, buf: *mut i8, bufsize: u32) -> i32; diff --git a/src/mac/mod.rs b/src/mac/mod.rs index 1ae6e4f8a..4cccbc57b 100644 --- a/src/mac/mod.rs +++ b/src/mac/mod.rs @@ -16,5 +16,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::Processor; +pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; pub use self::system::System; diff --git a/src/mac/processor.rs b/src/mac/processor.rs index 09eba16b2..5ff7e2fc6 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -4,10 +4,12 @@ // Copyright (c) 2015 Guillaume Gomez // +use libc::c_char; use std::ops::Deref; use std::sync::Arc; use sys::ffi; +use LoadAvg; use ProcessorExt; pub struct UnsafePtr(*mut T); @@ -96,3 +98,33 @@ pub fn set_cpu_proc(p: &mut Processor, cpu_usage: f32) { pub fn get_processor_data(p: &Processor) -> Arc { Arc::clone(&p.processor_data) } + +/// get_cpu_frequency returns the CPU frequency in MHz +pub fn get_cpu_frequency() -> u64 { + let mut speed: u64 = 0; + let mut len = std::mem::size_of::(); + unsafe { + ffi::sysctlbyname( + "hw.cpufrequency".as_ptr() as *const c_char, + &mut speed, + &mut len, + std::ptr::null_mut(), + 0, + ); + } + speed /= 1000000; + speed +} + +/// get_avg_load returns the system load average value. +pub fn get_avg_load() -> LoadAvg { + let loads = vec![0f64; 3]; + unsafe { + ffi::getloadavg(loads.as_ptr() as *const f64, 3); + } + LoadAvg { + one: loads[0], + five: loads[1], + fifteen: loads[2], + } +} diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 6d6d5d299..668ac3a54 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -79,7 +79,10 @@ cfg_if! { } pub use common::{AsU32, Pid, RefreshKind}; -pub use sys::{Component, Disk, DiskType, NetworkData, Process, ProcessStatus, Processor, System}; +pub use sys::{ + get_avg_load, get_cpu_frequency, Component, Disk, DiskType, NetworkData, Process, + ProcessStatus, Processor, System, +}; pub use traits::{ComponentExt, DiskExt, NetworkExt, ProcessExt, ProcessorExt, SystemExt}; #[cfg(feature = "c-interface")] @@ -205,6 +208,18 @@ pub enum Signal { Sys = 31, } +/// A struct represents system load average value. +#[repr(C)] +#[derive(Default, Debug)] +pub struct LoadAvg { + /// Average load within one minite. + pub one: f64, + /// Average load within five minites. + pub five: f64, + /// Average load within fifteen minites. + pub fifteen: f64, +} + #[cfg(test)] mod test { use traits::{ProcessExt, SystemExt}; @@ -221,4 +236,14 @@ mod test { false ); } + + #[test] + fn test_get_cpu_frequency() { + println!("test get_cpu_frequency: {}", ::get_cpu_frequency()); + } + + #[test] + fn test_get_avg_load() { + println!("test get_avg_load: {:?}", ::get_avg_load()); + } } diff --git a/src/unknown/mod.rs b/src/unknown/mod.rs index 9238248b9..913a1c977 100644 --- a/src/unknown/mod.rs +++ b/src/unknown/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::Processor; +pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; pub use self::system::System; diff --git a/src/unknown/processor.rs b/src/unknown/processor.rs index 8de271fdf..cfe09dfd8 100644 --- a/src/unknown/processor.rs +++ b/src/unknown/processor.rs @@ -4,6 +4,9 @@ // Copyright (c) 2015 Guillaume Gomez // +use std::default::Default; + +use LoadAvg; use ProcessorExt; /// Dummy struct that represents a processor. @@ -18,3 +21,12 @@ impl ProcessorExt for Processor { "" } } + +pub fn get_cpu_frequency() -> u64 { + 0 +} + +/// get_avg_load returns the system load average value. +pub fn get_avg_load() -> LoadAvg { + LoadAvg::default() +} diff --git a/src/windows/mod.rs b/src/windows/mod.rs index 95e5ded57..1191e49c4 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -34,5 +34,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::Processor; +pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; pub use self::system::System; diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 6e446d623..5b99f23eb 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -5,11 +5,13 @@ // use std::collections::HashMap; +use std::default::Default; use std::sync::{Arc, Mutex}; use std::thread::{self /*, sleep*/, JoinHandle}; //use std::time::Duration; use windows::tools::KeyHandler; +use LoadAvg; use ProcessorExt; use winapi::shared::minwindef::{FALSE, ULONG}; @@ -286,3 +288,13 @@ pub fn get_key_idle(p: &mut Processor) -> &mut Option { pub fn get_key_used(p: &mut Processor) -> &mut Option { &mut p.key_used } + +pub fn get_cpu_frequency() -> u64 { + // TODO: support windows + 0 +} + +/// get_avg_load returns the system load average value. +pub fn get_avg_load() -> LoadAvg { + LoadAvg::default() +} From b33d66e149a5d908179cbacb33a6ea65e3483b87 Mon Sep 17 00:00:00 2001 From: Lonng Date: Tue, 3 Dec 2019 16:09:39 +0800 Subject: [PATCH 063/171] support retrieve network statistics Signed-off-by: Lonng --- src/net.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/sysinfo.rs | 7 +++++ 2 files changed, 79 insertions(+) create mode 100644 src/net.rs diff --git a/src/net.rs b/src/net.rs new file mode 100644 index 000000000..6abd84820 --- /dev/null +++ b/src/net.rs @@ -0,0 +1,72 @@ +use std::collections::HashMap; + +/// NICLoad represents the network interface card load informations +#[derive(Debug)] +pub struct NICLoad { + /// a total number of bytes received over interface. + pub rx_bytes: usize, + /// a total number of bytes transmitted over interface. + pub tx_bytes: usize, + /// a total number of packets received. + pub rx_packets: usize, + /// a total number of packets transmitted. + pub tx_packets: usize, + /// shows a total number of packets received with error. This includes + /// too-long-frames errors, ring-buffer overflow errors, CRC errors, + /// frame alignment errors, fifo overruns, and missed packets. + pub rx_errors: usize, + /// similar to `rx_errors` + pub tx_errors: usize, + /// Indicates the number of compressed packets received by this + /// network device. This value might only be relevant for interfaces + /// that support packet compression (e.g: PPP). + pub rx_compressed: usize, + /// Indicates the number of transmitted compressed packets. Note + /// this might only be relevant for devices that support + /// compression (e.g: PPP). + pub tx_compressed: usize, +} + +impl NICLoad { + /// Returns the current network interfaces card statistics + /// + /// # Notes + /// + /// Current don't support non-unix operating system + #[cfg(not(unix))] + pub fn current() -> HashMap { + HashMap::new() + } + + /// Returns the current network interfaces card statistics + #[cfg(unix)] + pub fn current() -> HashMap { + let mut result = HashMap::new(); + if let Ok(dir) = std::fs::read_dir("/sys/class/net/") { + for entry in dir { + if let Ok(entry) = entry { + let parent = entry.path().join("statistics"); + let read = |path: &str| -> usize { + std::fs::read_to_string(parent.join(path)) + .unwrap_or_default() + .trim() + .parse() + .unwrap_or_default() + }; + let load = NICLoad { + rx_bytes: read("rx_bytes"), + tx_bytes: read("tx_bytes"), + rx_packets: read("rx_packets"), + tx_packets: read("tx_packets"), + rx_errors: read("rx_errors"), + tx_errors: read("tx_errors"), + rx_compressed: read("rx_compressed"), + tx_compressed: read("tx_compressed"), + }; + result.insert(format!("{:?}", entry.file_name()), load); + } + } + } + result + } +} diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 668ac3a54..fe034a0ee 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -79,6 +79,7 @@ cfg_if! { } pub use common::{AsU32, Pid, RefreshKind}; +pub use net::NICLoad; pub use sys::{ get_avg_load, get_cpu_frequency, Component, Disk, DiskType, NetworkData, Process, ProcessStatus, Processor, System, @@ -93,6 +94,7 @@ pub use utils::get_current_pid; mod c_interface; mod common; mod component; +mod net; mod process; mod processor; mod system; @@ -246,4 +248,9 @@ mod test { fn test_get_avg_load() { println!("test get_avg_load: {:?}", ::get_avg_load()); } + + #[test] + fn test_nic_load() { + println!("test test_nic_load: {:?}", ::NICLoad::current()); + } } From 776ff789ec77c560ee8309dacc330c5ad21ee45b Mon Sep 17 00:00:00 2001 From: Lonng Date: Tue, 3 Dec 2019 17:02:14 +0800 Subject: [PATCH 064/171] support retrieve block device IO statistics Signed-off-by: Lonng --- src/io.rs | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/net.rs | 4 +-- src/sysinfo.rs | 9 ++++- 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 src/io.rs diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 000000000..05bdc3356 --- /dev/null +++ b/src/io.rs @@ -0,0 +1,93 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +/// IOLoad represents current system block devices IO statistics +#[derive(Debug)] +pub struct IOLoad { + /// number of read I/Os processed + /// units: requests + pub read_io: f64, + /// number of read I/Os merged with in-queue I/O + /// units: requests + pub read_merges: f64, + /// number of sectors read + /// units: sectors + pub read_sectors: f64, + /// total wait time for read requests + /// units: milliseconds + pub read_ticks: f64, + /// number of write I/Os processed + /// units: requests + pub write_io: f64, + /// number of write I/Os merged with in-queue I/O + /// units: requests + pub write_merges: f64, + /// number of sectors written + /// units: sectors + pub write_sectors: f64, + /// total wait time for write requests + /// units: milliseconds + pub write_ticks: f64, + /// number of I/Os currently in flight + /// units: requests + pub in_flight: f64, + /// total time this block device has been active + /// units: milliseconds + pub io_ticks: f64, + /// total wait time for all requests + /// units: milliseconds + pub time_in_queue: f64, +} + +impl IOLoad { + /// Returns the current IO statistics + /// + /// # Notes + /// + /// Current don't support non-unix operating system + #[cfg(not(unix))] + pub fn snapshot() -> HashMap { + HashMap::new() + } + + /// Returns the current IO statistics + #[cfg(unix)] + pub fn snapshot() -> HashMap { + let mut result = HashMap::new(); + // https://www.kernel.org/doc/Documentation/block/stat.txt + if let Ok(dir) = std::fs::read_dir("/sys/block/") { + for entry in dir { + if let Ok(entry) = entry { + let stat = entry.path().join("stat"); + let mut s = String::new(); + if let Err(_) = File::open(stat).and_then(|mut f| f.read_to_string(&mut s)) { + continue; + }; + let parts = s + .split_whitespace() + .map(|w| w.parse().unwrap_or_default()) + .collect::>(); + if parts.len() != 11 { + continue; + } + let load = IOLoad { + read_io: parts[0], + read_merges: parts[1], + read_sectors: parts[2], + read_ticks: parts[3], + write_io: parts[4], + write_merges: parts[5], + write_sectors: parts[6], + write_ticks: parts[7], + in_flight: parts[8], + io_ticks: parts[9], + time_in_queue: parts[10], + }; + result.insert(format!("{:?}", entry.file_name()), load); + } + } + } + result + } +} diff --git a/src/net.rs b/src/net.rs index 6abd84820..878c6648b 100644 --- a/src/net.rs +++ b/src/net.rs @@ -34,13 +34,13 @@ impl NICLoad { /// /// Current don't support non-unix operating system #[cfg(not(unix))] - pub fn current() -> HashMap { + pub fn snapshot() -> HashMap { HashMap::new() } /// Returns the current network interfaces card statistics #[cfg(unix)] - pub fn current() -> HashMap { + pub fn snapshot() -> HashMap { let mut result = HashMap::new(); if let Ok(dir) = std::fs::read_dir("/sys/class/net/") { for entry in dir { diff --git a/src/sysinfo.rs b/src/sysinfo.rs index fe034a0ee..82fbb1b2a 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -79,6 +79,7 @@ cfg_if! { } pub use common::{AsU32, Pid, RefreshKind}; +pub use io::IOLoad; pub use net::NICLoad; pub use sys::{ get_avg_load, get_cpu_frequency, Component, Disk, DiskType, NetworkData, Process, @@ -94,6 +95,7 @@ pub use utils::get_current_pid; mod c_interface; mod common; mod component; +mod io; mod net; mod process; mod processor; @@ -251,6 +253,11 @@ mod test { #[test] fn test_nic_load() { - println!("test test_nic_load: {:?}", ::NICLoad::current()); + println!("test test_nic_load: {:?}", ::NICLoad::snapshot()); + } + + #[test] + fn test_io_load() { + println!("test test_io_load: {:?}", ::IOLoad::snapshot()); } } From 1f52533aeebab1b724f7abd7d8b0728c3039e1da Mon Sep 17 00:00:00 2001 From: Lonng Date: Tue, 3 Dec 2019 19:21:12 +0800 Subject: [PATCH 065/171] support retrieve system wide configuration list Signed-off-by: Lonng --- Cargo.toml | 1 + src/sysinfo.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index dfdf9be6b..425b684bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ build = "build.rs" cfg-if = "0.1" rayon = "^1.0" doc-comment = "0.3" +walkdir = "2.2.9" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase"] } diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 82fbb1b2a..8a6738e6d 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -91,6 +91,8 @@ pub use traits::{ComponentExt, DiskExt, NetworkExt, ProcessExt, ProcessorExt, Sy pub use c_interface::*; pub use utils::get_current_pid; +use std::collections::HashMap; + #[cfg(feature = "c-interface")] mod c_interface; mod common; @@ -224,6 +226,35 @@ pub struct LoadAvg { pub fifteen: f64, } +/// Returns system wide configuration +/// +/// # Note +/// +/// Current only can be used in operating system mounted `procfs` +pub fn get_sysctl_list() -> HashMap { + const DIR: &str = "/proc/sys/"; + let mut result = HashMap::new(); + for entry in walkdir::WalkDir::new(DIR) { + let entry = match entry { + Ok(entry) => entry, + _ => continue, + }; + + let content = match std::fs::read_to_string(entry.path()) { + Ok(c) => c, + _ => continue, + }; + + let path = match entry.path().to_str() { + Some(p) => p, + _ => continue, + }; + let name = path.trim_start_matches(DIR).replace("/", "."); + result.insert(name, content.trim().to_string()); + } + result +} + #[cfg(test)] mod test { use traits::{ProcessExt, SystemExt}; From 97922cb9e3224494744d21b6881131c716265f36 Mon Sep 17 00:00:00 2001 From: Lonng Date: Wed, 4 Dec 2019 16:44:50 +0800 Subject: [PATCH 066/171] wrap num_cpus/pnet_datalink/cache_size crates Signed-off-by: Lonng --- Cargo.toml | 3 +++ src/sysinfo.rs | 30 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 425b684bb..016327ec6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,9 @@ cfg-if = "0.1" rayon = "^1.0" doc-comment = "0.3" walkdir = "2.2.9" +pnet_datalink = "0.23.0" +num_cpus = "1.11.1" +cache-size = "0.4.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase"] } diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 8a6738e6d..19744bde3 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -48,6 +48,8 @@ //#![deny(warnings)] #![allow(unknown_lints)] +extern crate num_cpus; + #[macro_use] extern crate cfg_if; #[cfg(not(any(target_os = "unknown", target_arch = "wasm32")))] @@ -78,9 +80,14 @@ cfg_if! { } } +pub extern crate cache_size; +pub extern crate pnet_datalink as datalink; + pub use common::{AsU32, Pid, RefreshKind}; pub use io::IOLoad; pub use net::NICLoad; +pub use num_cpus::{get as get_logical_cores, get_physical as get_physical_cores}; + pub use sys::{ get_avg_load, get_cpu_frequency, Component, Disk, DiskType, NetworkData, Process, ProcessStatus, Processor, System, @@ -228,7 +235,7 @@ pub struct LoadAvg { /// Returns system wide configuration /// -/// # Note +/// # Notes /// /// Current only can be used in operating system mounted `procfs` pub fn get_sysctl_list() -> HashMap { @@ -291,4 +298,25 @@ mod test { fn test_io_load() { println!("test test_io_load: {:?}", ::IOLoad::snapshot()); } + + #[test] + fn test_get_cores() { + assert_ne!(::get_logical_cores(), 0, "expect none-zero logical core"); + assert_ne!(::get_physical_cores(), 0, "expect none-zero physical core"); + } + + #[test] + fn test_cache_size() { + let caches = vec![ + ("l1-cache-size", ::cache_size::l1_cache_size()), + ("l1-cache-line-size", ::cache_size::l1_cache_line_size()), + ("l2-cache-size", ::cache_size::l2_cache_size()), + ("l2-cache-line-size", ::cache_size::l2_cache_line_size()), + ("l3-cache-size", ::cache_size::l3_cache_size()), + ("l3-cache-line-size", ::cache_size::l3_cache_line_size()), + ]; + for c in caches { + assert_ne!(c.1.unwrap(), 0, "{} expect non-zero", c.0) + } + } } From b57d44d2b92318ed1911354a4d74304b354ffa37 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 22 Jan 2020 18:51:47 +0000 Subject: [PATCH 067/171] Fix io issue with modern Linux versions Signed-off-by: Nick Cameron --- src/io.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.rs b/src/io.rs index 05bdc3356..ae6debd56 100644 --- a/src/io.rs +++ b/src/io.rs @@ -68,7 +68,7 @@ impl IOLoad { .split_whitespace() .map(|w| w.parse().unwrap_or_default()) .collect::>(); - if parts.len() != 11 { + if parts.len() < 11 { continue; } let load = IOLoad { From 1473e52e1d0dea18633b95af30796cc7cf8eda0a Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 22 Jan 2020 18:52:12 +0000 Subject: [PATCH 068/171] Add get_vendor_id function Signed-off-by: Nick Cameron --- src/linux/mod.rs | 2 +- src/linux/processor.rs | 13 +++++++++++++ src/mac/mod.rs | 2 +- src/mac/processor.rs | 6 ++++++ src/sysinfo.rs | 8 ++++++-- src/unknown/mod.rs | 2 +- src/unknown/processor.rs | 5 +++++ src/windows/mod.rs | 2 +- src/windows/processor.rs | 6 ++++++ 9 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/linux/mod.rs b/src/linux/mod.rs index 913a1c977..6ce307c97 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; +pub use self::processor::{get_avg_load, get_cpu_frequency, get_vendor_id, Processor}; pub use self::system::System; diff --git a/src/linux/processor.rs b/src/linux/processor.rs index 94d6e10c9..3fc0273d3 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -277,6 +277,19 @@ pub fn get_cpu_frequency() -> u64 { .unwrap_or_default() } +/// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). +pub fn get_vendor_id() -> String { + let mut s = String::new(); + if let Err(_) = File::open("/proc/cpuinfo").and_then(|mut f| f.read_to_string(&mut s)) { + return String::new(); + } + + s.split('\n').find(|line| line.starts_with("vendor_id\t")) + .and_then(|line| line.split(':').last()) + .map(|s| s.trim().to_owned()) + .unwrap_or_default() +} + /// get_avg_load returns the system load average value. pub fn get_avg_load() -> LoadAvg { let mut s = String::new(); diff --git a/src/mac/mod.rs b/src/mac/mod.rs index 4cccbc57b..7bc9da3d0 100644 --- a/src/mac/mod.rs +++ b/src/mac/mod.rs @@ -16,5 +16,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; +pub use self::processor::{get_avg_load, get_cpu_frequency, get_vendor_id, Processor}; pub use self::system::System; diff --git a/src/mac/processor.rs b/src/mac/processor.rs index 5ff7e2fc6..62db4fb29 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -116,6 +116,12 @@ pub fn get_cpu_frequency() -> u64 { speed } +/// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). +pub fn get_vendor_id() -> String { + // TODO: support Mac + "".to_owned() +} + /// get_avg_load returns the system load average value. pub fn get_avg_load() -> LoadAvg { let loads = vec![0f64; 3]; diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 19744bde3..57e5bb57b 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -89,7 +89,7 @@ pub use net::NICLoad; pub use num_cpus::{get as get_logical_cores, get_physical as get_physical_cores}; pub use sys::{ - get_avg_load, get_cpu_frequency, Component, Disk, DiskType, NetworkData, Process, + get_avg_load, get_cpu_frequency, get_vendor_id, Component, Disk, DiskType, NetworkData, Process, ProcessStatus, Processor, System, }; pub use traits::{ComponentExt, DiskExt, NetworkExt, ProcessExt, ProcessorExt, SystemExt}; @@ -264,7 +264,7 @@ pub fn get_sysctl_list() -> HashMap { #[cfg(test)] mod test { - use traits::{ProcessExt, SystemExt}; + use super::*; #[test] fn check_memory_usage() { @@ -307,6 +307,10 @@ mod test { #[test] fn test_cache_size() { + if get_vendor_id() == "AuthenticAMD" { + return; + } + let caches = vec![ ("l1-cache-size", ::cache_size::l1_cache_size()), ("l1-cache-line-size", ::cache_size::l1_cache_line_size()), diff --git a/src/unknown/mod.rs b/src/unknown/mod.rs index 913a1c977..6ce307c97 100644 --- a/src/unknown/mod.rs +++ b/src/unknown/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; +pub use self::processor::{get_avg_load, get_cpu_frequency, get_vendor_id, Processor}; pub use self::system::System; diff --git a/src/unknown/processor.rs b/src/unknown/processor.rs index cfe09dfd8..7c719064f 100644 --- a/src/unknown/processor.rs +++ b/src/unknown/processor.rs @@ -26,6 +26,11 @@ pub fn get_cpu_frequency() -> u64 { 0 } +/// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). +pub fn get_vendor_id() -> String { + "".to_owned() +} + /// get_avg_load returns the system load average value. pub fn get_avg_load() -> LoadAvg { LoadAvg::default() diff --git a/src/windows/mod.rs b/src/windows/mod.rs index 1191e49c4..f6bbda86f 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -34,5 +34,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; +pub use self::processor::{get_avg_load, get_cpu_frequency, get_vendor_id, Processor}; pub use self::system::System; diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 5b99f23eb..5e79aa70f 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -294,6 +294,12 @@ pub fn get_cpu_frequency() -> u64 { 0 } +/// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). +pub fn get_vendor_id() -> String { + // TODO: support windows + "".to_owned() +} + /// get_avg_load returns the system load average value. pub fn get_avg_load() -> LoadAvg { LoadAvg::default() From 159022d179c9433d2bdeb01e22d2bd469c7f0bee Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2020 22:24:52 +0100 Subject: [PATCH 069/171] Clean up linux new methods --- src/linux/mod.rs | 2 +- src/linux/process.rs | 1 + src/linux/processor.rs | 88 +++++++---------------------------- src/linux/system.rs | 102 ++++++++++++++++++++++++++++------------- src/mac/process.rs | 12 ++--- src/mac/system.rs | 18 ++------ src/sysinfo.rs | 15 +++--- src/traits.rs | 10 ++++ 8 files changed, 116 insertions(+), 132 deletions(-) diff --git a/src/linux/mod.rs b/src/linux/mod.rs index 6ce307c97..9238248b9 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, get_vendor_id, Processor}; +pub use self::processor::Processor; pub use self::system::System; diff --git a/src/linux/process.rs b/src/linux/process.rs index c15543e41..54750913f 100644 --- a/src/linux/process.rs +++ b/src/linux/process.rs @@ -7,6 +7,7 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; use std::fs::File; +use std::io::Read; use std::path::{Path, PathBuf}; use libc::{c_int, gid_t, kill, uid_t}; diff --git a/src/linux/processor.rs b/src/linux/processor.rs index 3fc0273d3..809990b0c 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -6,11 +6,9 @@ #![allow(clippy::too_many_arguments)] -use std::default::Default; use std::fs::File; use std::io::Read; -use LoadAvg; use ProcessorExt; /// Struct containing values to compute a CPU usage. @@ -130,22 +128,12 @@ pub struct Processor { cpu_usage: f32, total_time: u64, old_total_time: u64, + frequency: u64, + vendor_id: String, } impl Processor { - #[allow(dead_code)] - fn new() -> Processor { - Processor { - name: String::new(), - old_values: CpuValues::new(), - new_values: CpuValues::new(), - cpu_usage: 0f32, - total_time: 0, - old_total_time: 0, - } - } - - fn new_with_values( + pub(crate) fn new_with_values( name: &str, user: u64, nice: u64, @@ -157,6 +145,8 @@ impl Processor { steal: u64, guest: u64, guest_nice: u64, + frequency: u64, + vendor_id: String, ) -> Processor { Processor { name: name.to_owned(), @@ -167,10 +157,12 @@ impl Processor { cpu_usage: 0f32, total_time: 0, old_total_time: 0, + frequency, + vendor_id, } } - fn set( + pub(crate) fn set( &mut self, user: u64, nice: u64, @@ -213,49 +205,21 @@ impl ProcessorExt for Processor { fn get_name(&self) -> &str { &self.name } -} -pub fn new_processor( - name: &str, - user: u64, - nice: u64, - system: u64, - idle: u64, - iowait: u64, - irq: u64, - softirq: u64, - steal: u64, - guest: u64, - guest_nice: u64, -) -> Processor { - Processor::new_with_values( - name, user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice, - ) -} + /// Returns the CPU frequency in MHz. + fn get_frequency(&self) -> u64 { + self.frequency + } -pub fn set_processor( - p: &mut Processor, - user: u64, - nice: u64, - system: u64, - idle: u64, - iowait: u64, - irq: u64, - softirq: u64, - steal: u64, - guest: u64, - guest_nice: u64, -) { - p.set( - user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice, - ) + fn get_vendor_id(&self) -> &str { + &self.vendor_id + } } pub fn get_raw_times(p: &Processor) -> (u64, u64) { (p.new_values.total_time(), p.old_values.total_time()) } -/// get_cpu_frequency returns the CPU frequency in MHz pub fn get_cpu_frequency() -> u64 { // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq let mut s = String::new(); @@ -284,27 +248,9 @@ pub fn get_vendor_id() -> String { return String::new(); } - s.split('\n').find(|line| line.starts_with("vendor_id\t")) + s.split('\n') + .find(|line| line.starts_with("vendor_id\t")) .and_then(|line| line.split(':').last()) .map(|s| s.trim().to_owned()) .unwrap_or_default() } - -/// get_avg_load returns the system load average value. -pub fn get_avg_load() -> LoadAvg { - let mut s = String::new(); - if let Err(_) = File::open("/proc/loadavg").and_then(|mut f| f.read_to_string(&mut s)) { - return LoadAvg::default(); - } - let loads = s - .trim() - .split(' ') - .take(3) - .map(|val| val.parse::().unwrap()) - .collect::>(); - LoadAvg { - one: loads[0], - five: loads[1], - fifteen: loads[2], - } -} diff --git a/src/linux/system.rs b/src/linux/system.rs index 9002ed24e..feb195fe7 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -11,6 +11,7 @@ use sys::process::*; use sys::processor::*; use sys::Disk; use sys::NetworkData; +use LoadAvg; use Pid; use {DiskExt, ProcessExt, RefreshKind, SystemExt}; @@ -132,12 +133,63 @@ impl System { } fn refresh_processors(&mut self, limit: Option) { + fn get_callbacks( + first: bool, + ) -> Box, &mut Vec, &mut usize)> { + if first { + let frequency = get_cpu_frequency(); + let vendor_id = get_vendor_id(); + Box::new( + move |parts: &mut dyn Iterator, + processors: &mut Vec, + _| { + processors.push(Processor::new_with_values( + to_str!(parts.next().unwrap_or(&[])), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + frequency, + vendor_id.clone(), + )); + }, + ) + } else { + Box::new( + |parts: &mut dyn Iterator, + processors: &mut Vec, + i: &mut usize| { + parts.next(); // we don't want the name again + processors[*i].set( + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + ); + *i += 1; + }, + ) + } + } if let Ok(f) = File::open("/proc/stat") { let buf = BufReader::new(f); let mut i = 0; let first = self.processors.is_empty(); let mut it = buf.split(b'\n'); let mut count = 0; + let callback = get_callbacks(first); while let Some(Ok(line)) = it.next() { if &line[..3] != b"cpu" { @@ -146,37 +198,7 @@ impl System { count += 1; let mut parts = line.split(|x| *x == b' ').filter(|s| !s.is_empty()); - if first { - self.processors.push(new_processor( - to_str!(parts.next().unwrap_or(&[])), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - )); - } else { - parts.next(); // we don't want the name again - set_processor( - &mut self.processors[i], - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - ); - i += 1; - } + callback(&mut parts, &mut self.processors, &mut i); if let Some(limit) = limit { if count >= limit { break; @@ -351,6 +373,24 @@ impl SystemExt for System { fn get_uptime(&self) -> u64 { self.uptime } + + fn get_avg_load(&self) -> LoadAvg { + let mut s = String::new(); + if let Err(_) = File::open("/proc/loadavg").and_then(|mut f| f.read_to_string(&mut s)) { + return LoadAvg::default(); + } + let loads = s + .trim() + .split(' ') + .take(3) + .map(|val| val.parse::().unwrap()) + .collect::>(); + LoadAvg { + one: loads[0], + five: loads[1], + fifteen: loads[2], + } + } } impl Default for System { diff --git a/src/mac/process.rs b/src/mac/process.rs index b36796ad6..65ffb013d 100644 --- a/src/mac/process.rs +++ b/src/mac/process.rs @@ -152,11 +152,7 @@ pub struct Process { } impl Process { - pub(crate) fn new_empty( - pid: Pid, - exe: PathBuf, - name: String, - ) -> Process { + pub(crate) fn new_empty(pid: Pid, exe: PathBuf, name: String) -> Process { Process { name, pid, @@ -435,7 +431,11 @@ pub(crate) fn update_process( ) != mem::size_of::() as _ { let mut buffer: Vec = Vec::with_capacity(ffi::PROC_PIDPATHINFO_MAXSIZE as _); - match ffi::proc_pidpath(pid, buffer.as_mut_ptr() as *mut _, ffi::PROC_PIDPATHINFO_MAXSIZE) { + match ffi::proc_pidpath( + pid, + buffer.as_mut_ptr() as *mut _, + ffi::PROC_PIDPATHINFO_MAXSIZE, + ) { x if x > 0 => { buffer.set_len(x as _); let tmp = String::from_utf8_unchecked(buffer); diff --git a/src/mac/system.rs b/src/mac/system.rs index 2e5610fe9..1903cf742 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -288,15 +288,9 @@ impl SystemExt for System { let entries: Vec = { let wrap = &Wrap(UnsafeCell::new(&mut self.process_list)); pids.par_iter() - .flat_map(|pid| { - match update_process( - wrap, - *pid, - arg_max as size_t, - ) { - Ok(x) => x, - Err(_) => None, - } + .flat_map(|pid| match update_process(wrap, *pid, arg_max as size_t) { + Ok(x) => x, + Err(_) => None, }) .collect() }; @@ -311,11 +305,7 @@ impl SystemExt for System { let arg_max = get_arg_max(); match { let wrap = Wrap(UnsafeCell::new(&mut self.process_list)); - update_process( - &wrap, - pid, - arg_max as size_t, - ) + update_process(&wrap, pid, arg_max as size_t) } { Ok(Some(p)) => { self.process_list.insert(p.pid(), p); diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 57e5bb57b..a30739d98 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -88,10 +88,7 @@ pub use io::IOLoad; pub use net::NICLoad; pub use num_cpus::{get as get_logical_cores, get_physical as get_physical_cores}; -pub use sys::{ - get_avg_load, get_cpu_frequency, get_vendor_id, Component, Disk, DiskType, NetworkData, Process, - ProcessStatus, Processor, System, -}; +pub use sys::{Component, Disk, DiskType, NetworkData, Process, ProcessStatus, Processor, System}; pub use traits::{ComponentExt, DiskExt, NetworkExt, ProcessExt, ProcessorExt, SystemExt}; #[cfg(feature = "c-interface")] @@ -118,7 +115,7 @@ mod utils; /// a maximum number of files open equivalent to half of the system limit. /// /// The problem is that some users might need all the available file descriptors so we need to -/// allow them to change this limit. Reducing +/// allow them to change this limit. Reducing /// /// Note that if you set a limit bigger than the system limit, the system limit will be set. /// @@ -223,13 +220,13 @@ pub enum Signal { /// A struct represents system load average value. #[repr(C)] -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct LoadAvg { - /// Average load within one minite. + /// Average load within one minute. pub one: f64, - /// Average load within five minites. + /// Average load within five minutes. pub five: f64, - /// Average load within fifteen minites. + /// Average load within fifteen minutes. pub fifteen: f64, } diff --git a/src/traits.rs b/src/traits.rs index b65fbf8ee..337e12bdb 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -5,6 +5,7 @@ // use sys::{Component, Disk, DiskType, NetworkData, Process, Processor}; +use LoadAvg; use Pid; use ProcessStatus; use RefreshKind; @@ -105,6 +106,12 @@ pub trait ProcessorExt { /// Returns this processor's name. fn get_name(&self) -> &str; + + /// Returns the processor's vendor id. + fn get_vendor_id(&self) -> &str; + + /// Returns the processor's frequency. + fn get_frequency(&self) -> u64; } /// Contains all the methods of the [`System`] type. @@ -275,6 +282,9 @@ pub trait SystemExt: Sized { /// Returns system uptime. fn get_uptime(&self) -> u64; + + /// Returns the system load average value. + fn get_avg_load(&self) -> LoadAvg; } /// Getting volume of incoming and outgoing data. From 751c348f6cedc5e0c48b699d6ea34e221012c05d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2020 22:49:06 +0100 Subject: [PATCH 070/171] Clean up mac interface --- src/mac/ffi.rs | 2 +- src/mac/mod.rs | 2 +- src/mac/process.rs | 13 +++++++++ src/mac/processor.rs | 67 +++++++++++++++++++++++++++++++------------- src/mac/system.rs | 14 +++++++-- 5 files changed, 74 insertions(+), 24 deletions(-) diff --git a/src/mac/ffi.rs b/src/mac/ffi.rs index eabc5f4d0..93868274a 100644 --- a/src/mac/ffi.rs +++ b/src/mac/ffi.rs @@ -84,7 +84,7 @@ extern "C" { pub fn vm_deallocate(target_task: u32, address: *mut i32, size: u32) -> kern_return_t; pub fn sysctlbyname( name: *const c_char, - oldp: *mut u64, + oldp: *mut c_void, oldlenp: *mut usize, newp: *mut c_void, newlen: usize, diff --git a/src/mac/mod.rs b/src/mac/mod.rs index 7bc9da3d0..1ae6e4f8a 100644 --- a/src/mac/mod.rs +++ b/src/mac/mod.rs @@ -16,5 +16,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, get_vendor_id, Processor}; +pub use self::processor::Processor; pub use self::system::System; diff --git a/src/mac/process.rs b/src/mac/process.rs index 65ffb013d..d5c60cf03 100644 --- a/src/mac/process.rs +++ b/src/mac/process.rs @@ -13,6 +13,7 @@ use std::path::{Path, PathBuf}; use libc::{c_int, c_void, gid_t, kill, size_t, uid_t}; +use LoadAvg; use Pid; use ProcessExt; @@ -296,6 +297,18 @@ impl ProcessExt for Process { fn cpu_usage(&self) -> f32 { self.cpu_usage } + + fn get_avg_load(&self) -> LoadAvg { + let loads = vec![0f64; 3]; + unsafe { + ffi::getloadavg(loads.as_ptr() as *const f64, 3); + } + LoadAvg { + one: loads[0], + five: loads[1], + fifteen: loads[2], + } + } } #[allow(unused_must_use)] diff --git a/src/mac/processor.rs b/src/mac/processor.rs index 62db4fb29..0e0546348 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -9,7 +9,6 @@ use std::ops::Deref; use std::sync::Arc; use sys::ffi; -use LoadAvg; use ProcessorExt; pub struct UnsafePtr(*mut T); @@ -56,14 +55,23 @@ pub struct Processor { name: String, cpu_usage: f32, processor_data: Arc, + frequency: u64, + vendor_id: String, } impl Processor { - fn new(name: String, processor_data: Arc) -> Processor { + pub(crate) fn new( + name: String, + processor_data: Arc, + frequency: u64, + vendor_id: String, + ) -> Processor { Processor { name, cpu_usage: 0f32, processor_data, + frequency, + vendor_id, } } } @@ -76,16 +84,20 @@ impl ProcessorExt for Processor { fn get_name(&self) -> &str { &self.name } + + fn get_frequency(&self) -> u64 { + self.frequency + } + + fn get_vendor_id(&self) -> &str { + &self.vendor_id + } } pub fn set_cpu_usage(p: &mut Processor, usage: f32) { p.cpu_usage = usage; } -pub fn create_proc(name: String, processor_data: Arc) -> Processor { - Processor::new(name, processor_data) -} - pub fn update_proc(p: &mut Processor, cpu_usage: f32, processor_data: Arc) { p.cpu_usage = cpu_usage; p.processor_data = processor_data; @@ -105,8 +117,8 @@ pub fn get_cpu_frequency() -> u64 { let mut len = std::mem::size_of::(); unsafe { ffi::sysctlbyname( - "hw.cpufrequency".as_ptr() as *const c_char, - &mut speed, + b"hw.cpufrequency\0".as_ptr() as *const c_char, + &mut speed as *mut _ as _, &mut len, std::ptr::null_mut(), 0, @@ -118,19 +130,36 @@ pub fn get_cpu_frequency() -> u64 { /// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). pub fn get_vendor_id() -> String { - // TODO: support Mac - "".to_owned() -} + let mut len = 0; -/// get_avg_load returns the system load average value. -pub fn get_avg_load() -> LoadAvg { - let loads = vec![0f64; 3]; unsafe { - ffi::getloadavg(loads.as_ptr() as *const f64, 3); + ffi::sysctlbyname( + b"machdep.cpu.brand_string\0".as_ptr() as *const c_char, + std::ptr::null_mut(), + &mut len, + std::ptr::null_mut(), + 0, + ); + } + if len < 1 { + return String::new(); + } + let mut buf = Vec::with_capacity(len); + unsafe { + ffi::sysctlbyname( + b"machdep.cpu.brand_string\0".as_ptr() as *const c_char, + buf.as_mut_ptr() as _, + &mut len, + std::ptr::null_mut(), + 0, + ); } - LoadAvg { - one: loads[0], - five: loads[1], - fifteen: loads[2], + if len > 0 { + unsafe { + buf.set_len(len); + } + String::from_utf8(buf).unwrap_or_else(|_| String::new()) + } else { + String::new() } } diff --git a/src/mac/system.rs b/src/mac/system.rs index 1903cf742..7a300acab 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -183,6 +183,8 @@ impl SystemExt for System { if self.processors.is_empty() { let mut num_cpu = 0; + let vendor_id = get_vendor_id(); + let frequency = get_cpu_frequency(); if !get_sys_value( ffi::CTL_HW, @@ -194,9 +196,11 @@ impl SystemExt for System { num_cpu = 1; } - self.processors.push(processor::create_proc( + self.processors.push(Processor::new( "0".to_owned(), Arc::new(ProcessorData::new(::std::ptr::null_mut(), 0)), + frequency, + vendor_id.clone(), )); if ffi::host_processor_info( self.port, @@ -208,8 +212,12 @@ impl SystemExt for System { { let proc_data = Arc::new(ProcessorData::new(cpu_info, num_cpu_info)); for i in 0..num_cpu { - let mut p = - processor::create_proc(format!("{}", i + 1), Arc::clone(&proc_data)); + let mut p = Processor::new( + format!("{}", i + 1), + Arc::clone(&proc_data), + frequency, + vendor_id.clone(), + ); let in_use = *cpu_info.offset( (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize, ) + *cpu_info.offset( From 347ca3894cca20ee5265cf0d1246a9178a2e865e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2020 22:54:30 +0100 Subject: [PATCH 071/171] Clean up weird mac API --- src/mac/process.rs | 13 ------------- src/mac/processor.rs | 33 ++++++++++++++------------------- src/mac/system.rs | 24 +++++++++++++++++------- 3 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/mac/process.rs b/src/mac/process.rs index d5c60cf03..65ffb013d 100644 --- a/src/mac/process.rs +++ b/src/mac/process.rs @@ -13,7 +13,6 @@ use std::path::{Path, PathBuf}; use libc::{c_int, c_void, gid_t, kill, size_t, uid_t}; -use LoadAvg; use Pid; use ProcessExt; @@ -297,18 +296,6 @@ impl ProcessExt for Process { fn cpu_usage(&self) -> f32 { self.cpu_usage } - - fn get_avg_load(&self) -> LoadAvg { - let loads = vec![0f64; 3]; - unsafe { - ffi::getloadavg(loads.as_ptr() as *const f64, 3); - } - LoadAvg { - one: loads[0], - five: loads[1], - fifteen: loads[2], - } - } } #[allow(unused_must_use)] diff --git a/src/mac/processor.rs b/src/mac/processor.rs index 0e0546348..cacdb3ce9 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -74,6 +74,19 @@ impl Processor { vendor_id, } } + + pub(crate) fn set_cpu_usage(&mut self, cpu_usage: f32) { + self.cpu_usage = cpu_usage; + } + + pub(crate) fn update(&mut self, cpu_usage: f32, processor_data: Arc) { + self.cpu_usage = cpu_usage; + self.processor_data = processor_data; + } + + pub(crate) fn get_data(&self) -> Arc { + Arc::clone(&self.processor_data) + } } impl ProcessorExt for Processor { @@ -85,6 +98,7 @@ impl ProcessorExt for Processor { &self.name } + /// Returns the processor frequency in MHz. fn get_frequency(&self) -> u64 { self.frequency } @@ -94,24 +108,6 @@ impl ProcessorExt for Processor { } } -pub fn set_cpu_usage(p: &mut Processor, usage: f32) { - p.cpu_usage = usage; -} - -pub fn update_proc(p: &mut Processor, cpu_usage: f32, processor_data: Arc) { - p.cpu_usage = cpu_usage; - p.processor_data = processor_data; -} - -pub fn set_cpu_proc(p: &mut Processor, cpu_usage: f32) { - p.cpu_usage = cpu_usage; -} - -pub fn get_processor_data(p: &Processor) -> Arc { - Arc::clone(&p.processor_data) -} - -/// get_cpu_frequency returns the CPU frequency in MHz pub fn get_cpu_frequency() -> u64 { let mut speed: u64 = 0; let mut len = std::mem::size_of::(); @@ -128,7 +124,6 @@ pub fn get_cpu_frequency() -> u64 { speed } -/// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). pub fn get_vendor_id() -> String { let mut len = 0; diff --git a/src/mac/system.rs b/src/mac/system.rs index 7a300acab..c7ba5f5f9 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -11,13 +11,12 @@ use sys::network::{self, NetworkData}; use sys::process::*; use sys::processor::*; -use {DiskExt, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; +use {DiskExt, LoadAvg, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; use std::cell::UnsafeCell; use std::collections::HashMap; use std::mem; use std::sync::Arc; -use sys::processor; use libc::{self, c_int, c_void, size_t, sysconf, _SC_PAGESIZE}; @@ -229,7 +228,7 @@ impl SystemExt for System { + *cpu_info.offset( (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize, ); - processor::set_cpu_proc(&mut p, in_use as f32 / total as f32); + p.set_cpu_usage(in_use as f32 / total as f32); self.processors.push(p); } } @@ -244,7 +243,7 @@ impl SystemExt for System { let mut pourcent = 0f32; let proc_data = Arc::new(ProcessorData::new(cpu_info, num_cpu_info)); for (i, proc_) in self.processors.iter_mut().skip(1).enumerate() { - let old_proc_data = &*processor::get_processor_data(proc_); + let old_proc_data = &*proc_.get_data(); let in_use = (*cpu_info.offset( (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize, @@ -265,8 +264,7 @@ impl SystemExt for System { ) - *old_proc_data.cpu_info.offset( (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize, )); - processor::update_proc( - proc_, + proc_.update( in_use as f32 / total as f32, Arc::clone(&proc_data), ); @@ -275,7 +273,7 @@ impl SystemExt for System { if self.processors.len() > 1 { let len = self.processors.len() - 1; if let Some(p) = self.processors.get_mut(0) { - processor::set_cpu_usage(p, pourcent / len as f32); + p.set_cpu_usage(pourcent / len as f32); } } } @@ -390,6 +388,18 @@ impl SystemExt for System { fn get_uptime(&self) -> u64 { self.uptime } + + fn get_avg_load(&self) -> LoadAvg { + let loads = vec![0f64; 3]; + unsafe { + ffi::getloadavg(loads.as_ptr() as *const f64, 3); + } + LoadAvg { + one: loads[0], + five: loads[1], + fifteen: loads[2], + } + } } impl Default for System { From 029d07129298db1b2e27d750cb7621917bde8570 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2020 23:01:13 +0100 Subject: [PATCH 072/171] Add new methods for windows --- src/windows/processor.rs | 10 ++++++++++ src/windows/system.rs | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 5e79aa70f..5289a5a17 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -260,6 +260,16 @@ impl ProcessorExt for Processor { fn get_name(&self) -> &str { &self.name } + + // Not yet implemented. + fn get_frequency(&self) -> u64 { + 0 + } + + // Not yet implemented. + fn get_vendor_id(&self) -> &str { + "" + } } impl Processor { diff --git a/src/windows/system.rs b/src/windows/system.rs index 40dc3f961..f1dbeacc7 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -434,6 +434,15 @@ impl SystemExt for System { fn get_uptime(&self) -> u64 { self.uptime } + + /// Not yet implemented. + fn get_avg_load(&self) -> LoadAvg { + LoadAvg { + one: 0., + five: 0., + fifteen: 0., + } + } } fn is_proc_running(handle: HANDLE) -> bool { From 2101ee4751d83e35d25e9a68c04e964d8cbcb4f5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2020 23:03:17 +0100 Subject: [PATCH 073/171] Implement API for unknown as well --- src/unknown/mod.rs | 2 +- src/unknown/processor.rs | 18 ++++++------------ src/unknown/system.rs | 8 ++++++++ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/unknown/mod.rs b/src/unknown/mod.rs index 6ce307c97..9238248b9 100644 --- a/src/unknown/mod.rs +++ b/src/unknown/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, get_vendor_id, Processor}; +pub use self::processor::Processor; pub use self::system::System; diff --git a/src/unknown/processor.rs b/src/unknown/processor.rs index 7c719064f..9fa77276b 100644 --- a/src/unknown/processor.rs +++ b/src/unknown/processor.rs @@ -20,18 +20,12 @@ impl ProcessorExt for Processor { fn get_name(&self) -> &str { "" } -} - -pub fn get_cpu_frequency() -> u64 { - 0 -} -/// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). -pub fn get_vendor_id() -> String { - "".to_owned() -} + fn get_frequency(&self) -> u64 { + 0 + } -/// get_avg_load returns the system load average value. -pub fn get_avg_load() -> LoadAvg { - LoadAvg::default() + fn get_vendor_id(&self) -> &str { + "" + } } diff --git a/src/unknown/system.rs b/src/unknown/system.rs index 14ed598e0..8011c4675 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -102,6 +102,14 @@ impl SystemExt for System { fn get_uptime(&self) -> u64 { 0 } + + fn get_avg_load(&self) -> LoadAvg { + LoadAvg { + one: 0., + five: 0., + fifteen: 0., + } + } } impl Default for System { From 7512696c3a594006d5329b2fc2301fbd36a4226e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2020 23:14:10 +0100 Subject: [PATCH 074/171] rename load_avg method --- src/linux/system.rs | 2 +- src/mac/system.rs | 2 +- src/traits.rs | 2 +- src/unknown/system.rs | 2 +- src/windows/processor.rs | 2 +- src/windows/system.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index feb195fe7..0cf9d819b 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -374,7 +374,7 @@ impl SystemExt for System { self.uptime } - fn get_avg_load(&self) -> LoadAvg { + fn get_load_average(&self) -> LoadAvg { let mut s = String::new(); if let Err(_) = File::open("/proc/loadavg").and_then(|mut f| f.read_to_string(&mut s)) { return LoadAvg::default(); diff --git a/src/mac/system.rs b/src/mac/system.rs index c7ba5f5f9..6e1f1838a 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -389,7 +389,7 @@ impl SystemExt for System { self.uptime } - fn get_avg_load(&self) -> LoadAvg { + fn get_load_average(&self) -> LoadAvg { let loads = vec![0f64; 3]; unsafe { ffi::getloadavg(loads.as_ptr() as *const f64, 3); diff --git a/src/traits.rs b/src/traits.rs index 337e12bdb..da35cb52a 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -284,7 +284,7 @@ pub trait SystemExt: Sized { fn get_uptime(&self) -> u64; /// Returns the system load average value. - fn get_avg_load(&self) -> LoadAvg; + fn get_load_average(&self) -> LoadAvg; } /// Getting volume of incoming and outgoing data. diff --git a/src/unknown/system.rs b/src/unknown/system.rs index 8011c4675..d321fdd01 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -103,7 +103,7 @@ impl SystemExt for System { 0 } - fn get_avg_load(&self) -> LoadAvg { + fn get_load_average(&self) -> LoadAvg { LoadAvg { one: 0., five: 0., diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 5289a5a17..c0a09c4f0 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -311,6 +311,6 @@ pub fn get_vendor_id() -> String { } /// get_avg_load returns the system load average value. -pub fn get_avg_load() -> LoadAvg { +pub fn get_load_average() -> LoadAvg { LoadAvg::default() } diff --git a/src/windows/system.rs b/src/windows/system.rs index f1dbeacc7..5a276bda4 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -436,7 +436,7 @@ impl SystemExt for System { } /// Not yet implemented. - fn get_avg_load(&self) -> LoadAvg { + fn get_load_average(&self) -> LoadAvg { LoadAvg { one: 0., five: 0., From 564ab541730d75a5d4534b499bc38800318c04d1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2020 23:14:23 +0100 Subject: [PATCH 075/171] Add new methods into examples as well --- examples/src/simple.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index a623ce9ab..5f364d37c 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -38,6 +38,9 @@ fn print_help() { writeln!(&mut io::stdout(), "network : Displays network' information"); writeln!(&mut io::stdout(), "all : Displays all process name and pid"); writeln!(&mut io::stdout(), "uptime : Displays system uptime"); + writeln!(&mut io::stdout(), "vendor_id : Displays processor vendor id"); + writeln!(&mut io::stdout(), "load_avg : Displays system load average"); + writeln!(&mut io::stdout(), "frequency : Displays processor frequency"); writeln!(&mut io::stdout(), "quit : exit the program"); } @@ -78,6 +81,18 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { writeln!(&mut io::stdout(), "{}:{} status={:?}", pid, proc_.name(), proc_.status()); } } + "frequency" => { + writeln!(&mut io::stdout(), "{} MHz", sys.get_processor_list()[0].get_frequency()); + } + "vendor_id" => { + writeln!(&mut io::stdout(), "vendor ID: {}", sys.get_processor_list()[0].get_vendor_id()); + } + "load_avg" => { + let load_avg = sys.get_load_average(); + writeln!(&mut io::stdout(), "one minute : {}%", load_avg.one); + writeln!(&mut io::stdout(), "five minutes : {}%", load_avg.five); + writeln!(&mut io::stdout(), "fifteen minutes: {}%", load_avg.fifteen); + } e if e.starts_with("show ") => { let tmp : Vec<&str> = e.split(' ').collect(); From 4e0401719b7801fc03311dbaec29b9a9321ee446 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2020 23:17:25 +0100 Subject: [PATCH 076/171] Handle CTRL+D in example --- examples/src/simple.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index 5f364d37c..14b84a5f1 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -216,6 +216,12 @@ fn main() { io::stdout().flush(); stin.read_line(&mut input); + if input.is_empty() { + // The string is empty, meaning there is no '\n', meaning + // that the user used CTRL+D so we can just quit! + println!("\nLeaving, bye!"); + break; + } if (&input as &str).ends_with('\n') { input.pop(); } From 338e3ed9009c9a3f1d5734a6b5468adb3d2312ae Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sun, 26 Jan 2020 23:29:07 +0100 Subject: [PATCH 077/171] windows --- src/windows/mod.rs | 2 +- src/windows/system.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/windows/mod.rs b/src/windows/mod.rs index f6bbda86f..95e5ded57 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -34,5 +34,5 @@ pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, get_vendor_id, Processor}; +pub use self::processor::Processor; pub use self::system::System; diff --git a/src/windows/system.rs b/src/windows/system.rs index 5a276bda4..afb577e96 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -13,6 +13,7 @@ use std::collections::HashMap; use std::mem::{size_of, zeroed}; use DiskExt; +use LoadAvg; use Pid; use ProcessExt; use RefreshKind; From d05a3a4dc2585ecda8314bed9161a6f368e948dd Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sun, 26 Jan 2020 23:39:05 +0100 Subject: [PATCH 078/171] Remove unneeded dependencies and unused functions --- Cargo.toml | 4 -- src/io.rs | 4 ++ src/sysinfo.rs | 82 ---------------------------------------- src/windows/processor.rs | 18 --------- 4 files changed, 4 insertions(+), 104 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 016327ec6..dfdf9be6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,10 +16,6 @@ build = "build.rs" cfg-if = "0.1" rayon = "^1.0" doc-comment = "0.3" -walkdir = "2.2.9" -pnet_datalink = "0.23.0" -num_cpus = "1.11.1" -cache-size = "0.4.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase"] } diff --git a/src/io.rs b/src/io.rs index ae6debd56..e30186215 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,7 +1,11 @@ use std::collections::HashMap; +#[cfg(unix)] use std::fs::File; +#[cfg(unix)] use std::io::Read; +use NICLoad; + /// IOLoad represents current system block devices IO statistics #[derive(Debug)] pub struct IOLoad { diff --git a/src/sysinfo.rs b/src/sysinfo.rs index a30739d98..26a1f5d3f 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -48,8 +48,6 @@ //#![deny(warnings)] #![allow(unknown_lints)] -extern crate num_cpus; - #[macro_use] extern crate cfg_if; #[cfg(not(any(target_os = "unknown", target_arch = "wasm32")))] @@ -80,13 +78,9 @@ cfg_if! { } } -pub extern crate cache_size; -pub extern crate pnet_datalink as datalink; - pub use common::{AsU32, Pid, RefreshKind}; pub use io::IOLoad; pub use net::NICLoad; -pub use num_cpus::{get as get_logical_cores, get_physical as get_physical_cores}; pub use sys::{Component, Disk, DiskType, NetworkData, Process, ProcessStatus, Processor, System}; pub use traits::{ComponentExt, DiskExt, NetworkExt, ProcessExt, ProcessorExt, SystemExt}; @@ -95,8 +89,6 @@ pub use traits::{ComponentExt, DiskExt, NetworkExt, ProcessExt, ProcessorExt, Sy pub use c_interface::*; pub use utils::get_current_pid; -use std::collections::HashMap; - #[cfg(feature = "c-interface")] mod c_interface; mod common; @@ -230,35 +222,6 @@ pub struct LoadAvg { pub fifteen: f64, } -/// Returns system wide configuration -/// -/// # Notes -/// -/// Current only can be used in operating system mounted `procfs` -pub fn get_sysctl_list() -> HashMap { - const DIR: &str = "/proc/sys/"; - let mut result = HashMap::new(); - for entry in walkdir::WalkDir::new(DIR) { - let entry = match entry { - Ok(entry) => entry, - _ => continue, - }; - - let content = match std::fs::read_to_string(entry.path()) { - Ok(c) => c, - _ => continue, - }; - - let path = match entry.path().to_str() { - Some(p) => p, - _ => continue, - }; - let name = path.trim_start_matches(DIR).replace("/", "."); - result.insert(name, content.trim().to_string()); - } - result -} - #[cfg(test)] mod test { use super::*; @@ -275,49 +238,4 @@ mod test { false ); } - - #[test] - fn test_get_cpu_frequency() { - println!("test get_cpu_frequency: {}", ::get_cpu_frequency()); - } - - #[test] - fn test_get_avg_load() { - println!("test get_avg_load: {:?}", ::get_avg_load()); - } - - #[test] - fn test_nic_load() { - println!("test test_nic_load: {:?}", ::NICLoad::snapshot()); - } - - #[test] - fn test_io_load() { - println!("test test_io_load: {:?}", ::IOLoad::snapshot()); - } - - #[test] - fn test_get_cores() { - assert_ne!(::get_logical_cores(), 0, "expect none-zero logical core"); - assert_ne!(::get_physical_cores(), 0, "expect none-zero physical core"); - } - - #[test] - fn test_cache_size() { - if get_vendor_id() == "AuthenticAMD" { - return; - } - - let caches = vec![ - ("l1-cache-size", ::cache_size::l1_cache_size()), - ("l1-cache-line-size", ::cache_size::l1_cache_line_size()), - ("l2-cache-size", ::cache_size::l2_cache_size()), - ("l2-cache-line-size", ::cache_size::l2_cache_line_size()), - ("l3-cache-size", ::cache_size::l3_cache_size()), - ("l3-cache-line-size", ::cache_size::l3_cache_line_size()), - ]; - for c in caches { - assert_ne!(c.1.unwrap(), 0, "{} expect non-zero", c.0) - } - } } diff --git a/src/windows/processor.rs b/src/windows/processor.rs index c0a09c4f0..3f8cc72cf 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -5,13 +5,11 @@ // use std::collections::HashMap; -use std::default::Default; use std::sync::{Arc, Mutex}; use std::thread::{self /*, sleep*/, JoinHandle}; //use std::time::Duration; use windows::tools::KeyHandler; -use LoadAvg; use ProcessorExt; use winapi::shared::minwindef::{FALSE, ULONG}; @@ -298,19 +296,3 @@ pub fn get_key_idle(p: &mut Processor) -> &mut Option { pub fn get_key_used(p: &mut Processor) -> &mut Option { &mut p.key_used } - -pub fn get_cpu_frequency() -> u64 { - // TODO: support windows - 0 -} - -/// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). -pub fn get_vendor_id() -> String { - // TODO: support windows - "".to_owned() -} - -/// get_avg_load returns the system load average value. -pub fn get_load_average() -> LoadAvg { - LoadAvg::default() -} From e70594d45522585f2438919f74da8f648c034d19 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sun, 26 Jan 2020 23:51:30 +0100 Subject: [PATCH 079/171] remove windows warnings --- src/sysinfo.rs | 12 ++++++------ src/traits.rs | 9 +++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 26a1f5d3f..54d08a1ad 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -112,21 +112,21 @@ mod utils; /// Note that if you set a limit bigger than the system limit, the system limit will be set. /// /// Returns `true` if the new value has been set. -pub fn set_open_files_limit(mut new_limit: isize) -> bool { +pub fn set_open_files_limit(mut _new_limit: isize) -> bool { #[cfg(all(not(target_os = "macos"), unix))] { - if new_limit < 0 { - new_limit = 0; + if _new_limit < 0 { + _new_limit = 0; } let max = sys::system::get_max_nb_fds(); - if new_limit > max { - new_limit = max; + if _new_limit > max { + _new_limit = max; } return if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } { // If files are already open, to be sure that the number won't be bigger when those // files are closed, we subtract the current number of opened files to the new limit. let diff = max - **x; - **x = new_limit - diff; + **x = _new_limit - diff; true } else { false diff --git a/src/traits.rs b/src/traits.rs index da35cb52a..a495c3460 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -15,6 +15,15 @@ use std::ffi::OsStr; use std::path::Path; /// Contains all the methods of the `Disk` struct. +/// +/// ```no_run +/// use sysinfo::{DiskExt, System, SystemExt}; +/// +/// let s = System::new(); +/// for disk in s.get_disks() { +/// println!("{:?}: {:?}", disk.get_name(), disk.get_type()); +/// } +/// ``` pub trait DiskExt { /// Returns the disk type. fn get_type(&self) -> DiskType; From f8d766aef47e52961cddd553133b63eeff0b657e Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Mon, 27 Jan 2020 00:19:25 +0100 Subject: [PATCH 080/171] Add code examples --- src/traits.rs | 477 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 475 insertions(+), 2 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index a495c3460..d3622ef14 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -26,24 +26,79 @@ use std::path::Path; /// ``` pub trait DiskExt { /// Returns the disk type. + /// + /// ```no_run + /// use sysinfo::{DiskExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for disk in s.get_disks() { + /// println!("{:?}", disk.get_type()); + /// } + /// ``` fn get_type(&self) -> DiskType; /// Returns the disk name. + /// + /// ```no_run + /// use sysinfo::{DiskExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for disk in s.get_disks() { + /// println!("{:?}", disk.get_name()); + /// } + /// ``` fn get_name(&self) -> &OsStr; /// Returns the file system used on this disk (so for example: `EXT4`, `NTFS`, etc...). + /// + /// ```no_run + /// use sysinfo::{DiskExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for disk in s.get_disks() { + /// println!("{:?}", disk.get_file_system()); + /// } + /// ``` fn get_file_system(&self) -> &[u8]; /// Returns the mount point of the disk (`/` for example). + /// + /// ```no_run + /// use sysinfo::{DiskExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for disk in s.get_disks() { + /// println!("{:?}", disk.get_mount_point()); + /// } + /// ``` fn get_mount_point(&self) -> &Path; /// Returns the total disk size, in bytes. + /// + /// ```no_run + /// use sysinfo::{DiskExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for disk in s.get_disks() { + /// println!("{}", disk.get_total_space()); + /// } + /// ``` fn get_total_space(&self) -> u64; /// Returns the available disk size, in bytes. + /// + /// ```no_run + /// use sysinfo::{DiskExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for disk in s.get_disks() { + /// println!("{}", disk.get_available_space()); + /// } + /// ``` fn get_available_space(&self) -> u64; /// Update the disk' information. + #[doc(hidden)] fn update(&mut self) -> bool; } @@ -52,56 +107,183 @@ pub trait ProcessExt { /// Create a new process only containing the given information. /// /// On windows, the `start_time` argument is ignored. + #[doc(hidden)] fn new(pid: Pid, parent: Option, start_time: u64) -> Self; /// Sends the given `signal` to the process. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, Signal, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// process.kill(Signal::Kill); + /// } + /// ``` fn kill(&self, signal: ::Signal) -> bool; /// Returns the name of the process. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{}", process.name()); + /// } + /// ``` fn name(&self) -> &str; /// Returns the command line. // /// // /// On Windows, this is always a one element vector. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{:?}", process.cmd()); + /// } + /// ``` fn cmd(&self) -> &[String]; /// Returns the path to the process. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{}", process.exe().display()); + /// } + /// ``` fn exe(&self) -> &Path; /// Returns the pid of the process. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{}", process.pid()); + /// } + /// ``` fn pid(&self) -> Pid; /// Returns the environment of the process. /// - /// Always empty on Windows except for current process. + /// Always empty on Windows, except for current process. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{:?}", process.environ()); + /// } + /// ``` fn environ(&self) -> &[String]; /// Returns the current working directory. /// /// Always empty on Windows. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{}", process.cwd().display()); + /// } + /// ``` fn cwd(&self) -> &Path; /// Returns the path of the root directory. /// /// Always empty on Windows. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{}", process.root().display()); + /// } + /// ``` fn root(&self) -> &Path; /// Returns the memory usage (in KiB). + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{} KiB", process.memory()); + /// } + /// ``` fn memory(&self) -> u64; /// Returns the virtual memory usage (in KiB). + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{} KiB", process.virtual_memory()); + /// } + /// ``` fn virtual_memory(&self) -> u64; /// Returns the parent pid. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{:?}", process.parent()); + /// } + /// ``` fn parent(&self) -> Option; /// Returns the status of the processus. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{:?}", process.status()); + /// } + /// ``` fn status(&self) -> ProcessStatus; /// Returns the time of process launch (in seconds). + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{}", process.start_time()); + /// } + /// ``` fn start_time(&self) -> u64; - /// Returns the total CPU usage. + /// Returns the total CPU usage (in %). + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{}%", process.cpu_usage()); + /// } + /// ``` fn cpu_usage(&self) -> f32; } @@ -111,15 +293,51 @@ pub trait ProcessorExt { /// /// Note: You'll need to refresh it at least twice at first if you want to have a /// non-zero value. + /// + /// ```no_run + /// use sysinfo::{ProcessorExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for processor in s.get_processor_list() { + /// println!("{}%", processor.get_cpu_usage()); + /// } + /// ``` fn get_cpu_usage(&self) -> f32; /// Returns this processor's name. + /// + /// ```no_run + /// use sysinfo::{ProcessorExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for processor in s.get_processor_list() { + /// println!("{}", processor.get_name()); + /// } + /// ``` fn get_name(&self) -> &str; /// Returns the processor's vendor id. + /// + /// ```no_run + /// use sysinfo::{ProcessorExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for processor in s.get_processor_list() { + /// println!("{}", processor.get_vendor_id()); + /// } + /// ``` fn get_vendor_id(&self) -> &str; /// Returns the processor's frequency. + /// + /// ```no_run + /// use sysinfo::{ProcessorExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for processor in s.get_processor_list() { + /// println!("{}", processor.get_frequency()); + /// } + /// ``` fn get_frequency(&self) -> u64; } @@ -130,6 +348,12 @@ pub trait SystemExt: Sized { /// the `refresh_` method). /// /// [`refresh_all`]: #method.refresh_all + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new(); + /// ``` fn new() -> Self { let mut s = Self::new_with_specifics(RefreshKind::new()); s.refresh_disk_list(); @@ -203,6 +427,13 @@ pub trait SystemExt: Sized { /// [`refresh_memory`]: SystemExt::refresh_memory /// [`refresh_cpu`]: SystemExt::refresh_memory /// [`refresh_temperatures`]: SystemExt::refresh_temperatures + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_system(); + /// ``` fn refresh_system(&mut self) { self.refresh_memory(); self.refresh_cpu(); @@ -210,31 +441,94 @@ pub trait SystemExt: Sized { } /// Refresh RAM and SWAP usage. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_memory(); + /// ``` fn refresh_memory(&mut self); /// Refresh CPU usage. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_cpu(); + /// ``` fn refresh_cpu(&mut self); /// Refresh components' temperature. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_temperatures(); + /// ``` fn refresh_temperatures(&mut self); /// Get all processes and update their information. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_processes(); + /// ``` fn refresh_processes(&mut self); /// Refresh *only* the process corresponding to `pid`. Returns `false` if the process doesn't /// exist. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_process(1337); + /// ``` fn refresh_process(&mut self, pid: Pid) -> bool; /// Refreshes the listed disks' information. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_disks(); + /// ``` fn refresh_disks(&mut self); /// The disk list will be emptied then completely recomputed. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_disk_list(); + /// ``` fn refresh_disk_list(&mut self); /// Refresh data network. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_network(); + /// ``` fn refresh_network(&mut self); /// Refreshes all system, processes and disks information. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_all(); + /// ``` fn refresh_all(&mut self) { self.refresh_system(); self.refresh_processes(); @@ -243,12 +537,39 @@ pub trait SystemExt: Sized { } /// Returns the process list. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for (pid, process) in s.get_process_list() { + /// println!("{} {}", pid, process.name()); + /// } + /// ``` fn get_process_list(&self) -> &HashMap; /// Returns the process corresponding to the given pid or `None` if no such process exists. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// if let Some(process) = s.get_process(1337) { + /// println!("{}", process.name()); + /// } + /// ``` fn get_process(&self, pid: Pid) -> Option<&Process>; /// Returns a list of process containing the given `name`. + /// + /// ```no_run + /// use sysinfo::{ProcessExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for process in s.get_process_by_name("htop") { + /// println!("{} {}", process.pid(), process.name()); + /// } + /// ``` fn get_process_by_name(&self, name: &str) -> Vec<&Process> { let mut ret = vec![]; for val in self.get_process_list().values() { @@ -260,59 +581,211 @@ pub trait SystemExt: Sized { } /// The first processor in the array is the "main" one (aka the addition of all the others). + /// + /// ```no_run + /// use sysinfo::{ProcessorExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for processor in s.get_processor_list() { + /// println!("{}%", processor.get_cpu_usage()); + /// } + /// ``` fn get_processor_list(&self) -> &[Processor]; /// Returns total RAM size in KiB. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new(); + /// println!("{} KiB", s.get_total_memory()); + /// ``` fn get_total_memory(&self) -> u64; /// Returns free RAM size in KiB. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new(); + /// println!("{} KiB", s.get_free_memory()); + /// ``` fn get_free_memory(&self) -> u64; /// Returns used RAM size in KiB. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new(); + /// println!("{} KiB", s.get_used_memory()); + /// ``` fn get_used_memory(&self) -> u64; /// Returns SWAP size in KiB. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new(); + /// println!("{} KiB", s.get_total_swap()); + /// ``` fn get_total_swap(&self) -> u64; /// Returns free SWAP size in KiB. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new(); + /// println!("{} KiB", s.get_free_swap()); + /// ``` fn get_free_swap(&self) -> u64; /// Returns used SWAP size in KiB. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new(); + /// println!("{} KiB", s.get_used_swap()); + /// ``` fn get_used_swap(&self) -> u64; /// Returns components list. + /// + /// ```no_run + /// use sysinfo::{ComponentExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for component in s.get_components_list() { + /// println!("{}: {}°C", component.get_label(), component.get_temperature()); + /// } + /// ``` fn get_components_list(&self) -> &[Component]; /// Returns disks' list. + /// + /// ```no_run + /// use sysinfo::{DiskExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for disk in s.get_disks() { + /// println!("{:?}", disk.get_name()); + /// } + /// ``` fn get_disks(&self) -> &[Disk]; /// Returns network data. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, System, SystemExt}; + /// + /// let s = System::new(); + /// let network = s.get_network(); + /// println!("in: {}, out: {}", network.get_income(), network.get_outcome()); + /// ``` fn get_network(&self) -> &NetworkData; /// Returns system uptime. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new(); + /// println!("{}", s.get_uptime()); + /// ``` fn get_uptime(&self) -> u64; /// Returns the system load average value. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new(); + /// let load_avg = s.get_load_average(); + /// println!( + /// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%", + /// load_avg.one, + /// load_avg.five, + /// load_avg.fifteen, + /// ); + /// ``` fn get_load_average(&self) -> LoadAvg; } /// Getting volume of incoming and outgoing data. pub trait NetworkExt { /// Returns the number of incoming bytes. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, System, SystemExt}; + /// + /// let s = System::new(); + /// let network = s.get_network(); + /// println!("in: {}", network.get_income()); + /// ``` fn get_income(&self) -> u64; /// Returns the number of outgoing bytes. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, System, SystemExt}; + /// + /// let s = System::new(); + /// let network = s.get_network(); + /// println!("out: {}", network.get_outcome()); + /// ``` fn get_outcome(&self) -> u64; } /// Getting a component temperature information. pub trait ComponentExt { /// Returns the component's temperature (in celsius degree). + /// + /// ```no_run + /// use sysinfo::{ComponentExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for component in s.get_components_list() { + /// println!("{}°C", component.get_temperature()); + /// } + /// ``` fn get_temperature(&self) -> f32; + /// Returns the maximum temperature of this component. + /// + /// ```no_run + /// use sysinfo::{ComponentExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for component in s.get_components_list() { + /// println!("{}°C", component.get_max()); + /// } + /// ``` fn get_max(&self) -> f32; + /// Returns the highest temperature before the computer halts. + /// + /// ```no_run + /// use sysinfo::{ComponentExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for component in s.get_components_list() { + /// println!("{:?}°C", component.get_critical()); + /// } + /// ``` fn get_critical(&self) -> Option; + /// Returns component's label. + /// + /// ```no_run + /// use sysinfo::{ComponentExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for component in s.get_components_list() { + /// println!("{}", component.get_label()); + /// } + /// ``` fn get_label(&self) -> &str; } From a3bf93f4e055a17159c7967742272a4dfb7a4b1b Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 28 Jan 2020 01:02:16 +0100 Subject: [PATCH 081/171] Clean up simple.rs --- examples/src/simple.rs | 274 +++++++++++++++++++++++++++++++---------- 1 file changed, 212 insertions(+), 62 deletions(-) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index 14b84a5f1..8bbc9be97 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -1,46 +1,122 @@ -// +// // Sysinfo -// +// // Copyright (c) 2017 Guillaume Gomez // #![crate_type = "bin"] - #![allow(unused_must_use, non_upper_case_globals)] extern crate sysinfo; -use sysinfo::{NetworkExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt}; -use sysinfo::Signal::*; use std::io::{self, BufRead, Write}; use std::str::FromStr; +use sysinfo::Signal::*; +use sysinfo::{NetworkExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt}; -const signals: [Signal; 31] = [Hangup, Interrupt, Quit, Illegal, Trap, Abort, Bus, - FloatingPointException, Kill, User1, Segv, User2, Pipe, Alarm, - Term, Stklft, Child, Continue, Stop, TSTP, TTIN, TTOU, Urgent, - XCPU, XFSZ, VirtualAlarm, Profiling, Winch, IO, Power, Sys]; +const signals: [Signal; 31] = [ + Hangup, + Interrupt, + Quit, + Illegal, + Trap, + Abort, + Bus, + FloatingPointException, + Kill, + User1, + Segv, + User2, + Pipe, + Alarm, + Term, + Stklft, + Child, + Continue, + Stop, + TSTP, + TTIN, + TTOU, + Urgent, + XCPU, + XFSZ, + VirtualAlarm, + Profiling, + Winch, + IO, + Power, + Sys, +]; fn print_help() { writeln!(&mut io::stdout(), "== Help menu =="); writeln!(&mut io::stdout(), "help : show this menu"); - writeln!(&mut io::stdout(), "signals : show the available signals"); - writeln!(&mut io::stdout(), "refresh : reloads all processes' information"); - writeln!(&mut io::stdout(), "refresh [pid] : reloads corresponding process' information"); - writeln!(&mut io::stdout(), "refresh_disks : reloads only disks' information"); - writeln!(&mut io::stdout(), "show [pid | name] : show information of the given process \ - corresponding to [pid | name]"); - writeln!(&mut io::stdout(), "kill [pid] [signal]: send [signal] to the process with this \ - [pid]. 0 < [signal] < 32"); - writeln!(&mut io::stdout(), "proc : Displays proc state"); - writeln!(&mut io::stdout(), "memory : Displays memory state"); - writeln!(&mut io::stdout(), "temperature : Displays components' temperature"); - writeln!(&mut io::stdout(), "disks : Displays disks' information"); - writeln!(&mut io::stdout(), "network : Displays network' information"); - writeln!(&mut io::stdout(), "all : Displays all process name and pid"); - writeln!(&mut io::stdout(), "uptime : Displays system uptime"); - writeln!(&mut io::stdout(), "vendor_id : Displays processor vendor id"); - writeln!(&mut io::stdout(), "load_avg : Displays system load average"); - writeln!(&mut io::stdout(), "frequency : Displays processor frequency"); + writeln!( + &mut io::stdout(), + "signals : show the available signals" + ); + writeln!( + &mut io::stdout(), + "refresh : reloads all processes' information" + ); + writeln!( + &mut io::stdout(), + "refresh [pid] : reloads corresponding process' information" + ); + writeln!( + &mut io::stdout(), + "refresh_disks : reloads only disks' information" + ); + writeln!( + &mut io::stdout(), + "show [pid | name] : show information of the given process \ + corresponding to [pid | name]" + ); + writeln!( + &mut io::stdout(), + "kill [pid] [signal]: send [signal] to the process with this \ + [pid]. 0 < [signal] < 32" + ); + writeln!( + &mut io::stdout(), + "proc : Displays proc state" + ); + writeln!( + &mut io::stdout(), + "memory : Displays memory state" + ); + writeln!( + &mut io::stdout(), + "temperature : Displays components' temperature" + ); + writeln!( + &mut io::stdout(), + "disks : Displays disks' information" + ); + writeln!( + &mut io::stdout(), + "network : Displays network' information" + ); + writeln!( + &mut io::stdout(), + "all : Displays all process name and pid" + ); + writeln!( + &mut io::stdout(), + "uptime : Displays system uptime" + ); + writeln!( + &mut io::stdout(), + "vendor_id : Displays processor vendor id" + ); + writeln!( + &mut io::stdout(), + "load_avg : Displays system load average" + ); + writeln!( + &mut io::stdout(), + "frequency : Displays processor frequency" + ); writeln!(&mut io::stdout(), "quit : exit the program"); } @@ -64,28 +140,64 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { // Note: you should refresh a few times before using this, so that usage statistics can be ascertained let procs = sys.get_processor_list(); - writeln!(&mut io::stdout(), "total process usage: {}%", procs[0].get_cpu_usage()); + writeln!( + &mut io::stdout(), + "total process usage: {}%", + procs[0].get_cpu_usage() + ); for proc_ in procs.iter().skip(1) { writeln!(&mut io::stdout(), "{:?}", proc_); } } "memory" => { - writeln!(&mut io::stdout(), "total memory: {} KiB", sys.get_total_memory()); - writeln!(&mut io::stdout(), "used memory : {} KiB", sys.get_used_memory()); - writeln!(&mut io::stdout(), "total swap : {} KiB", sys.get_total_swap()); - writeln!(&mut io::stdout(), "used swap : {} KiB", sys.get_used_swap()); + writeln!( + &mut io::stdout(), + "total memory: {} KiB", + sys.get_total_memory() + ); + writeln!( + &mut io::stdout(), + "used memory : {} KiB", + sys.get_used_memory() + ); + writeln!( + &mut io::stdout(), + "total swap : {} KiB", + sys.get_total_swap() + ); + writeln!( + &mut io::stdout(), + "used swap : {} KiB", + sys.get_used_swap() + ); } "quit" | "exit" => return true, "all" => { for (pid, proc_) in sys.get_process_list() { - writeln!(&mut io::stdout(), "{}:{} status={:?}", pid, proc_.name(), proc_.status()); + writeln!( + &mut io::stdout(), + "{}:{} status={:?}", + pid, + proc_.name(), + proc_.status() + ); } } "frequency" => { - writeln!(&mut io::stdout(), "{} MHz", sys.get_processor_list()[0].get_frequency()); + let procs = sys.get_processor_list(); + // On windows, the first processor is the "all processors", so not interesting in here. + writeln!( + &mut io::stdout(), + "{} MHz", + procs[if procs.len() > 1 { 1 } else { 0 }].get_frequency() + ); } "vendor_id" => { - writeln!(&mut io::stdout(), "vendor ID: {}", sys.get_processor_list()[0].get_vendor_id()); + writeln!( + &mut io::stdout(), + "vendor ID: {}", + sys.get_processor_list()[0].get_vendor_id() + ); } "load_avg" => { let load_avg = sys.get_load_average(); @@ -94,10 +206,13 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { writeln!(&mut io::stdout(), "fifteen minutes: {}%", load_avg.fifteen); } e if e.starts_with("show ") => { - let tmp : Vec<&str> = e.split(' ').collect(); + let tmp: Vec<&str> = e.split(' ').collect(); if tmp.len() != 2 { - writeln!(&mut io::stdout(), "show command takes a pid or a name in parameter!"); + writeln!( + &mut io::stdout(), + "show command takes a pid or a name in parameter!" + ); writeln!(&mut io::stdout(), "example: show 1254"); } else if let Ok(pid) = Pid::from_str(tmp[1]) { match sys.get_process(pid) { @@ -118,33 +233,51 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { } } "network" => { - writeln!(&mut io::stdout(), "input data : {} B", sys.get_network().get_income()); - writeln!(&mut io::stdout(), "output data: {} B", sys.get_network().get_outcome()); + writeln!( + &mut io::stdout(), + "input data : {} B", + sys.get_network().get_income() + ); + writeln!( + &mut io::stdout(), + "output data: {} B", + sys.get_network().get_outcome() + ); } "show" => { - writeln!(&mut io::stdout(), "'show' command expects a pid number or a process name"); + writeln!( + &mut io::stdout(), + "'show' command expects a pid number or a process name" + ); } e if e.starts_with("kill ") => { - let tmp : Vec<&str> = e.split(' ').collect(); + let tmp: Vec<&str> = e.split(' ').collect(); if tmp.len() != 3 { - writeln!(&mut io::stdout(), - "kill command takes the pid and a signal number in parameter !"); + writeln!( + &mut io::stdout(), + "kill command takes the pid and a signal number in parameter !" + ); writeln!(&mut io::stdout(), "example: kill 1254 9"); } else { let pid = Pid::from_str(tmp[1]).unwrap(); let signal = i32::from_str(tmp[2]).unwrap(); if signal < 1 || signal > 31 { - writeln!(&mut io::stdout(), - "Signal must be between 0 and 32 ! See the signals list with the \ - signals command"); + writeln!( + &mut io::stdout(), + "Signal must be between 0 and 32 ! See the signals list with the \ + signals command" + ); } else { match sys.get_process(pid) { Some(p) => { - writeln!(&mut io::stdout(), "kill: {}", - p.kill(*signals.get(signal as usize - 1).unwrap())); - }, + writeln!( + &mut io::stdout(), + "kill: {}", + p.kill(*signals.get(signal as usize - 1).unwrap()) + ); + } None => { writeln!(&mut io::stdout(), "pid not found"); } @@ -164,11 +297,13 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { let hours = uptime / 3600; uptime -= hours * 3600; let minutes = uptime / 60; - writeln!(&mut io::stdout(), - "{} days {} hours {} minutes", - days, - hours, - minutes); + writeln!( + &mut io::stdout(), + "{} days {} hours {} minutes", + days, + hours, + minutes + ); } x if x.starts_with("refresh") => { if x == "refresh" { @@ -177,25 +312,40 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { writeln!(&mut io::stdout(), "Done."); } else if x.starts_with("refresh ") { writeln!(&mut io::stdout(), "Getting process' information..."); - if let Some(pid) = x.split(' ').filter_map(|pid| pid.parse().ok()).take(1).next() { + if let Some(pid) = x + .split(' ') + .filter_map(|pid| pid.parse().ok()) + .take(1) + .next() + { if sys.refresh_process(pid) { writeln!(&mut io::stdout(), "Process `{}` updated successfully", pid); } else { - writeln!(&mut io::stdout(), "Process `{}` couldn't be updated...", pid); + writeln!( + &mut io::stdout(), + "Process `{}` couldn't be updated...", + pid + ); } } else { writeln!(&mut io::stdout(), "Invalid [pid] received..."); } } else { - writeln!(&mut io::stdout(), - "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \ - list.", x); + writeln!( + &mut io::stdout(), + "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \ + list.", + x + ); } } e => { - writeln!(&mut io::stdout(), - "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \ - list.", e); + writeln!( + &mut io::stdout(), + "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \ + list.", + e + ); } } false From 13b91546025a23f1b8ac50802c6ef2efbd5feb5b Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 28 Jan 2020 01:02:37 +0100 Subject: [PATCH 082/171] Add frequency and vendor id on windows --- Cargo.toml | 2 +- src/windows/ffi.rs | 333 --------------------------------------- src/windows/mod.rs | 16 -- src/windows/processor.rs | 138 ++++++++++++++-- src/windows/system.rs | 2 +- src/windows/tools.rs | 49 +----- 6 files changed, 133 insertions(+), 407 deletions(-) delete mode 100644 src/windows/ffi.rs diff --git a/Cargo.toml b/Cargo.toml index dfdf9be6b..f3f68f096 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ rayon = "^1.0" doc-comment = "0.3" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase"] } +winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase", "powerbase"] } ntapi = "0.3" [target.'cfg(not(any(target_os = "unknown", target_arch = "wasm32")))'.dependencies] diff --git a/src/windows/ffi.rs b/src/windows/ffi.rs deleted file mode 100644 index b01faccad..000000000 --- a/src/windows/ffi.rs +++ /dev/null @@ -1,333 +0,0 @@ -// -// Sysinfo -// -// Copyright (c) 2015 Guillaume Gomez -// - -use libc::{c_int, c_char, c_void, c_uchar, c_uint, size_t, uint32_t, uint64_t, c_ushort}; - -extern "C" { - pub static kCFAllocatorDefault: CFAllocatorRef; - - pub fn proc_pidinfo(pid: c_int, flavor: c_int, arg: u64, buffer: *mut c_void, - buffersize: c_int) -> c_int; - pub fn proc_listallpids(buffer: *mut c_void, buffersize: c_int) -> c_int; - //pub fn proc_name(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; - //pub fn proc_regionfilename(pid: c_int, address: u64, buffer: *mut c_void, - // buffersize: u32) -> c_int; - //pub fn proc_pidpath(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; - - pub fn IOMasterPort(a: i32, b: *mut mach_port_t) -> i32; - pub fn IOServiceMatching(a: *const c_char) -> *mut c_void; - pub fn IOServiceGetMatchingServices(a: mach_port_t, b: *mut c_void, c: *mut io_iterator_t) -> i32; - pub fn IOIteratorNext(iterator: io_iterator_t) -> io_object_t; - pub fn IOObjectRelease(obj: io_object_t) -> i32; - pub fn IOServiceOpen(device: io_object_t, a: u32, t: u32, x: *mut io_connect_t) -> i32; - pub fn IOServiceClose(a: io_connect_t) -> i32; - pub fn IOConnectCallStructMethod(connection: mach_port_t, - selector: u32, - inputStruct: *mut KeyData_t, - inputStructCnt: size_t, - outputStruct: *mut KeyData_t, - outputStructCnt: *mut size_t) -> i32; - pub fn IORegistryEntryCreateCFProperties(entry: io_registry_entry_t, - properties: *mut CFMutableDictionaryRef, - allocator: CFAllocatorRef, - options: IOOptionBits) - -> kern_return_t; - pub fn CFDictionaryContainsKey(d: CFDictionaryRef, key: *const c_void) -> Boolean; - pub fn CFDictionaryGetValue(d: CFDictionaryRef, key: *const c_void) -> *const c_void; - pub fn IORegistryEntryGetName(entry: io_registry_entry_t, name: *mut c_char) -> kern_return_t; - pub fn CFRelease(cf: CFTypeRef); - pub fn CFStringCreateWithCStringNoCopy(alloc: *mut c_void, cStr: *const c_char, - encoding: CFStringEncoding, - contentsDeallocator: *mut c_void) -> CFStringRef; - - pub static kCFAllocatorNull: CFAllocatorRef; - - pub fn mach_absolute_time() -> u64; - //pub fn task_for_pid(host: u32, pid: pid_t, task: *mut task_t) -> u32; - pub fn mach_task_self() -> u32; - pub fn mach_host_self() -> u32; - //pub fn task_info(host_info: u32, t: u32, c: *mut c_void, x: *mut u32) -> u32; - pub fn host_statistics64(host_info: u32, x: u32, y: *mut c_void, z: *const u32) -> u32; - pub fn host_processor_info(host_info: u32, t: u32, num_cpu_u: *mut u32, - cpu_info: *mut *mut i32, num_cpu_info: *mut u32) -> u32; - //pub fn host_statistics(host_priv: u32, flavor: u32, host_info: *mut c_void, - // host_count: *const u32) -> u32; - pub fn vm_deallocate(target_task: u32, address: *mut i32, size: u32) -> u32; -} - -// TODO: waiting for https://github.com/rust-lang/libc/pull/678 -macro_rules! cfg_if { - ($( - if #[cfg($($meta:meta),*)] { $($it:item)* } - ) else * else { - $($it2:item)* - }) => { - __cfg_if_items! { - () ; - $( ( ($($meta),*) ($($it)*) ), )* - ( () ($($it2)*) ), - } - } -} - -// TODO: waiting for https://github.com/rust-lang/libc/pull/678 -macro_rules! __cfg_if_items { - (($($not:meta,)*) ; ) => {}; - (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { - __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* } - __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } - } -} - -// TODO: waiting for https://github.com/rust-lang/libc/pull/678 -macro_rules! __cfg_if_apply { - ($m:meta, $($it:item)*) => { - $(#[$m] $it)* - } -} - -// TODO: waiting for https://github.com/rust-lang/libc/pull/678 -cfg_if! { - if #[cfg(any(target_arch = "arm", target_arch = "x86"))] { - pub type timeval32 = ::libc::timeval; - } else { - use libc::timeval32; - } -} - -// TODO: waiting for https://github.com/rust-lang/libc/pull/678 -#[repr(C)] -pub struct if_data64 { - pub ifi_type: c_uchar, - pub ifi_typelen: c_uchar, - pub ifi_physical: c_uchar, - pub ifi_addrlen: c_uchar, - pub ifi_hdrlen: c_uchar, - pub ifi_recvquota: c_uchar, - pub ifi_xmitquota: c_uchar, - pub ifi_unused1: c_uchar, - pub ifi_mtu: uint32_t, - pub ifi_metric: uint32_t, - pub ifi_baudrate: uint64_t, - pub ifi_ipackets: uint64_t, - pub ifi_ierrors: uint64_t, - pub ifi_opackets: uint64_t, - pub ifi_oerrors: uint64_t, - pub ifi_collisions: uint64_t, - pub ifi_ibytes: uint64_t, - pub ifi_obytes: uint64_t, - pub ifi_imcasts: uint64_t, - pub ifi_omcasts: uint64_t, - pub ifi_iqdrops: uint64_t, - pub ifi_noproto: uint64_t, - pub ifi_recvtiming: uint32_t, - pub ifi_xmittiming: uint32_t, - pub ifi_lastchange: timeval32, -} - -// TODO: waiting for https://github.com/rust-lang/libc/pull/678 -#[repr(C)] -pub struct if_msghdr2 { - pub ifm_msglen: c_ushort, - pub ifm_version: c_uchar, - pub ifm_type: c_uchar, - pub ifm_addrs: c_int, - pub ifm_flags: c_int, - pub ifm_index: c_ushort, - pub ifm_snd_len: c_int, - pub ifm_snd_maxlen: c_int, - pub ifm_snd_drops: c_int, - pub ifm_timer: c_int, - pub ifm_data: if_data64, -} - -#[repr(C)] -pub struct __CFAllocator { - __private: c_void, -} - -#[repr(C)] -pub struct __CFDictionary { - __private: c_void, -} - -#[repr(C)] -pub struct __CFString { - __private: c_void, -} - -pub type CFAllocatorRef = *const __CFAllocator; -pub type CFMutableDictionaryRef = *mut __CFDictionary; -pub type CFDictionaryRef = *const __CFDictionary; -#[allow(non_camel_case_types)] -pub type io_name_t = [u8; 128]; -#[allow(non_camel_case_types)] -pub type io_registry_entry_t = io_object_t; -pub type CFTypeRef = *const c_void; -pub type CFStringRef = *const __CFString; - -//#[allow(non_camel_case_types)] -//pub type policy_t = i32; -#[allow(non_camel_case_types)] -//pub type integer_t = i32; -//#[allow(non_camel_case_types)] -//pub type time_t = i64; -//#[allow(non_camel_case_types)] -//pub type suseconds_t = i32; -//#[allow(non_camel_case_types)] -//pub type mach_vm_size_t = u64; -//#[allow(non_camel_case_types)] -//pub type task_t = u32; -//#[allow(non_camel_case_types)] -//pub type pid_t = i32; -#[allow(non_camel_case_types)] -pub type natural_t = u32; -#[allow(non_camel_case_types)] -pub type mach_port_t = u32; -#[allow(non_camel_case_types)] -pub type io_object_t = mach_port_t; -#[allow(non_camel_case_types)] -pub type io_iterator_t = io_object_t; -#[allow(non_camel_case_types)] -pub type io_connect_t = io_object_t; -#[allow(non_camel_case_types)] -pub type boolean_t = c_uint; -#[allow(non_camel_case_types)] -pub type kern_return_t = c_int; -pub type Boolean = c_uchar; -pub type IOOptionBits = u32; -pub type CFStringEncoding = u32; - -/*#[repr(C)] -pub struct task_thread_times_info { - pub user_time: time_value, - pub system_time: time_value, -}*/ - -/*#[repr(C)] -pub struct task_basic_info_64 { - pub suspend_count: integer_t, - pub virtual_size: mach_vm_size_t, - pub resident_size: mach_vm_size_t, - pub user_time: time_value_t, - pub system_time: time_value_t, - pub policy: policy_t, -}*/ - -#[repr(C)] -pub struct vm_statistics64 { - pub free_count: natural_t, - pub active_count: natural_t, - pub inactive_count: natural_t, - pub wire_count: natural_t, - pub zero_fill_count: u64, - pub reactivations: u64, - pub pageins: u64, - pub pageouts: u64, - pub faults: u64, - pub cow_faults: u64, - pub lookups: u64, - pub hits: u64, - pub purges: u64, - pub purgeable_count: natural_t, - pub speculative_count: natural_t, - pub decompressions: u64, - pub compressions: u64, - pub swapins: u64, - pub swapouts: u64, - pub compressor_page_count: natural_t, - pub throttled_count: natural_t, - pub external_page_count: natural_t, - pub internal_page_count: natural_t, - pub total_uncompressed_pages_in_compressor: u64, -} - -#[repr(C)] -pub struct Val_t { - pub key: [i8; 5], - pub data_size: u32, - pub data_type: [i8; 5], // UInt32Char_t - pub bytes: [i8; 32], // SMCBytes_t -} - -#[repr(C)] -pub struct KeyData_vers_t { - pub major: u8, - pub minor: u8, - pub build: u8, - pub reserved: [u8; 1], - pub release: u16, -} - -#[repr(C)] -pub struct KeyData_pLimitData_t { - pub version: u16, - pub length: u16, - pub cpu_plimit: u32, - pub gpu_plimit: u32, - pub mem_plimit: u32, -} - -#[repr(C)] -pub struct KeyData_keyInfo_t { - pub data_size: u32, - pub data_type: u32, - pub data_attributes: u8, -} - -#[repr(C)] -pub struct KeyData_t { - pub key: u32, - pub vers: KeyData_vers_t, - pub p_limit_data: KeyData_pLimitData_t, - pub key_info: KeyData_keyInfo_t, - pub result: u8, - pub status: u8, - pub data8: u8, - pub data32: u32, - pub bytes: [i8; 32], // SMCBytes_t -} - -#[repr(C)] -pub struct xsw_usage { - pub xsu_total: u64, - pub xsu_avail: u64, - pub xsu_used: u64, - pub xsu_pagesize: u32, - pub xsu_encrypted: boolean_t, -} - -//pub const HOST_CPU_LOAD_INFO_COUNT: usize = 4; -//pub const HOST_CPU_LOAD_INFO: u32 = 3; -pub const KERN_SUCCESS: u32 = 0; - -pub const HW_NCPU: u32 = 3; -pub const CTL_HW: u32 = 6; -pub const CTL_VM: u32 = 2; -pub const VM_SWAPUSAGE: u32 = 5; -pub const PROCESSOR_CPU_LOAD_INFO: u32 = 2; -pub const CPU_STATE_USER: u32 = 0; -pub const CPU_STATE_SYSTEM: u32 = 1; -pub const CPU_STATE_IDLE: u32 = 2; -pub const CPU_STATE_NICE: u32 = 3; -pub const CPU_STATE_MAX: usize = 4; -pub const HW_MEMSIZE: u32 = 24; - -//pub const TASK_THREAD_TIMES_INFO: u32 = 3; -//pub const TASK_THREAD_TIMES_INFO_COUNT: u32 = 4; -//pub const TASK_BASIC_INFO_64: u32 = 5; -//pub const TASK_BASIC_INFO_64_COUNT: u32 = 10; -pub const HOST_VM_INFO64: u32 = 4; -pub const HOST_VM_INFO64_COUNT: u32 = 38; - -pub const MACH_PORT_NULL: i32 = 0; -pub const KERNEL_INDEX_SMC: i32 = 2; -pub const SMC_CMD_READ_KEYINFO: u8 = 9; -pub const SMC_CMD_READ_BYTES: u8 = 5; - -pub const KIO_RETURN_SUCCESS: i32 = 0; -#[allow(non_upper_case_globals)] -pub const kCFStringEncodingMacRoman: CFStringEncoding = 0; diff --git a/src/windows/mod.rs b/src/windows/mod.rs index 95e5ded57..611e9aa60 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -4,24 +4,8 @@ // Copyright (c) 2015 Guillaume Gomez // -/*pub mod component; -pub mod disk; -mod ffi; -pub mod network; -pub mod process; -pub mod processor; -pub mod system; - -pub use self::component::Component; -pub use self::disk::{Disk, DiskType}; -pub use self::network::NetworkData; -pub use self::process::{Process,ProcessStatus}; -pub use self::processor::Processor; -pub use self::system::System;*/ - mod component; mod disk; -//mod ffi; #[macro_use] mod macros; mod network; diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 3f8cc72cf..f6fdd8374 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -5,13 +5,15 @@ // use std::collections::HashMap; +use std::mem; use std::sync::{Arc, Mutex}; -use std::thread::{self /*, sleep*/, JoinHandle}; -//use std::time::Duration; +use std::thread::{self, JoinHandle}; use windows::tools::KeyHandler; use ProcessorExt; +use ntapi::ntpoapi::PROCESSOR_POWER_INFORMATION; + use winapi::shared::minwindef::{FALSE, ULONG}; use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::handleapi::CloseHandle; @@ -20,9 +22,11 @@ use winapi::um::pdh::{ PdhGetFormattedCounterValue, PdhOpenQueryA, PdhRemoveCounter, PDH_FMT_COUNTERVALUE, PDH_FMT_DOUBLE, PDH_FMT_LARGE, PDH_HCOUNTER, PDH_HQUERY, }; +use winapi::um::powerbase::CallNtPowerInformation; use winapi::um::synchapi::{CreateEventA, WaitForSingleObject}; +use winapi::um::sysinfoapi::SYSTEM_INFO; use winapi::um::winbase::{INFINITE, WAIT_OBJECT_0}; -use winapi::um::winnt::HANDLE; +use winapi::um::winnt::{HANDLE, ProcessorInformation}; #[derive(Debug)] pub enum CounterValue { @@ -248,6 +252,8 @@ pub struct Processor { cpu_usage: f32, key_idle: Option, key_used: Option, + vendor_id: String, + frequency: u64, } impl ProcessorExt for Processor { @@ -259,34 +265,124 @@ impl ProcessorExt for Processor { &self.name } - // Not yet implemented. fn get_frequency(&self) -> u64 { - 0 + self.frequency } - // Not yet implemented. fn get_vendor_id(&self) -> &str { - "" + &self.vendor_id } } impl Processor { - fn new_with_values(name: &str) -> Processor { + pub(crate) fn new_with_values(name: &str, vendor_id: String, frequency: u64) -> Processor { Processor { name: name.to_owned(), cpu_usage: 0f32, key_idle: None, key_used: None, + vendor_id, + frequency, } } + + pub(crate) fn set_cpu_usage(&mut self, value: f32) { + self.cpu_usage = value; + } } -pub fn create_processor(name: &str) -> Processor { - Processor::new_with_values(name) +fn get_vendor_id_not_great(info: &SYSTEM_INFO) -> String { + use winapi::um::winnt; + // https://docs.microsoft.com/fr-fr/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info + match unsafe { info.u.s() }.wProcessorArchitecture { + winnt::PROCESSOR_ARCHITECTURE_INTEL => "Intel x86", + winnt::PROCESSOR_ARCHITECTURE_MIPS => "MIPS", + winnt::PROCESSOR_ARCHITECTURE_ALPHA => "RISC Alpha", + winnt::PROCESSOR_ARCHITECTURE_PPC => "PPC", + winnt::PROCESSOR_ARCHITECTURE_SHX => "SHX", + winnt::PROCESSOR_ARCHITECTURE_ARM => "ARM", + winnt::PROCESSOR_ARCHITECTURE_IA64 => "Intel Itanium-based x64", + winnt::PROCESSOR_ARCHITECTURE_ALPHA64 => "RISC Alpha x64", + winnt::PROCESSOR_ARCHITECTURE_MSIL => "MSIL", + winnt::PROCESSOR_ARCHITECTURE_AMD64 => "(Intel or AMD) x64", + winnt::PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 => "Intel Itanium-based x86", + winnt::PROCESSOR_ARCHITECTURE_NEUTRAL => "unknown", + winnt::PROCESSOR_ARCHITECTURE_ARM64 => "ARM x64", + winnt::PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64 => "ARM", + winnt::PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 => "Intel Itanium-based x86", + _ => "unknown" + }.to_owned() } -pub fn set_cpu_usage(p: &mut Processor, value: f32) { - p.cpu_usage = value; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn get_vendor_id(info: &SYSTEM_INFO) -> String { + #[cfg(target_arch = "x86")] + use std::arch::x86::__cpuid; + #[cfg(target_arch = "x86_64")] + use std::arch::x86_64::__cpuid; + + fn add_u32(v: &mut Vec, i: u32) { + let i = &i as *const u32 as *const u8; + unsafe { + v.push(*i); + v.push(*i.offset(1)); + v.push(*i.offset(2)); + v.push(*i.offset(3)); + } + } + + // First, we try to get the complete name. + let res = unsafe { __cpuid(0x80000000) }; + let n_ex_ids = res.eax; + if n_ex_ids >= 0x80000004 { + let mut extdata = Vec::with_capacity(5); + + for i in 0x80000000..=n_ex_ids { + extdata.push(unsafe { __cpuid(i) }); + } + + let mut out = Vec::with_capacity(4 * 4 * 3); // 4 * u32 * nb_entries + for i in 2..5 { + add_u32(&mut out, extdata[i].eax); + add_u32(&mut out, extdata[i].ebx); + add_u32(&mut out, extdata[i].ecx); + add_u32(&mut out, extdata[i].edx); + } + let mut pos = 0; + for e in out.iter() { + if *e == 0 { + break; + } + pos += 1; + } + match ::std::str::from_utf8(&out[..pos]) { + Ok(s) => return s.to_owned(), + _ => {}, + } + } + + // Failed to get full name, let's retry for the short version! + let res = unsafe { __cpuid(0) }; + let mut x = Vec::with_capacity(16); // 3 * u32 + add_u32(&mut x, res.ebx); + add_u32(&mut x, res.edx); + add_u32(&mut x, res.ecx); + let mut pos = 0; + for e in x.iter() { + if *e == 0 { + break; + } + pos += 1; + } + match ::std::str::from_utf8(&x[..pos]) { + Ok(s) => s.to_owned(), + Err(_) => get_vendor_id_not_great(info), + } +} + +#[cfg(all(not(target_arch = "x86_64"), not(target_arch = "x86")))] +pub fn get_vendor_id(info: &SYSTEM_INFO) -> String { + get_vendor_id_not_great(info) } pub fn get_key_idle(p: &mut Processor) -> &mut Option { @@ -296,3 +392,21 @@ pub fn get_key_idle(p: &mut Processor) -> &mut Option { pub fn get_key_used(p: &mut Processor) -> &mut Option { &mut p.key_used } + +// From https://stackoverflow.com/a/43813138: +// +// If your PC has 64 or fewer logical processors installed, the above code will work fine. However, +// if your PC has more than 64 logical processors installed, use GetActiveProcessorCount() or +// GetLogicalProcessorInformation() to determine the total number of logical processors installed. +pub fn get_frequencies(nb_processors: usize) -> Vec { + let size = nb_processors * mem::size_of::(); + let mut infos: Vec = Vec::with_capacity(nb_processors); + + if unsafe { CallNtPowerInformation(ProcessorInformation, ::std::ptr::null_mut(), 0, infos.as_mut_ptr() as _, size as _) } == 0 { + unsafe { infos.set_len(nb_processors); } + // infos.Number + infos.into_iter().map(|i| i.CurrentMhz as u64).collect::>() + } else { + vec![0; nb_processors] + } +} diff --git a/src/windows/system.rs b/src/windows/system.rs index afb577e96..8bd7aa511 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -232,7 +232,7 @@ impl SystemExt for System { idle_time = Some(query.get(&key_idle.unique_id).expect("key disappeared")); } if let Some(idle_time) = idle_time { - set_cpu_usage(p, 1. - idle_time); + p.set_cpu_usage(1. - idle_time); } } } diff --git a/src/windows/tools.rs b/src/windows/tools.rs index abcac0078..892f9f8c6 100644 --- a/src/windows/tools.rs +++ b/src/windows/tools.rs @@ -4,7 +4,7 @@ // Copyright (c) 2018 Guillaume Gomez // -use windows::processor::{create_processor, CounterValue, Processor, Query}; +use windows::processor::{self, CounterValue, Processor, Query}; use sys::disk::{new_disk, Disk, DiskType}; @@ -44,56 +44,17 @@ impl KeyHandler { } } -/*#[allow(non_snake_case)] -#[allow(unused)] -unsafe fn browser() { - use winapi::um::pdh::{PdhBrowseCountersA, PDH_BROWSE_DLG_CONFIG_A}; - use winapi::shared::winerror::ERROR_SUCCESS; - - let mut BrowseDlgData: PDH_BROWSE_DLG_CONFIG_A = ::std::mem::zeroed(); - let mut CounterPathBuffer: [i8; 255] = ::std::mem::zeroed(); - const PERF_DETAIL_WIZARD: u32 = 400; - let text = b"Select a counter to monitor.\0"; - - BrowseDlgData.set_IncludeInstanceIndex(FALSE as u32); - BrowseDlgData.set_SingleCounterPerAdd(TRUE as u32); - BrowseDlgData.set_SingleCounterPerDialog(TRUE as u32); - BrowseDlgData.set_LocalCountersOnly(FALSE as u32); - BrowseDlgData.set_WildCardInstances(TRUE as u32); - BrowseDlgData.set_HideDetailBox(TRUE as u32); - BrowseDlgData.set_InitializePath(FALSE as u32); - BrowseDlgData.set_DisableMachineSelection(FALSE as u32); - BrowseDlgData.set_IncludeCostlyObjects(FALSE as u32); - BrowseDlgData.set_ShowObjectBrowser(FALSE as u32); - BrowseDlgData.hWndOwner = ::std::ptr::null_mut(); - BrowseDlgData.szReturnPathBuffer = CounterPathBuffer.as_mut_ptr(); - BrowseDlgData.cchReturnPathLength = 255; - BrowseDlgData.pCallBack = None; - BrowseDlgData.dwCallBackArg = 0; - BrowseDlgData.CallBackStatus = ERROR_SUCCESS as i32; - BrowseDlgData.dwDefaultDetailLevel = PERF_DETAIL_WIZARD; - BrowseDlgData.szDialogBoxCaption = text as *const _ as usize as *mut i8; - let ret = PdhBrowseCountersA(&mut BrowseDlgData as *mut _); - println!("browser: {:?}", ret); - for x in CounterPathBuffer.iter() { - print!("{:?} ", *x); - } - println!(""); - for x in 0..256 { - print!("{:?} ", *BrowseDlgData.szReturnPathBuffer.offset(x)); - } - println!(""); -}*/ - pub fn init_processors() -> Vec { unsafe { let mut sys_info: SYSTEM_INFO = zeroed(); GetSystemInfo(&mut sys_info); + let vendor_id = processor::get_vendor_id(&sys_info); + let frequencies = processor::get_frequencies(sys_info.dwNumberOfProcessors as usize); let mut ret = Vec::with_capacity(sys_info.dwNumberOfProcessors as usize + 1); for nb in 0..sys_info.dwNumberOfProcessors { - ret.push(create_processor(&format!("CPU {}", nb + 1))); + ret.push(Processor::new_with_values(&format!("CPU {}", nb + 1), vendor_id.clone(), frequencies[nb as usize])); } - ret.insert(0, create_processor("Total CPU")); + ret.insert(0, Processor::new_with_values("Total CPU", vendor_id, 0)); ret } } From 40c6c8a6bb3a372cd343e9cc1a3aa883cd2ebff4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Jan 2020 22:55:59 +0100 Subject: [PATCH 083/171] Add get_brand method for processor --- src/traits.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/traits.rs b/src/traits.rs index d3622ef14..22a2cd425 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -328,6 +328,18 @@ pub trait ProcessorExt { /// ``` fn get_vendor_id(&self) -> &str; + /// Returns the processor's brand. + /// + /// ```no_run + /// use sysinfo::{ProcessorExt, System, SystemExt}; + /// + /// let s = System::new(); + /// for processor in s.get_processor_list() { + /// println!("{}", processor.get_brand()); + /// } + /// ``` + fn get_brand(&self) -> &str; + /// Returns the processor's frequency. /// /// ```no_run From 68d64df1b00806cad13cb75902cf5f4b78e43f2a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Jan 2020 22:56:10 +0100 Subject: [PATCH 084/171] Add brand for linux --- src/linux/process.rs | 1 - src/linux/processor.rs | 36 +++++++++++++++++++++++++++++------- src/linux/system.rs | 3 ++- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/linux/process.rs b/src/linux/process.rs index 54750913f..c15543e41 100644 --- a/src/linux/process.rs +++ b/src/linux/process.rs @@ -7,7 +7,6 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; use std::fs::File; -use std::io::Read; use std::path::{Path, PathBuf}; use libc::{c_int, gid_t, kill, uid_t}; diff --git a/src/linux/processor.rs b/src/linux/processor.rs index 809990b0c..ffc06fac4 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -130,6 +130,7 @@ pub struct Processor { old_total_time: u64, frequency: u64, vendor_id: String, + brand: String, } impl Processor { @@ -147,6 +148,7 @@ impl Processor { guest_nice: u64, frequency: u64, vendor_id: String, + brand: String, ) -> Processor { Processor { name: name.to_owned(), @@ -159,6 +161,7 @@ impl Processor { old_total_time: 0, frequency, vendor_id, + brand, } } @@ -214,6 +217,10 @@ impl ProcessorExt for Processor { fn get_vendor_id(&self) -> &str { &self.vendor_id } + + fn get_brand(&self) -> &str { + &self.brand + } } pub fn get_raw_times(p: &Processor) -> (u64, u64) { @@ -242,15 +249,30 @@ pub fn get_cpu_frequency() -> u64 { } /// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). -pub fn get_vendor_id() -> String { +pub fn get_vendor_id_and_brand() -> (String, String) { let mut s = String::new(); if let Err(_) = File::open("/proc/cpuinfo").and_then(|mut f| f.read_to_string(&mut s)) { - return String::new(); + return (String::new(), String::new()); } - s.split('\n') - .find(|line| line.starts_with("vendor_id\t")) - .and_then(|line| line.split(':').last()) - .map(|s| s.trim().to_owned()) - .unwrap_or_default() + fn get_value(s: &str) -> String { + s.split(':').last().map(|x| x.trim().to_owned()).unwrap_or_default() + } + + let mut vendor_id = None; + let mut brand = None; + + for it in s.split('\n') { + if it.starts_with("vendor_id\t") { + vendor_id = Some(get_value(it)); + } else if it.starts_with("model name\t") { + brand = Some(get_value(it)); + } else { + continue; + } + if brand.is_some() && vendor_id.is_some() { + break; + } + } + (vendor_id.unwrap_or_default(), brand.unwrap_or_default()) } diff --git a/src/linux/system.rs b/src/linux/system.rs index 0cf9d819b..f4e6bb049 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -138,7 +138,7 @@ impl System { ) -> Box, &mut Vec, &mut usize)> { if first { let frequency = get_cpu_frequency(); - let vendor_id = get_vendor_id(); + let (vendor_id, brand) = get_vendor_id_and_brand(); Box::new( move |parts: &mut dyn Iterator, processors: &mut Vec, @@ -157,6 +157,7 @@ impl System { parts.next().map(|v| to_u64(v)).unwrap_or(0), frequency, vendor_id.clone(), + brand.clone(), )); }, ) From 7bd812ada659416b87bde7cea15e91e3309c31c7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Jan 2020 22:56:29 +0100 Subject: [PATCH 085/171] Add brand for mac --- src/mac/processor.rs | 17 ++++++++++++++--- src/mac/system.rs | 4 +++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/mac/processor.rs b/src/mac/processor.rs index cacdb3ce9..b6fbbbdbc 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -57,6 +57,7 @@ pub struct Processor { processor_data: Arc, frequency: u64, vendor_id: String, + brand: String, } impl Processor { @@ -65,6 +66,7 @@ impl Processor { processor_data: Arc, frequency: u64, vendor_id: String, + brand: String, ) -> Processor { Processor { name, @@ -72,6 +74,7 @@ impl Processor { processor_data, frequency, vendor_id, + brand, } } @@ -106,6 +109,10 @@ impl ProcessorExt for Processor { fn get_vendor_id(&self) -> &str { &self.vendor_id } + + fn get_brand(&self) -> &str { + &self.brand + } } pub fn get_cpu_frequency() -> u64 { @@ -124,12 +131,12 @@ pub fn get_cpu_frequency() -> u64 { speed } -pub fn get_vendor_id() -> String { +fn get_sysctl_str(s: &[u8]) -> String { let mut len = 0; unsafe { ffi::sysctlbyname( - b"machdep.cpu.brand_string\0".as_ptr() as *const c_char, + s.as_ptr() as *const c_char, std::ptr::null_mut(), &mut len, std::ptr::null_mut(), @@ -142,7 +149,7 @@ pub fn get_vendor_id() -> String { let mut buf = Vec::with_capacity(len); unsafe { ffi::sysctlbyname( - b"machdep.cpu.brand_string\0".as_ptr() as *const c_char, + s.as_ptr() as *const c_char, buf.as_mut_ptr() as _, &mut len, std::ptr::null_mut(), @@ -158,3 +165,7 @@ pub fn get_vendor_id() -> String { String::new() } } + +pub fn get_vendor_id_and_brand() -> (String, String) { + (get_sysctl_str(b"machdep.cpu.brand_string\0"), get_sysctl_str(b"machdep.cpu.vendor\0")) +} diff --git a/src/mac/system.rs b/src/mac/system.rs index 6e1f1838a..3788e3e09 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -182,7 +182,7 @@ impl SystemExt for System { if self.processors.is_empty() { let mut num_cpu = 0; - let vendor_id = get_vendor_id(); + let (vendor_id, brand) = get_vendor_id_and_brand(); let frequency = get_cpu_frequency(); if !get_sys_value( @@ -200,6 +200,7 @@ impl SystemExt for System { Arc::new(ProcessorData::new(::std::ptr::null_mut(), 0)), frequency, vendor_id.clone(), + brand.clone(), )); if ffi::host_processor_info( self.port, @@ -216,6 +217,7 @@ impl SystemExt for System { Arc::clone(&proc_data), frequency, vendor_id.clone(), + brand.clone(), ); let in_use = *cpu_info.offset( (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize, From 4682a4287f0d82fb511d254b3b2ab79288ec69b9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Jan 2020 23:05:46 +0100 Subject: [PATCH 086/171] Add brand for windows --- src/windows/processor.rs | 29 +++++++++++++++++++---------- src/windows/tools.rs | 6 +++--- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/windows/processor.rs b/src/windows/processor.rs index f6fdd8374..395930914 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -253,6 +253,7 @@ pub struct Processor { key_idle: Option, key_used: Option, vendor_id: String, + brand: String, frequency: u64, } @@ -272,16 +273,21 @@ impl ProcessorExt for Processor { fn get_vendor_id(&self) -> &str { &self.vendor_id } + + fn get_brand(&self) -> &str { + &self.brand + } } impl Processor { - pub(crate) fn new_with_values(name: &str, vendor_id: String, frequency: u64) -> Processor { + pub(crate) fn new_with_values(name: &str, vendor_id: String, brand: String, frequency: u64) -> Processor { Processor { name: name.to_owned(), cpu_usage: 0f32, key_idle: None, key_used: None, vendor_id, + brand, frequency, } } @@ -315,7 +321,7 @@ fn get_vendor_id_not_great(info: &SYSTEM_INFO) -> String { } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub fn get_vendor_id(info: &SYSTEM_INFO) -> String { +pub fn get_vendor_id_and_brand(info: &SYSTEM_INFO) -> (String, String) { #[cfg(target_arch = "x86")] use std::arch::x86::__cpuid; #[cfg(target_arch = "x86_64")] @@ -334,7 +340,7 @@ pub fn get_vendor_id(info: &SYSTEM_INFO) -> String { // First, we try to get the complete name. let res = unsafe { __cpuid(0x80000000) }; let n_ex_ids = res.eax; - if n_ex_ids >= 0x80000004 { + let brand = if n_ex_ids >= 0x80000004 { let mut extdata = Vec::with_capacity(5); for i in 0x80000000..=n_ex_ids { @@ -356,10 +362,12 @@ pub fn get_vendor_id(info: &SYSTEM_INFO) -> String { pos += 1; } match ::std::str::from_utf8(&out[..pos]) { - Ok(s) => return s.to_owned(), - _ => {}, + Ok(s) => s.to_owned(), + _ => String::new(), } - } + } else { + String::new() + }; // Failed to get full name, let's retry for the short version! let res = unsafe { __cpuid(0) }; @@ -374,15 +382,16 @@ pub fn get_vendor_id(info: &SYSTEM_INFO) -> String { } pos += 1; } - match ::std::str::from_utf8(&x[..pos]) { + let vendor_id = match ::std::str::from_utf8(&x[..pos]) { Ok(s) => s.to_owned(), Err(_) => get_vendor_id_not_great(info), - } + }; + (vendor_id, brand) } #[cfg(all(not(target_arch = "x86_64"), not(target_arch = "x86")))] -pub fn get_vendor_id(info: &SYSTEM_INFO) -> String { - get_vendor_id_not_great(info) +pub fn get_vendor_id_and_brand(info: &SYSTEM_INFO) -> (String, String) { + (get_vendor_id_not_great(info), String::new()) } pub fn get_key_idle(p: &mut Processor) -> &mut Option { diff --git a/src/windows/tools.rs b/src/windows/tools.rs index 892f9f8c6..69ac2ea25 100644 --- a/src/windows/tools.rs +++ b/src/windows/tools.rs @@ -48,13 +48,13 @@ pub fn init_processors() -> Vec { unsafe { let mut sys_info: SYSTEM_INFO = zeroed(); GetSystemInfo(&mut sys_info); - let vendor_id = processor::get_vendor_id(&sys_info); + let (vendor_id, brand) = processor::get_vendor_id_and_brand(&sys_info); let frequencies = processor::get_frequencies(sys_info.dwNumberOfProcessors as usize); let mut ret = Vec::with_capacity(sys_info.dwNumberOfProcessors as usize + 1); for nb in 0..sys_info.dwNumberOfProcessors { - ret.push(Processor::new_with_values(&format!("CPU {}", nb + 1), vendor_id.clone(), frequencies[nb as usize])); + ret.push(Processor::new_with_values(&format!("CPU {}", nb + 1), vendor_id.clone(), brand.clone(), frequencies[nb as usize])); } - ret.insert(0, Processor::new_with_values("Total CPU", vendor_id, 0)); + ret.insert(0, Processor::new_with_values("Total CPU", vendor_id, brand, 0)); ret } } From 34fea68986741026ccd5dbea4a34a1c537720de7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Jan 2020 23:09:12 +0100 Subject: [PATCH 087/171] fmt --- src/linux/processor.rs | 5 ++++- src/mac/processor.rs | 5 ++++- src/mac/system.rs | 5 +---- src/windows/processor.rs | 42 +++++++++++++++++++++++++++++----------- src/windows/tools.rs | 12 ++++++++++-- 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/linux/processor.rs b/src/linux/processor.rs index ffc06fac4..0ba11b81c 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -256,7 +256,10 @@ pub fn get_vendor_id_and_brand() -> (String, String) { } fn get_value(s: &str) -> String { - s.split(':').last().map(|x| x.trim().to_owned()).unwrap_or_default() + s.split(':') + .last() + .map(|x| x.trim().to_owned()) + .unwrap_or_default() } let mut vendor_id = None; diff --git a/src/mac/processor.rs b/src/mac/processor.rs index b6fbbbdbc..581f6ead4 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -167,5 +167,8 @@ fn get_sysctl_str(s: &[u8]) -> String { } pub fn get_vendor_id_and_brand() -> (String, String) { - (get_sysctl_str(b"machdep.cpu.brand_string\0"), get_sysctl_str(b"machdep.cpu.vendor\0")) + ( + get_sysctl_str(b"machdep.cpu.brand_string\0"), + get_sysctl_str(b"machdep.cpu.vendor\0"), + ) } diff --git a/src/mac/system.rs b/src/mac/system.rs index 3788e3e09..0e7719e7d 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -266,10 +266,7 @@ impl SystemExt for System { ) - *old_proc_data.cpu_info.offset( (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize, )); - proc_.update( - in_use as f32 / total as f32, - Arc::clone(&proc_data), - ); + proc_.update(in_use as f32 / total as f32, Arc::clone(&proc_data)); pourcent += proc_.get_cpu_usage(); } if self.processors.len() > 1 { diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 395930914..dd3245ca3 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -26,7 +26,7 @@ use winapi::um::powerbase::CallNtPowerInformation; use winapi::um::synchapi::{CreateEventA, WaitForSingleObject}; use winapi::um::sysinfoapi::SYSTEM_INFO; use winapi::um::winbase::{INFINITE, WAIT_OBJECT_0}; -use winapi::um::winnt::{HANDLE, ProcessorInformation}; +use winapi::um::winnt::{ProcessorInformation, HANDLE}; #[derive(Debug)] pub enum CounterValue { @@ -280,7 +280,12 @@ impl ProcessorExt for Processor { } impl Processor { - pub(crate) fn new_with_values(name: &str, vendor_id: String, brand: String, frequency: u64) -> Processor { + pub(crate) fn new_with_values( + name: &str, + vendor_id: String, + brand: String, + frequency: u64, + ) -> Processor { Processor { name: name.to_owned(), cpu_usage: 0f32, @@ -293,7 +298,7 @@ impl Processor { } pub(crate) fn set_cpu_usage(&mut self, value: f32) { - self.cpu_usage = value; + self.cpu_usage = value; } } @@ -316,8 +321,9 @@ fn get_vendor_id_not_great(info: &SYSTEM_INFO) -> String { winnt::PROCESSOR_ARCHITECTURE_ARM64 => "ARM x64", winnt::PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64 => "ARM", winnt::PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 => "Intel Itanium-based x86", - _ => "unknown" - }.to_owned() + _ => "unknown", + } + .to_owned() } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] @@ -408,13 +414,27 @@ pub fn get_key_used(p: &mut Processor) -> &mut Option { // if your PC has more than 64 logical processors installed, use GetActiveProcessorCount() or // GetLogicalProcessorInformation() to determine the total number of logical processors installed. pub fn get_frequencies(nb_processors: usize) -> Vec { - let size = nb_processors * mem::size_of::(); - let mut infos: Vec = Vec::with_capacity(nb_processors); - - if unsafe { CallNtPowerInformation(ProcessorInformation, ::std::ptr::null_mut(), 0, infos.as_mut_ptr() as _, size as _) } == 0 { - unsafe { infos.set_len(nb_processors); } + let size = nb_processors * mem::size_of::(); + let mut infos: Vec = Vec::with_capacity(nb_processors); + + if unsafe { + CallNtPowerInformation( + ProcessorInformation, + ::std::ptr::null_mut(), + 0, + infos.as_mut_ptr() as _, + size as _, + ) + } == 0 + { + unsafe { + infos.set_len(nb_processors); + } // infos.Number - infos.into_iter().map(|i| i.CurrentMhz as u64).collect::>() + infos + .into_iter() + .map(|i| i.CurrentMhz as u64) + .collect::>() } else { vec![0; nb_processors] } diff --git a/src/windows/tools.rs b/src/windows/tools.rs index 69ac2ea25..895183247 100644 --- a/src/windows/tools.rs +++ b/src/windows/tools.rs @@ -52,9 +52,17 @@ pub fn init_processors() -> Vec { let frequencies = processor::get_frequencies(sys_info.dwNumberOfProcessors as usize); let mut ret = Vec::with_capacity(sys_info.dwNumberOfProcessors as usize + 1); for nb in 0..sys_info.dwNumberOfProcessors { - ret.push(Processor::new_with_values(&format!("CPU {}", nb + 1), vendor_id.clone(), brand.clone(), frequencies[nb as usize])); + ret.push(Processor::new_with_values( + &format!("CPU {}", nb + 1), + vendor_id.clone(), + brand.clone(), + frequencies[nb as usize], + )); } - ret.insert(0, Processor::new_with_values("Total CPU", vendor_id, brand, 0)); + ret.insert( + 0, + Processor::new_with_values("Total CPU", vendor_id, brand, 0), + ); ret } } From d7b4a3571b882cb6cdba7b7ddbe33982f83d8a8f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Jan 2020 23:16:10 +0100 Subject: [PATCH 088/171] Add brand command and rename proc to procs --- examples/src/simple.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index 8bbc9be97..d0b8c5af7 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -79,7 +79,7 @@ fn print_help() { ); writeln!( &mut io::stdout(), - "proc : Displays proc state" + "procd : Displays processors state" ); writeln!( &mut io::stdout(), @@ -109,6 +109,10 @@ fn print_help() { &mut io::stdout(), "vendor_id : Displays processor vendor id" ); + writeln!( + &mut io::stdout(), + "brand : Displays processor brand" + ); writeln!( &mut io::stdout(), "load_avg : Displays system load average" @@ -136,8 +140,9 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { nb += 1; } } - "proc" => { - // Note: you should refresh a few times before using this, so that usage statistics can be ascertained + "procs" => { + // Note: you should refresh a few times before using this, so that usage statistics + // can be ascertained let procs = sys.get_processor_list(); writeln!( @@ -199,6 +204,13 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { sys.get_processor_list()[0].get_vendor_id() ); } + "brand" => { + writeln!( + &mut io::stdout(), + "brand: {}", + sys.get_processor_list()[0].get_brand() + ); + } "load_avg" => { let load_avg = sys.get_load_average(); writeln!(&mut io::stdout(), "one minute : {}%", load_avg.one); From f53b7bc39de04d751f521caca7d7a29b2734bc37 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Jan 2020 23:19:08 +0100 Subject: [PATCH 089/171] Add get_brand for unknown --- src/unknown/processor.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/unknown/processor.rs b/src/unknown/processor.rs index 9fa77276b..dab8d5947 100644 --- a/src/unknown/processor.rs +++ b/src/unknown/processor.rs @@ -28,4 +28,8 @@ impl ProcessorExt for Processor { fn get_vendor_id(&self) -> &str { "" } + + fn get_brand(&self) -> &str { + "" + } } From 983c87b30533b51cd93ca0b01a7e2672fd12deb8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 29 Jan 2020 23:31:22 +0100 Subject: [PATCH 090/171] remove too general io and net files --- src/io.rs | 97 -------------------------------------------------- src/net.rs | 72 ------------------------------------- src/sysinfo.rs | 3 -- 3 files changed, 172 deletions(-) delete mode 100644 src/io.rs delete mode 100644 src/net.rs diff --git a/src/io.rs b/src/io.rs deleted file mode 100644 index e30186215..000000000 --- a/src/io.rs +++ /dev/null @@ -1,97 +0,0 @@ -use std::collections::HashMap; -#[cfg(unix)] -use std::fs::File; -#[cfg(unix)] -use std::io::Read; - -use NICLoad; - -/// IOLoad represents current system block devices IO statistics -#[derive(Debug)] -pub struct IOLoad { - /// number of read I/Os processed - /// units: requests - pub read_io: f64, - /// number of read I/Os merged with in-queue I/O - /// units: requests - pub read_merges: f64, - /// number of sectors read - /// units: sectors - pub read_sectors: f64, - /// total wait time for read requests - /// units: milliseconds - pub read_ticks: f64, - /// number of write I/Os processed - /// units: requests - pub write_io: f64, - /// number of write I/Os merged with in-queue I/O - /// units: requests - pub write_merges: f64, - /// number of sectors written - /// units: sectors - pub write_sectors: f64, - /// total wait time for write requests - /// units: milliseconds - pub write_ticks: f64, - /// number of I/Os currently in flight - /// units: requests - pub in_flight: f64, - /// total time this block device has been active - /// units: milliseconds - pub io_ticks: f64, - /// total wait time for all requests - /// units: milliseconds - pub time_in_queue: f64, -} - -impl IOLoad { - /// Returns the current IO statistics - /// - /// # Notes - /// - /// Current don't support non-unix operating system - #[cfg(not(unix))] - pub fn snapshot() -> HashMap { - HashMap::new() - } - - /// Returns the current IO statistics - #[cfg(unix)] - pub fn snapshot() -> HashMap { - let mut result = HashMap::new(); - // https://www.kernel.org/doc/Documentation/block/stat.txt - if let Ok(dir) = std::fs::read_dir("/sys/block/") { - for entry in dir { - if let Ok(entry) = entry { - let stat = entry.path().join("stat"); - let mut s = String::new(); - if let Err(_) = File::open(stat).and_then(|mut f| f.read_to_string(&mut s)) { - continue; - }; - let parts = s - .split_whitespace() - .map(|w| w.parse().unwrap_or_default()) - .collect::>(); - if parts.len() < 11 { - continue; - } - let load = IOLoad { - read_io: parts[0], - read_merges: parts[1], - read_sectors: parts[2], - read_ticks: parts[3], - write_io: parts[4], - write_merges: parts[5], - write_sectors: parts[6], - write_ticks: parts[7], - in_flight: parts[8], - io_ticks: parts[9], - time_in_queue: parts[10], - }; - result.insert(format!("{:?}", entry.file_name()), load); - } - } - } - result - } -} diff --git a/src/net.rs b/src/net.rs deleted file mode 100644 index 878c6648b..000000000 --- a/src/net.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::collections::HashMap; - -/// NICLoad represents the network interface card load informations -#[derive(Debug)] -pub struct NICLoad { - /// a total number of bytes received over interface. - pub rx_bytes: usize, - /// a total number of bytes transmitted over interface. - pub tx_bytes: usize, - /// a total number of packets received. - pub rx_packets: usize, - /// a total number of packets transmitted. - pub tx_packets: usize, - /// shows a total number of packets received with error. This includes - /// too-long-frames errors, ring-buffer overflow errors, CRC errors, - /// frame alignment errors, fifo overruns, and missed packets. - pub rx_errors: usize, - /// similar to `rx_errors` - pub tx_errors: usize, - /// Indicates the number of compressed packets received by this - /// network device. This value might only be relevant for interfaces - /// that support packet compression (e.g: PPP). - pub rx_compressed: usize, - /// Indicates the number of transmitted compressed packets. Note - /// this might only be relevant for devices that support - /// compression (e.g: PPP). - pub tx_compressed: usize, -} - -impl NICLoad { - /// Returns the current network interfaces card statistics - /// - /// # Notes - /// - /// Current don't support non-unix operating system - #[cfg(not(unix))] - pub fn snapshot() -> HashMap { - HashMap::new() - } - - /// Returns the current network interfaces card statistics - #[cfg(unix)] - pub fn snapshot() -> HashMap { - let mut result = HashMap::new(); - if let Ok(dir) = std::fs::read_dir("/sys/class/net/") { - for entry in dir { - if let Ok(entry) = entry { - let parent = entry.path().join("statistics"); - let read = |path: &str| -> usize { - std::fs::read_to_string(parent.join(path)) - .unwrap_or_default() - .trim() - .parse() - .unwrap_or_default() - }; - let load = NICLoad { - rx_bytes: read("rx_bytes"), - tx_bytes: read("tx_bytes"), - rx_packets: read("rx_packets"), - tx_packets: read("tx_packets"), - rx_errors: read("rx_errors"), - tx_errors: read("tx_errors"), - rx_compressed: read("rx_compressed"), - tx_compressed: read("tx_compressed"), - }; - result.insert(format!("{:?}", entry.file_name()), load); - } - } - } - result - } -} diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 54d08a1ad..15393a555 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -79,9 +79,6 @@ cfg_if! { } pub use common::{AsU32, Pid, RefreshKind}; -pub use io::IOLoad; -pub use net::NICLoad; - pub use sys::{Component, Disk, DiskType, NetworkData, Process, ProcessStatus, Processor, System}; pub use traits::{ComponentExt, DiskExt, NetworkExt, ProcessExt, ProcessorExt, SystemExt}; From b1277bae7df98ebe0d3670343baeebf5d9a7be03 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Jan 2020 00:19:17 +0100 Subject: [PATCH 091/171] Rework network interface --- src/linux/mod.rs | 2 +- src/linux/network.rs | 163 ++++++++++++++++++++++++++++--------------- src/linux/system.rs | 14 ++-- src/mac/network.rs | 2 + src/traits.rs | 24 +++---- 5 files changed, 127 insertions(+), 78 deletions(-) diff --git a/src/linux/mod.rs b/src/linux/mod.rs index 9238248b9..bfb7215ff 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -13,7 +13,7 @@ pub mod system; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; -pub use self::network::NetworkData; +pub use self::network::{Networks, NetworkData}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; diff --git a/src/linux/network.rs b/src/linux/network.rs index 12316ea53..cb3694094 100644 --- a/src/linux/network.rs +++ b/src/linux/network.rs @@ -7,15 +7,116 @@ use std::fs::File; use std::io::{Error, ErrorKind, Read}; +use std::collections::HashMap; use NetworkExt; +pub struct Networks { + interfaces: HashMap, +} + +macro_rules! old_and_new { + ($ty_:ident, $name:ident) => {{ + $ty_.old_$name = $name; + $ty_.$name = $name; + }} +} + +impl Networks { + pub(crate) fn new() -> Self { + Networks { + interfaces: HashMap::new(), + } + } + + pub(crate) fn update(&mut self) { + if let Ok(dir) = std::fs::read_dir("/sys/class/net/") { + for entry in dir { + if let Ok(entry) = entry { + let parent = entry.path().join("statistics"); + let read = |path: &str| -> usize { + // TODO: check optimization here? + std::fs::read_to_string(parent.join(path)) + .unwrap_or_default() + .trim() + .parse() + .unwrap_or_default() + }; + let rx_bytes = read("rx_bytes"); + let tx_bytes = read("tx_bytes"); + let rx_packets = read("rx_packets"); + let tx_packets = read("tx_packets"); + let rx_errors = read("rx_errors"); + let tx_errors = read("tx_errors"); + let rx_compressed = read("rx_compressed"); + let tx_compressed = read("tx_compressed"); + let entry = format!("{}", entry.file_name()); + let interface = self.interfaces.entry(&entry).or_insert( + NetworkData { + rx_bytes, + old_rx_bytes: rx_bytes, + tx_bytes, + old_tx_bytes: tx_bytes, + rx_packets, + old_rx_packets: rx_packets, + tx_packets, + old_tx_packets: tx_packets, + rx_errors, + old_rx_errors: rx_errors, + tx_errors, + old_tx_errors: tx_errors, + rx_compressed, + old_rx_compressed: rx_compressed, + tx_compressed, + old_tx_compressed: tx_compressed, + } + ); + old_and_new!(interface, rx_bytes); + old_and_new!(interface, tx_bytes); + old_and_new!(interface, rx_packets); + old_and_new!(interface, tx_packets); + old_and_new!(interface, rx_errors); + old_and_new!(interface, tx_errors); + old_and_new!(interface, rx_compressed); + old_and_new!(interface, tx_compressed); + } + } + } + } +} + /// Contains network information. #[derive(Debug)] pub struct NetworkData { - old_in: u64, - old_out: u64, - current_in: u64, - current_out: u64, + /// Total number of bytes received over interface. + rx_bytes: usize, + old_rx_bytes: usize, + /// Total number of bytes transmitted over interface. + tx_bytes: usize, + old_tx_bytes: usize, + /// Total number of packets received. + rx_packets: usize, + old_rx_packets: usize, + /// Total number of packets transmitted. + tx_packets: usize, + old_tx_packets: usize, + /// Shows the total number of packets received with error. This includes + /// too-long-frames errors, ring-buffer overflow errors, CRC errors, + /// frame alignment errors, fifo overruns, and missed packets. + rx_errors: usize, + old_rx_errors: usize, + /// similar to `rx_errors` + tx_errors: usize, + old_tx_errors: usize, + /// Indicates the number of compressed packets received by this + /// network device. This value might only be relevant for interfaces + /// that support packet compression (e.g: PPP). + rx_compressed: usize, + old_rx_compressed: usize, + /// Indicates the number of transmitted compressed packets. Note + /// this might only be relevant for devices that support + /// compression (e.g: PPP). + tx_compressed: usize, + old_tx_compressed: usize, } impl NetworkExt for NetworkData { @@ -27,57 +128,3 @@ impl NetworkExt for NetworkData { self.current_out - self.old_out } } - -pub fn new() -> NetworkData { - NetworkData { - old_in: 0, - old_out: 0, - current_in: 0, - current_out: 0, - } -} - -fn read_things() -> Result<(u64, u64), Error> { - fn read_interface_stat(iface: &str, typ: &str) -> Result { - let mut file = File::open(format!("/sys/class/net/{}/statistics/{}_bytes", iface, typ))?; - let mut content = String::with_capacity(20); - file.read_to_string(&mut content)?; - content - .trim() - .parse() - .map_err(|_| Error::new(ErrorKind::Other, "Failed to parse network stat")) - } - - let default_interface = { - let mut file = File::open("/proc/net/route")?; - let mut content = String::with_capacity(800); - file.read_to_string(&mut content)?; - content - .lines() - .filter(|l| { - l.split_whitespace() - .nth(2) - .map(|l| l != "00000000") - .unwrap_or(false) - }) - .last() - .and_then(|l| l.split_whitespace().nth(0)) - .ok_or_else(|| Error::new(ErrorKind::Other, "Default device not found"))? - .to_owned() - }; - - Ok(( - read_interface_stat(&default_interface, "rx")?, - read_interface_stat(&default_interface, "tx")?, - )) -} - -pub fn update_network(n: &mut NetworkData) { - if let Ok((new_in, new_out)) = read_things() { - n.old_in = n.current_in; - n.old_out = n.current_out; - n.current_in = new_in; - n.current_out = new_out; - } - // TODO: maybe handle error here? -} diff --git a/src/linux/system.rs b/src/linux/system.rs index f4e6bb049..29d13b3a5 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -10,7 +10,7 @@ use sys::network; use sys::process::*; use sys::processor::*; use sys::Disk; -use sys::NetworkData; +use sys::Networks; use LoadAvg; use Pid; use {DiskExt, ProcessExt, RefreshKind, SystemExt}; @@ -107,7 +107,7 @@ pub struct System { page_size_kb: u64, temperatures: Vec, disks: Vec, - network: NetworkData, + networks: Networks, uptime: u64, } @@ -222,7 +222,7 @@ impl SystemExt for System { page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 }, temperatures: component::get_components(), disks: Vec::with_capacity(2), - network: network::new(), + networks: Networks::new(), uptime: get_uptime(), }; s.refresh_specifics(refreshes); @@ -314,8 +314,8 @@ impl SystemExt for System { self.disks = get_all_disks(); } - fn refresh_network(&mut self) { - network::update_network(&mut self.network); + fn refresh_networks(&mut self) { + self.networks.update(); } // COMMON PART @@ -330,8 +330,8 @@ impl SystemExt for System { self.process_list.tasks.get(&pid) } - fn get_network(&self) -> &NetworkData { - &self.network + fn get_networks(&self) -> &Networks { + &self.networks } fn get_processor_list(&self) -> &[Processor] { diff --git a/src/mac/network.rs b/src/mac/network.rs index 2bb47b5a1..cc56139de 100644 --- a/src/mac/network.rs +++ b/src/mac/network.rs @@ -39,6 +39,8 @@ pub fn new() -> NetworkData { #[allow(clippy::cast_ptr_alignment)] pub fn update_network(n: &mut NetworkData) { + // getifaddrs + // freeifaddrs let mib = &mut [CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0]; let mut len = 0; if unsafe { libc::sysctl(mib.as_mut_ptr(), 6, null_mut(), &mut len, null_mut(), 0) } < 0 { diff --git a/src/traits.rs b/src/traits.rs index 22a2cd425..1c1ab6cbf 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -4,7 +4,7 @@ // Copyright (c) 2017 Guillaume Gomez // -use sys::{Component, Disk, DiskType, NetworkData, Process, Processor}; +use sys::{Component, Disk, DiskType, Networks, Process, Processor}; use LoadAvg; use Pid; use ProcessStatus; @@ -404,8 +404,8 @@ pub trait SystemExt: Sized { /// /// let mut s = System::new(); /// - /// // Let's just update network data and processes: - /// s.refresh_specifics(RefreshKind::new().with_network().with_processes()); + /// // Let's just update networks and processes: + /// s.refresh_specifics(RefreshKind::new().with_networks().with_processes()); /// ``` fn refresh_specifics(&mut self, refreshes: RefreshKind) { if refreshes.memory() { @@ -417,8 +417,8 @@ pub trait SystemExt: Sized { if refreshes.temperatures() { self.refresh_temperatures(); } - if refreshes.network() { - self.refresh_network(); + if refreshes.networks() { + self.refresh_networks(); } if refreshes.processes() { self.refresh_processes(); @@ -523,15 +523,15 @@ pub trait SystemExt: Sized { /// ``` fn refresh_disk_list(&mut self); - /// Refresh data network. + /// Refresh networks data. /// /// ```no_run /// use sysinfo::{System, SystemExt}; /// /// let mut s = System::new(); - /// s.refresh_network(); + /// s.refresh_networks(); /// ``` - fn refresh_network(&mut self); + fn refresh_networks(&mut self); /// Refreshes all system, processes and disks information. /// @@ -545,7 +545,7 @@ pub trait SystemExt: Sized { self.refresh_system(); self.refresh_processes(); self.refresh_disks(); - self.refresh_network(); + self.refresh_networks(); } /// Returns the process list. @@ -688,16 +688,16 @@ pub trait SystemExt: Sized { /// ``` fn get_disks(&self) -> &[Disk]; - /// Returns network data. + /// Returns network interfaces. /// /// ```no_run /// use sysinfo::{NetworkExt, System, SystemExt}; /// /// let s = System::new(); - /// let network = s.get_network(); + /// let network = s.get_networks(); /// println!("in: {}, out: {}", network.get_income(), network.get_outcome()); /// ``` - fn get_network(&self) -> &NetworkData; + fn get_networks(&self) -> &Networks; /// Returns system uptime. /// From ab059a7693c7df148aa9fe813728ffc609f0c5ff Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Jan 2020 23:12:33 +0100 Subject: [PATCH 092/171] Update to new Networks type --- benches/basic.rs | 4 ++-- examples/src/simple.rs | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/benches/basic.rs b/benches/basic.rs index 6fae247dc..a6f3833fd 100644 --- a/benches/basic.rs +++ b/benches/basic.rs @@ -70,11 +70,11 @@ fn bench_refresh_disk_lists(b: &mut test::Bencher) { } #[bench] -fn bench_refresh_network(b: &mut test::Bencher) { +fn bench_refresh_networks(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); b.iter(move || { - s.refresh_network(); + s.refresh_networks(); }); } diff --git a/examples/src/simple.rs b/examples/src/simple.rs index d0b8c5af7..eb062424a 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -12,7 +12,7 @@ extern crate sysinfo; use std::io::{self, BufRead, Write}; use std::str::FromStr; use sysinfo::Signal::*; -use sysinfo::{NetworkExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt}; +use sysinfo::{NetworkExt, NetworksExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt}; const signals: [Signal; 31] = [ Hangup, @@ -245,16 +245,15 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { } } "network" => { - writeln!( - &mut io::stdout(), - "input data : {} B", - sys.get_network().get_income() - ); - writeln!( - &mut io::stdout(), - "output data: {} B", - sys.get_network().get_outcome() - ); + for (interface_name, data) in sys.get_networks().iter() { + writeln!( + &mut io::stdout(), + "{}:\n input data: {} B\n output data: {} B", + interface_name, + data.get_income(), + data.get_outcome() + ); + } } "show" => { writeln!( From 383f944dd04cab3ae4227768dae2db5ea11cb370 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Jan 2020 23:15:54 +0100 Subject: [PATCH 093/171] speed up networks refresh --- src/common.rs | 35 ++++++++++-- src/linux/network.rs | 127 ++++++++++++++++++++++++++++++++----------- src/linux/system.rs | 1 - src/sysinfo.rs | 8 +-- src/traits.rs | 53 +++++++++++++++--- 5 files changed, 172 insertions(+), 52 deletions(-) diff --git a/src/common.rs b/src/common.rs index 1ac80781b..56c143f59 100644 --- a/src/common.rs +++ b/src/common.rs @@ -4,6 +4,8 @@ // Copyright (c) 2015 Guillaume Gomez // +use NetworkData; + /// Trait to have a common fallback for the `Pid` type. pub trait AsU32 { /// Allows to convert `Pid` into `u32`. @@ -112,7 +114,7 @@ assert_eq!(r.", stringify!($name), "(), false); /// ``` #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct RefreshKind { - network: bool, + networks: bool, processes: bool, disk_list: bool, disks: bool, @@ -131,7 +133,7 @@ impl RefreshKind { /// /// let r = RefreshKind::new(); /// - /// assert_eq!(r.network(), false); + /// assert_eq!(r.networks(), false); /// assert_eq!(r.processes(), false); /// assert_eq!(r.disk_list(), false); /// assert_eq!(r.disks(), false); @@ -141,7 +143,7 @@ impl RefreshKind { /// ``` pub fn new() -> RefreshKind { RefreshKind { - network: false, + networks: false, processes: false, disks: false, disk_list: false, @@ -160,7 +162,7 @@ impl RefreshKind { /// /// let r = RefreshKind::everything(); /// - /// assert_eq!(r.network(), true); + /// assert_eq!(r.networks(), true); /// assert_eq!(r.processes(), true); /// assert_eq!(r.disk_list(), true); /// assert_eq!(r.disks(), true); @@ -170,7 +172,7 @@ impl RefreshKind { /// ``` pub fn everything() -> RefreshKind { RefreshKind { - network: true, + networks: true, processes: true, disks: true, disk_list: true, @@ -180,7 +182,7 @@ impl RefreshKind { } } - impl_get_set!(network, with_network, without_network); + impl_get_set!(networks, with_networks, without_networks); impl_get_set!(processes, with_processes, without_processes); impl_get_set!(disks, with_disks, without_disks); impl_get_set!(disk_list, with_disk_list, without_disk_list); @@ -188,3 +190,24 @@ impl RefreshKind { impl_get_set!(cpu, with_cpu, without_cpu); impl_get_set!(temperatures, with_temperatures, without_temperatures); } + +/// Iterator over network interfaces. +pub struct NetworksIter<'a> { + inner: std::collections::hash_map::Iter<'a, String, NetworkData>, +} + +impl<'a> NetworksIter<'a> { + pub(crate) fn new(v: std::collections::hash_map::Iter<'a, String, NetworkData>) -> Self { + NetworksIter { + inner: v, + } + } +} + +impl<'a> Iterator for NetworksIter<'a> { + type Item = (&'a String, &'a NetworkData); + + fn next(&mut self) -> Option { + self.inner.next() + } +} diff --git a/src/linux/network.rs b/src/linux/network.rs index cb3694094..f4d5f972a 100644 --- a/src/linux/network.rs +++ b/src/linux/network.rs @@ -5,20 +5,47 @@ // use std::fs::File; -use std::io::{Error, ErrorKind, Read}; +use std::io::Read; +use std::path::Path; use std::collections::HashMap; use NetworkExt; +use NetworksExt; +use NetworksIter; +/// Network interfaces. +#[derive(Debug)] pub struct Networks { interfaces: HashMap, } macro_rules! old_and_new { - ($ty_:ident, $name:ident) => {{ - $ty_.old_$name = $name; + ($ty_:expr, $name:ident, $old:ident) => {{ + $ty_.$old = $ty_.$name; $ty_.$name = $name; - }} + }}; + ($ty_:expr, $name:ident, $old:ident, $path:expr) => {{ + let _tmp = $path; + $ty_.$old = $ty_.$name; + $ty_.$name = _tmp; + }}; +} + +fn read>(parent: P, path: &str, data: &mut Vec) -> usize { + if let Ok(mut f) = File::open(parent.as_ref().join(path)) { + if let Ok(size) = f.read(data) { + let mut i = 0; + let mut ret = 0; + + while i < size && i < data.len() && data[i] >= b'0' && data[i] <= b'9' { + ret *= 10; + ret += (data[i] - b'0') as usize; + i += 1; + } + return ret; + } + } + 0 } impl Networks { @@ -29,28 +56,36 @@ impl Networks { } pub(crate) fn update(&mut self) { + if self.interfaces.is_empty() { + self.refresh_interfaces_list(); + } else { + let mut v = vec![0; 30]; + + for (interface_name, data) in self.interfaces.iter_mut() { + data.update(interface_name, &mut v); + } + } + } + + pub(crate) fn refresh_interfaces_list(&mut self) { if let Ok(dir) = std::fs::read_dir("/sys/class/net/") { + let mut data = vec![0; 30]; for entry in dir { if let Ok(entry) = entry { - let parent = entry.path().join("statistics"); - let read = |path: &str| -> usize { - // TODO: check optimization here? - std::fs::read_to_string(parent.join(path)) - .unwrap_or_default() - .trim() - .parse() - .unwrap_or_default() + let parent = &entry.path().join("statistics"); + let entry = match entry.file_name().into_string() { + Ok(entry) => entry, + Err(_) => continue, }; - let rx_bytes = read("rx_bytes"); - let tx_bytes = read("tx_bytes"); - let rx_packets = read("rx_packets"); - let tx_packets = read("tx_packets"); - let rx_errors = read("rx_errors"); - let tx_errors = read("tx_errors"); - let rx_compressed = read("rx_compressed"); - let tx_compressed = read("tx_compressed"); - let entry = format!("{}", entry.file_name()); - let interface = self.interfaces.entry(&entry).or_insert( + let rx_bytes = read(parent, "rx_bytes", &mut data); + let tx_bytes = read(parent, "tx_bytes", &mut data); + let rx_packets = read(parent, "rx_packets", &mut data); + let tx_packets = read(parent, "tx_packets", &mut data); + let rx_errors = read(parent, "rx_errors", &mut data); + let tx_errors = read(parent, "tx_errors", &mut data); + let rx_compressed = read(parent, "rx_compressed", &mut data); + let tx_compressed = read(parent, "tx_compressed", &mut data); + let interface = self.interfaces.entry(entry).or_insert( NetworkData { rx_bytes, old_rx_bytes: rx_bytes, @@ -70,20 +105,26 @@ impl Networks { old_tx_compressed: tx_compressed, } ); - old_and_new!(interface, rx_bytes); - old_and_new!(interface, tx_bytes); - old_and_new!(interface, rx_packets); - old_and_new!(interface, tx_packets); - old_and_new!(interface, rx_errors); - old_and_new!(interface, tx_errors); - old_and_new!(interface, rx_compressed); - old_and_new!(interface, tx_compressed); + old_and_new!(interface, rx_bytes, old_rx_bytes); + old_and_new!(interface, tx_bytes, old_tx_bytes); + old_and_new!(interface, rx_packets, old_rx_packets); + old_and_new!(interface, tx_packets, old_tx_packets); + old_and_new!(interface, rx_errors, old_rx_errors); + old_and_new!(interface, tx_errors, old_tx_errors); + old_and_new!(interface, rx_compressed, old_rx_compressed); + old_and_new!(interface, tx_compressed, old_tx_compressed); } } } } } +impl NetworksExt for Networks { + fn iter<'a>(&'a self) -> NetworksIter<'a> { + NetworksIter::new(self.interfaces.iter()) + } +} + /// Contains network information. #[derive(Debug)] pub struct NetworkData { @@ -119,12 +160,34 @@ pub struct NetworkData { old_tx_compressed: usize, } +impl NetworkData { + fn update(&mut self, path: &str, data: &mut Vec) { + let path = &Path::new("/sys/class/net/").join(path).join("statistics"); + old_and_new!(self, rx_bytes, old_rx_bytes, read(path, "rx_bytes", data)); + old_and_new!(self, tx_bytes, old_tx_bytes, read(path, "tx_bytes", data)); + old_and_new!(self, rx_packets, old_rx_packets, read(path, "rx_packets", data)); + old_and_new!(self, tx_packets, old_tx_packets, read(path, "tx_packets", data)); + old_and_new!(self, rx_errors, old_rx_errors, read(path, "rx_errors", data)); + old_and_new!(self, tx_errors, old_tx_errors, read(path, "tx_errors", data)); + old_and_new!(self, rx_compressed, old_rx_compressed, read(path, "rx_compressed", data)); + old_and_new!(self, tx_compressed, old_tx_compressed, read(path, "tx_compressed", data)); + } +} + impl NetworkExt for NetworkData { fn get_income(&self) -> u64 { - self.current_in - self.old_in + self.rx_bytes as u64 - self.old_rx_bytes as u64 } fn get_outcome(&self) -> u64 { - self.current_out - self.old_out + self.tx_bytes as u64 - self.old_tx_bytes as u64 + } + + fn get_total_income(&self) -> u64 { + self.rx_bytes as u64 + } + + fn get_total_outcome(&self) -> u64 { + self.rx_bytes as u64 } } diff --git a/src/linux/system.rs b/src/linux/system.rs index 29d13b3a5..86ed8f45e 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -6,7 +6,6 @@ use sys::component::{self, Component}; use sys::disk; -use sys::network; use sys::process::*; use sys::processor::*; use sys::Disk; diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 15393a555..c7e79ab91 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -78,9 +78,9 @@ cfg_if! { } } -pub use common::{AsU32, Pid, RefreshKind}; -pub use sys::{Component, Disk, DiskType, NetworkData, Process, ProcessStatus, Processor, System}; -pub use traits::{ComponentExt, DiskExt, NetworkExt, ProcessExt, ProcessorExt, SystemExt}; +pub use common::{AsU32, NetworksIter, Pid, RefreshKind}; +pub use sys::{Component, Disk, DiskType, NetworkData, Networks, Process, ProcessStatus, Processor, System}; +pub use traits::{ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt}; #[cfg(feature = "c-interface")] pub use c_interface::*; @@ -90,8 +90,6 @@ pub use utils::get_current_pid; mod c_interface; mod common; mod component; -mod io; -mod net; mod process; mod processor; mod system; diff --git a/src/traits.rs b/src/traits.rs index 1c1ab6cbf..154919b9e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -6,6 +6,7 @@ use sys::{Component, Disk, DiskType, Networks, Process, Processor}; use LoadAvg; +use NetworksIter; use Pid; use ProcessStatus; use RefreshKind; @@ -728,27 +729,63 @@ pub trait SystemExt: Sized { /// Getting volume of incoming and outgoing data. pub trait NetworkExt { - /// Returns the number of incoming bytes. + /// Returns the number of incoming bytes since the last refresh. /// /// ```no_run - /// use sysinfo::{NetworkExt, System, SystemExt}; + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// /// let s = System::new(); - /// let network = s.get_network(); - /// println!("in: {}", network.get_income()); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks.iter() { + /// println!("in: {} B", network.get_income()); + /// } /// ``` fn get_income(&self) -> u64; - /// Returns the number of outgoing bytes. + /// Returns the number of outgoing bytes since the last refresh. /// /// ```no_run - /// use sysinfo::{NetworkExt, System, SystemExt}; + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// /// let s = System::new(); - /// let network = s.get_network(); - /// println!("out: {}", network.get_outcome()); + /// let network = s.get_networks(); + /// for (interface_name, network) in networks.iter() { + /// println!("in: {} B", network.get_outcome()); + /// } /// ``` fn get_outcome(&self) -> u64; + + /// Returns the total number of incoming bytes. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new(); + /// let network = s.get_networks(); + /// for (interface_name, network) in networks.iter() { + /// println!("in: {} B", network.get_total_income()); + /// } + /// ``` + fn get_total_income(&self) -> u64; + + /// Returns the total number of outgoing bytes. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new(); + /// let network = s.get_networks(); + /// for (interface_name, network) in networks.iter() { + /// println!("in: {} B", network.get_total_outcome()); + /// } + /// ``` + fn get_total_outcome(&self) -> u64; +} + +/// Interacting with network interfaces. +pub trait NetworksExt { + /// Returns an iterator over the network interfaces. + fn iter(&self) -> NetworksIter; } /// Getting a component temperature information. From 3a7438496907a45551dbba070101b2761aa7b31d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2020 01:09:57 +0100 Subject: [PATCH 094/171] Implement new Networks system on mac --- src/common.rs | 4 +- src/linux/mod.rs | 2 +- src/linux/network.rs | 80 +++++++++++++++-------- src/mac/mod.rs | 2 +- src/mac/network.rs | 151 ++++++++++++++++++++++++++----------------- src/mac/system.rs | 14 ++-- src/sysinfo.rs | 8 ++- 7 files changed, 160 insertions(+), 101 deletions(-) diff --git a/src/common.rs b/src/common.rs index 56c143f59..4ccf9be36 100644 --- a/src/common.rs +++ b/src/common.rs @@ -198,9 +198,7 @@ pub struct NetworksIter<'a> { impl<'a> NetworksIter<'a> { pub(crate) fn new(v: std::collections::hash_map::Iter<'a, String, NetworkData>) -> Self { - NetworksIter { - inner: v, - } + NetworksIter { inner: v } } } diff --git a/src/linux/mod.rs b/src/linux/mod.rs index bfb7215ff..ea2b88c65 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -13,7 +13,7 @@ pub mod system; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; -pub use self::network::{Networks, NetworkData}; +pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; diff --git a/src/linux/network.rs b/src/linux/network.rs index f4d5f972a..34c402251 100644 --- a/src/linux/network.rs +++ b/src/linux/network.rs @@ -85,26 +85,24 @@ impl Networks { let tx_errors = read(parent, "tx_errors", &mut data); let rx_compressed = read(parent, "rx_compressed", &mut data); let tx_compressed = read(parent, "tx_compressed", &mut data); - let interface = self.interfaces.entry(entry).or_insert( - NetworkData { - rx_bytes, - old_rx_bytes: rx_bytes, - tx_bytes, - old_tx_bytes: tx_bytes, - rx_packets, - old_rx_packets: rx_packets, - tx_packets, - old_tx_packets: tx_packets, - rx_errors, - old_rx_errors: rx_errors, - tx_errors, - old_tx_errors: tx_errors, - rx_compressed, - old_rx_compressed: rx_compressed, - tx_compressed, - old_tx_compressed: tx_compressed, - } - ); + let interface = self.interfaces.entry(entry).or_insert(NetworkData { + rx_bytes, + old_rx_bytes: rx_bytes, + tx_bytes, + old_tx_bytes: tx_bytes, + rx_packets, + old_rx_packets: rx_packets, + tx_packets, + old_tx_packets: tx_packets, + rx_errors, + old_rx_errors: rx_errors, + tx_errors, + old_tx_errors: tx_errors, + rx_compressed, + old_rx_compressed: rx_compressed, + tx_compressed, + old_tx_compressed: tx_compressed, + }); old_and_new!(interface, rx_bytes, old_rx_bytes); old_and_new!(interface, tx_bytes, old_tx_bytes); old_and_new!(interface, rx_packets, old_rx_packets); @@ -165,12 +163,42 @@ impl NetworkData { let path = &Path::new("/sys/class/net/").join(path).join("statistics"); old_and_new!(self, rx_bytes, old_rx_bytes, read(path, "rx_bytes", data)); old_and_new!(self, tx_bytes, old_tx_bytes, read(path, "tx_bytes", data)); - old_and_new!(self, rx_packets, old_rx_packets, read(path, "rx_packets", data)); - old_and_new!(self, tx_packets, old_tx_packets, read(path, "tx_packets", data)); - old_and_new!(self, rx_errors, old_rx_errors, read(path, "rx_errors", data)); - old_and_new!(self, tx_errors, old_tx_errors, read(path, "tx_errors", data)); - old_and_new!(self, rx_compressed, old_rx_compressed, read(path, "rx_compressed", data)); - old_and_new!(self, tx_compressed, old_tx_compressed, read(path, "tx_compressed", data)); + old_and_new!( + self, + rx_packets, + old_rx_packets, + read(path, "rx_packets", data) + ); + old_and_new!( + self, + tx_packets, + old_tx_packets, + read(path, "tx_packets", data) + ); + old_and_new!( + self, + rx_errors, + old_rx_errors, + read(path, "rx_errors", data) + ); + old_and_new!( + self, + tx_errors, + old_tx_errors, + read(path, "tx_errors", data) + ); + old_and_new!( + self, + rx_compressed, + old_rx_compressed, + read(path, "rx_compressed", data) + ); + old_and_new!( + self, + tx_compressed, + old_tx_compressed, + read(path, "tx_compressed", data) + ); } } diff --git a/src/mac/mod.rs b/src/mac/mod.rs index 1ae6e4f8a..8a2becbc9 100644 --- a/src/mac/mod.rs +++ b/src/mac/mod.rs @@ -14,7 +14,7 @@ pub mod system; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; -pub use self::network::NetworkData; +pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; diff --git a/src/mac/network.rs b/src/mac/network.rs index cc56139de..6d7f01573 100644 --- a/src/mac/network.rs +++ b/src/mac/network.rs @@ -5,10 +5,96 @@ // use libc::{self, c_char, CTL_NET, NET_RT_IFLIST2, PF_ROUTE, RTM_IFINFO2}; + +use std::collections::HashMap; use std::ptr::null_mut; use sys::ffi; use NetworkExt; +use NetworksExt; +use NetworksIter; + +/// Network interfaces. +pub struct Networks { + interfaces: HashMap, +} + +impl Networks { + pub(crate) fn new() -> Self { + Networks { + interfaces: HashMap::new(), + } + } + + #[allow(clippy::cast_ptr_alignment)] + pub(crate) fn update(&mut self) { + let mib = &mut [CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0]; + let mut len = 0; + if unsafe { libc::sysctl(mib.as_mut_ptr(), 6, null_mut(), &mut len, null_mut(), 0) } < 0 { + // TODO: might be nice to put an error in here... + return; + } + let mut buf = Vec::with_capacity(len); + unsafe { + buf.set_len(len); + if libc::sysctl( + mib.as_mut_ptr(), + 6, + buf.as_mut_ptr(), + &mut len, + null_mut(), + 0, + ) < 0 + { + // TODO: might be nice to put an error in here... + return; + } + } + let buf = buf.as_ptr() as *const c_char; + let lim = unsafe { buf.add(len) }; + let mut next = buf; + while next < lim { + unsafe { + let ifm = next as *const libc::if_msghdr; + next = next.offset((*ifm).ifm_msglen as isize); + if (*ifm).ifm_type == RTM_IFINFO2 as u8 { + // The interface (line description) name stored at ifname will be returned in + // the default coded character set identifier (CCSID) currently in effect for + // the job. If this is not a single byte CCSID, then storage greater than + // IFNAMSIZ (16) bytes may be needed. 22 bytes is large enough for all CCSIDs. + let mut name = vec![0u8; libc::IFNAMSIZ + 6]; + + let if2m: *const ffi::if_msghdr2 = ifm as *const ffi::if_msghdr2; + let pname = + libc::if_indextoname((*if2m).ifm_index as _, name.as_mut_ptr() as _); + if pname.is_null() { + continue; + } + name.set_len(libc::strlen(pname)); + let name = String::from_utf8_unchecked(name); + let ibytes = (*if2m).ifm_data.ifi_ibytes; + let obytes = (*if2m).ifm_data.ifi_obytes; + let interface = self.interfaces.entry(name).or_insert_with(|| NetworkData { + old_in: ibytes, + current_in: ibytes, + old_out: obytes, + current_out: obytes, + }); + interface.old_in = interface.current_in; + interface.current_in = ibytes; + interface.old_out = interface.current_out; + interface.current_out = obytes; + } + } + } + } +} + +impl NetworksExt for Networks { + fn iter<'a>(&'a self) -> NetworksIter<'a> { + NetworksIter::new(self.interfaces.iter()) + } +} /// Contains network information. pub struct NetworkData { @@ -26,69 +112,12 @@ impl NetworkExt for NetworkData { fn get_outcome(&self) -> u64 { self.current_out - self.old_out } -} -pub fn new() -> NetworkData { - NetworkData { - old_in: 0, - old_out: 0, - current_in: 0, - current_out: 0, + fn get_total_income(&self) -> u64 { + self.current_in } -} -#[allow(clippy::cast_ptr_alignment)] -pub fn update_network(n: &mut NetworkData) { - // getifaddrs - // freeifaddrs - let mib = &mut [CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0]; - let mut len = 0; - if unsafe { libc::sysctl(mib.as_mut_ptr(), 6, null_mut(), &mut len, null_mut(), 0) } < 0 { - // TODO: might be nice to put an error in here... - return; - } - let mut buf = Vec::with_capacity(len); - unsafe { - buf.set_len(len); - if libc::sysctl( - mib.as_mut_ptr(), - 6, - buf.as_mut_ptr(), - &mut len, - null_mut(), - 0, - ) < 0 - { - // TODO: might be nice to put an error in here... - return; - } - } - let buf = buf.as_ptr() as *const c_char; - let lim = unsafe { buf.add(len) }; - let mut next = buf; - let mut totalibytes = 0u64; - let mut totalobytes = 0u64; - while next < lim { - unsafe { - let ifm = next as *const libc::if_msghdr; - next = next.offset((*ifm).ifm_msglen as isize); - if (*ifm).ifm_type == RTM_IFINFO2 as u8 { - let if2m: *const ffi::if_msghdr2 = ifm as *const ffi::if_msghdr2; - totalibytes += (*if2m).ifm_data.ifi_ibytes; - totalobytes += (*if2m).ifm_data.ifi_obytes; - } - } + fn get_total_outcome(&self) -> u64 { + self.current_out } - n.old_in = if n.current_in > totalibytes { - 0 - } else { - n.current_in - }; - n.current_in = totalibytes; - n.old_out = if n.current_out > totalibytes { - 0 - } else { - n.current_out - }; - n.current_out = totalobytes; } diff --git a/src/mac/system.rs b/src/mac/system.rs index 0e7719e7d..4683bcf2b 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -7,7 +7,7 @@ use sys::component::Component; use sys::disk::Disk; use sys::ffi; -use sys::network::{self, NetworkData}; +use sys::network::Networks; use sys::process::*; use sys::processor::*; @@ -34,7 +34,7 @@ pub struct System { temperatures: Vec, connection: Option, disks: Vec, - network: NetworkData, + networks: Networks, uptime: u64, port: ffi::mach_port_t, } @@ -82,7 +82,7 @@ impl SystemExt for System { temperatures: Vec::with_capacity(2), connection: get_io_service_connection(), disks: Vec::with_capacity(1), - network: network::new(), + networks: Networks::new(), uptime: get_uptime(), port: unsafe { ffi::mach_host_self() }, }; @@ -279,8 +279,8 @@ impl SystemExt for System { } } - fn refresh_network(&mut self) { - network::update_network(&mut self.network); + fn refresh_networks(&mut self) { + self.networks.update(); } fn refresh_processes(&mut self) { @@ -347,8 +347,8 @@ impl SystemExt for System { &self.processors[..] } - fn get_network(&self) -> &NetworkData { - &self.network + fn get_networks(&self) -> &Networks { + &self.networks } fn get_total_memory(&self) -> u64 { diff --git a/src/sysinfo.rs b/src/sysinfo.rs index c7e79ab91..7945492fc 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -79,8 +79,12 @@ cfg_if! { } pub use common::{AsU32, NetworksIter, Pid, RefreshKind}; -pub use sys::{Component, Disk, DiskType, NetworkData, Networks, Process, ProcessStatus, Processor, System}; -pub use traits::{ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt}; +pub use sys::{ + Component, Disk, DiskType, NetworkData, Networks, Process, ProcessStatus, Processor, System, +}; +pub use traits::{ + ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, +}; #[cfg(feature = "c-interface")] pub use c_interface::*; From 23256e80397395e0df43a80eb7be82ef614fb89c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2020 01:10:21 +0100 Subject: [PATCH 095/171] Improve network example --- examples/src/simple.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index eb062424a..d4fa7ca9f 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -248,10 +248,12 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { for (interface_name, data) in sys.get_networks().iter() { writeln!( &mut io::stdout(), - "{}:\n input data: {} B\n output data: {} B", + "{}:\n input data (new / total): {} / {} B\n output data (new / total): {} / {} B", interface_name, data.get_income(), - data.get_outcome() + data.get_total_income(), + data.get_outcome(), + data.get_total_outcome(), ); } } From 2ab3bf402bc20798d0debe2d978ade8eea5f73b8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2020 11:07:18 +0100 Subject: [PATCH 096/171] replace .insert by .insert_with --- src/linux/network.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linux/network.rs b/src/linux/network.rs index 34c402251..698088618 100644 --- a/src/linux/network.rs +++ b/src/linux/network.rs @@ -85,7 +85,7 @@ impl Networks { let tx_errors = read(parent, "tx_errors", &mut data); let rx_compressed = read(parent, "rx_compressed", &mut data); let tx_compressed = read(parent, "tx_compressed", &mut data); - let interface = self.interfaces.entry(entry).or_insert(NetworkData { + let interface = self.interfaces.entry(entry).or_insert_with(|| NetworkData { rx_bytes, old_rx_bytes: rx_bytes, tx_bytes, From 42067a7a7b7259db10662206192c73548bff1861 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2020 11:21:24 +0100 Subject: [PATCH 097/171] Fix doc --- src/traits.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 154919b9e..b234f6c2b 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -692,11 +692,13 @@ pub trait SystemExt: Sized { /// Returns network interfaces. /// /// ```no_run - /// use sysinfo::{NetworkExt, System, SystemExt}; + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// /// let s = System::new(); - /// let network = s.get_networks(); - /// println!("in: {}, out: {}", network.get_income(), network.get_outcome()); + /// let networks = s.get_networks(); + /// for (interface_name, data) in networks.iter() { + /// println!("[{}] in: {}, out: {}", interface_name, data.get_income(), data.get_outcome()); + /// } /// ``` fn get_networks(&self) -> &Networks; @@ -748,7 +750,7 @@ pub trait NetworkExt { /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// /// let s = System::new(); - /// let network = s.get_networks(); + /// let networks = s.get_networks(); /// for (interface_name, network) in networks.iter() { /// println!("in: {} B", network.get_outcome()); /// } @@ -761,7 +763,7 @@ pub trait NetworkExt { /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// /// let s = System::new(); - /// let network = s.get_networks(); + /// let networks = s.get_networks(); /// for (interface_name, network) in networks.iter() { /// println!("in: {} B", network.get_total_income()); /// } @@ -774,7 +776,7 @@ pub trait NetworkExt { /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// /// let s = System::new(); - /// let network = s.get_networks(); + /// let networks = s.get_networks(); /// for (interface_name, network) in networks.iter() { /// println!("in: {} B", network.get_total_outcome()); /// } From bebc32bd8797446b375ab5a5a6bb7c90e1cd2960 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2020 11:43:15 +0100 Subject: [PATCH 098/171] Update c_interface --- src/c_interface.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/c_interface.rs b/src/c_interface.rs index d144c35d7..4b9eef011 100644 --- a/src/c_interface.rs +++ b/src/c_interface.rs @@ -7,7 +7,7 @@ use libc::{self, c_char, c_float, c_uint, c_void, pid_t, size_t}; use std::borrow::BorrowMut; use std::ffi::CString; -use {NetworkExt, Process, ProcessExt, ProcessorExt, System, SystemExt}; +use {NetworkExt, NetworksExt, Process, ProcessExt, ProcessorExt, System, SystemExt}; /// Equivalent of `System` struct. pub type CSystem = *mut c_void; @@ -203,22 +203,30 @@ pub extern "C" fn sysinfo_get_used_swap(system: CSystem) -> size_t { ret } -/// Equivalent of `system::get_network().get_income()`. +/// Equivalent of +/// `system::get_networks().iter().fold(0, |acc, (_, data)| acc + data.get_income() as size_t)`. #[no_mangle] -pub extern "C" fn sysinfo_get_network_income(system: CSystem) -> size_t { +pub extern "C" fn sysinfo_get_networks_income(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; - let ret = system.get_network().get_income() as size_t; + let ret = system + .get_networks() + .iter() + .fold(0, |acc, (_, data)| acc + data.get_income() as size_t); Box::into_raw(system); ret } -/// Equivalent of `system::get_network().get_outcome()`. +/// Equivalent of +/// `system::get_networks().iter().fold(0, |acc, (_, data)| acc + data.get_outcome() as size_t)`. #[no_mangle] -pub extern "C" fn sysinfo_get_network_outcome(system: CSystem) -> size_t { +pub extern "C" fn sysinfo_get_networks_outcome(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; - let ret = system.get_network().get_outcome() as size_t; + let ret = system + .get_networks() + .iter() + .fold(0, |acc, (_, data)| acc + data.get_outcome() as size_t); Box::into_raw(system); ret } From 7965eda4717f2d65a6fab3ee2c66ab11177817a6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2020 11:57:34 +0100 Subject: [PATCH 099/171] fix C example --- examples/src/simple.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/src/simple.c b/examples/src/simple.c index 534d74cbb..2e6125dc1 100644 --- a/examples/src/simple.c +++ b/examples/src/simple.c @@ -63,19 +63,19 @@ bool process_loop(pid_t pid, CProcess process, void *data) { int main() { CSystem system = sysinfo_init(); sysinfo_refresh_all(system); - printf("total memory: %ld\n", sysinfo_get_total_memory(system)); - printf("free memory: %ld\n", sysinfo_get_free_memory(system)); - printf("used memory: %ld\n", sysinfo_get_used_memory(system)); - printf("total swap: %ld\n", sysinfo_get_total_swap(system)); - printf("free swap: %ld\n", sysinfo_get_free_swap(system)); - printf("used swap: %ld\n", sysinfo_get_used_swap(system)); - printf("network income: %ld\n", sysinfo_get_network_income(system)); - printf("network outcome: %ld\n", sysinfo_get_network_outcome(system)); + printf("total memory: %ld\n", sysinfo_get_total_memory(system)); + printf("free memory: %ld\n", sysinfo_get_free_memory(system)); + printf("used memory: %ld\n", sysinfo_get_used_memory(system)); + printf("total swap: %ld\n", sysinfo_get_total_swap(system)); + printf("free swap: %ld\n", sysinfo_get_free_swap(system)); + printf("used swap: %ld\n", sysinfo_get_used_swap(system)); + printf("networks income: %ld\n", sysinfo_get_networks_income(system)); + printf("networks outcome: %ld\n", sysinfo_get_networks_outcome(system)); unsigned int len = 0, i = 0; float *procs = NULL; sysinfo_get_processors_usage(system, &len, &procs); while (i < len) { - printf("Processor #%d usage: %f\n", i, procs[i]); + printf("Processor #%d usage: %f%%\n", i, procs[i]); i += 1; } free(procs); From 0277a0a55ec1ee8f222fa7e03747387b35dd9627 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 2 Feb 2020 16:24:51 +0100 Subject: [PATCH 100/171] Start network refactoring on windows --- src/windows/ffi.rs | 178 +++++++++++++++++++++++++++++++++++++++++ src/windows/mod.rs | 2 + src/windows/network.rs | 32 +++++++- src/windows/system.rs | 95 +--------------------- 4 files changed, 211 insertions(+), 96 deletions(-) create mode 100644 src/windows/ffi.rs diff --git a/src/windows/ffi.rs b/src/windows/ffi.rs new file mode 100644 index 000000000..7f561827a --- /dev/null +++ b/src/windows/ffi.rs @@ -0,0 +1,178 @@ +// TO BE REMOVED ONCE https://github.com/retep998/winapi-rs/pull/802 IS MERGED!!! +use shared::ifdef::{NET_LUID, NET_IFINDEX}; +use shared::ntdef::{UCHAR, ULONG, ULONG64, PVOID, WCHAR}; +use shared::guiddef::GUID; +use shared::minwindef::BYTE; +use shared::netioapi::NETIOAPI_API; + +const ANY_SIZE: usize = 1; + +pub const IF_MAX_STRING_SIZE: usize = 256; +pub const IF_MAX_PHYS_ADDRESS_LENGTH: usize = 32; + +pub type NET_IF_NETWORK_GUID = GUID; +pub type PMIB_IF_TABLE2 = *mut MIB_IF_TABLE2; + +STRUCT!{struct MIB_IF_TABLE2 { + NumEntries: ULONG, + Table: [MIB_IF_ROW2; ANY_SIZE], +}} + +ENUM!{enum NDIS_MEDIUM { + NdisMedium802_3 = 0, + NdisMedium802_5 = 1, + NdisMediumFddi = 2, + NdisMediumWan = 3, + NdisMediumLocalTalk = 4, + NdisMediumDix = 5, // defined for convenience, not a real medium + NdisMediumArcnetRaw = 6, + NdisMediumArcnet878_2 = 7, + NdisMediumAtm = 8, + NdisMediumWirelessWan = 9, + NdisMediumIrda = 10, + NdisMediumBpc = 11, + NdisMediumCoWan = 12, + NdisMedium1394 = 13, + NdisMediumInfiniBand = 14, + NdisMediumTunnel = 15, + NdisMediumNative802_11 = 16, + NdisMediumLoopback = 17, + NdisMediumWiMAX = 18, + NdisMediumIP = 19, + NdisMediumMax = 20, // Not a real medium, defined as an upper-bound +}} + +ENUM!{enum TUNNEL_TYPE { + TUNNEL_TYPE_NONE = 0, + TUNNEL_TYPE_OTHER = 1, + TUNNEL_TYPE_DIRECT = 2, + TUNNEL_TYPE_6TO4 = 11, + TUNNEL_TYPE_ISATAP = 13, + TUNNEL_TYPE_TEREDO = 14, + TUNNEL_TYPE_IPHTTPS = 15, +}} + +ENUM!{enum NDIS_PHYSICAL_MEDIUM { + NdisPhysicalMediumUnspecified = 0, + NdisPhysicalMediumWirelessLan = 1, + NdisPhysicalMediumCableModem = 2, + NdisPhysicalMediumPhoneLine = 3, + NdisPhysicalMediumPowerLine = 4, + NdisPhysicalMediumDSL = 5, // includes ADSL and UADSL (G.Lite) + NdisPhysicalMediumFibreChannel = 6, + NdisPhysicalMedium1394 = 7, + NdisPhysicalMediumWirelessWan = 8, + NdisPhysicalMediumNative802_11 = 9, + NdisPhysicalMediumBluetooth = 10, + NdisPhysicalMediumInfiniband = 11, + NdisPhysicalMediumWiMax = 12, + NdisPhysicalMediumUWB = 13, + NdisPhysicalMedium802_3 = 14, + NdisPhysicalMedium802_5 = 15, + NdisPhysicalMediumIrda = 16, + NdisPhysicalMediumWiredWAN = 17, + NdisPhysicalMediumWiredCoWan = 18, + NdisPhysicalMediumOther = 19, + NdisPhysicalMediumMax = 20, // Not a real physical type, defined as an upper-bound +}} + +ENUM!{enum NET_IF_ACCESS_TYPE { + NET_IF_ACCESS_LOOPBACK = 1, + NET_IF_ACCESS_BROADCAST = 2, + NET_IF_ACCESS_POINT_TO_POINT = 3, + NET_IF_ACCESS_POINT_TO_MULTI_POINT = 4, + NET_IF_ACCESS_MAXIMUM = 5, +}} + +ENUM!{enum NET_IF_DIRECTION_TYPE { + NET_IF_DIRECTION_SENDRECEIVE = 0, + NET_IF_DIRECTION_SENDONLY = 1, + NET_IF_DIRECTION_RECEIVEONLY = 2, + NET_IF_DIRECTION_MAXIMUM = 3, +}} + +ENUM!{enum IF_OPER_STATUS { + IfOperStatusUp = 1, + IfOperStatusDown = 2, + IfOperStatusTesting = 3, + IfOperStatusUnknown = 4, + IfOperStatusDormant = 5, + IfOperStatusNotPresent = 6, + IfOperStatusLowerLayerDown = 7, +}} + +ENUM!{enum NET_IF_ADMIN_STATUS { + NET_IF_ADMIN_STATUS_UP = 1, + NET_IF_ADMIN_STATUS_DOWN = 2, + NET_IF_ADMIN_STATUS_TESTING = 3, +}} + +ENUM!{enum NET_IF_MEDIA_CONNECT_STATE { + MediaConnectStateUnknown = 0, + MediaConnectStateConnected = 1, + MediaConnectStateDisconnected = 2, +}} + +ENUM!{enum NET_IF_CONNECTION_TYPE { + NET_IF_CONNECTION_DEDICATED = 1, + NET_IF_CONNECTION_PASSIVE = 2, + NET_IF_CONNECTION_DEMAND = 3, + NET_IF_CONNECTION_MAXIMUM = 4, +}} + +STRUCT!{struct MIB_IF_ROW2_InterfaceAndOperStatusFlags { + bitfield: BYTE, +}} + +STRUCT!{struct MIB_IF_ROW2 { + InterfaceLuid: NET_LUID, + InterfaceIndex: NET_IFINDEX, + InterfaceGuid: GUID, + Alias: [WCHAR; IF_MAX_STRING_SIZE + 1], + Description: [WCHAR; IF_MAX_STRING_SIZE + 1], + PhysicalAddressLength: ULONG, + PhysicalAddress: [UCHAR; IF_MAX_PHYS_ADDRESS_LENGTH], + PermanentPhysicalAddress: [UCHAR; IF_MAX_PHYS_ADDRESS_LENGTH], + Mtu: ULONG, + Type: ULONG, // Interface Type. + TunnelType: TUNNEL_TYPE, // Tunnel Type, if Type = IF_TUNNEL. + MediaType: NDIS_MEDIUM, + PhysicalMediumType: NDIS_PHYSICAL_MEDIUM, + AccessType: NET_IF_ACCESS_TYPE, + DirectionType: NET_IF_DIRECTION_TYPE, + InterfaceAndOperStatusFlags: MIB_IF_ROW2_InterfaceAndOperStatusFlags, + OperStatus: IF_OPER_STATUS, + AdminStatus: NET_IF_ADMIN_STATUS, + MediaConnectState: NET_IF_MEDIA_CONNECT_STATE, + NetworkGuid: NET_IF_NETWORK_GUID, + ConnectionType: NET_IF_CONNECTION_TYPE, + TransmitLinkSpeed: ULONG64, + ReceiveLinkSpeed: ULONG64, + InOctets: ULONG64, + InUcastPkts: ULONG64, + InNUcastPkts: ULONG64, + InDiscards: ULONG64, + InErrors: ULONG64, + InUnknownProtos: ULONG64, + InUcastOctets: ULONG64, + InMulticastOctets: ULONG64, + InBroadcastOctets: ULONG64, + OutOctets: ULONG64, + OutUcastPkts: ULONG64, + OutNUcastPkts: ULONG64, + OutDiscards: ULONG64, + OutErrors: ULONG64, + OutUcastOctets: ULONG64, + OutMulticastOctets: ULONG64, + OutBroadcastOctets: ULONG64, + OutQLen: ULONG64, +}} + +extern "system" { + pub fn GetIfTable2( + Table: *mut PMIB_IF_TABLE2, + ) -> NETIOAPI_API; + pub fn FreeMibTable( + Memory: PVOID, + ); +} diff --git a/src/windows/mod.rs b/src/windows/mod.rs index 611e9aa60..eba780a5d 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -14,6 +14,8 @@ mod processor; mod system; mod tools; +mod ffi; + pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; diff --git a/src/windows/network.rs b/src/windows/network.rs index 36ac737d2..fc63300fb 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -8,12 +8,40 @@ use windows::processor::Query; use windows::tools::KeyHandler; use NetworkExt; +pub struct Networks { + interfaces: HashMap, +} + +impl Networks { + pub(crate) fn new() -> Networks { + Networks { + interfaces: HashMap::new(), + } + } + + pub(crate) fn refresh_list(&mut self) { + ; + } + + pub(crate) fn refresh(&mut self) { + let mut table: MIB_IF_TABLE2 = zeroed(); + if unsafe { ffi::GetIfTable2(&mut table) } != NO_ERROR { + return; + } + let ptr = table.Table.as_ptr(); + for _ in 0..table.NumEntries { + // Alias + let entry = self.interfaces.entry() + // InOctets + // OutOctets + } + } +} + /// Contains network information. pub struct NetworkData { current_out: u64, current_in: u64, - keys_in: Vec, - keys_out: Vec, } impl NetworkExt for NetworkData { diff --git a/src/windows/system.rs b/src/windows/system.rs index 8bd7aa511..4ee575d50 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -124,100 +124,7 @@ impl SystemExt for System { } } - if let Some(network_trans) = get_translation(&"Network Interface".to_owned(), &x) { - let network_in_trans = get_translation(&"Bytes Received/Sec".to_owned(), &x); - let network_out_trans = get_translation(&"Bytes Sent/sec".to_owned(), &x); - - const PERF_DETAIL_WIZARD: DWORD = 400; - const PDH_MORE_DATA: DWORD = 0x800007D2; - - let mut network_trans_utf16: Vec = network_trans.encode_utf16().collect(); - network_trans_utf16.push(0); - let mut dwCounterListSize: DWORD = 0; - let mut dwInstanceListSize: DWORD = 0; - let status = unsafe { - PdhEnumObjectItemsW( - ::std::ptr::null(), - ::std::ptr::null(), - network_trans_utf16.as_ptr(), - ::std::ptr::null_mut(), - &mut dwCounterListSize, - ::std::ptr::null_mut(), - &mut dwInstanceListSize, - PERF_DETAIL_WIZARD, - 0, - ) - }; - if status != PDH_MORE_DATA as i32 { - eprintln!("PdhEnumObjectItems invalid status: {:x}", status); - } else { - let mut pwsCounterListBuffer: Vec = - Vec::with_capacity(dwCounterListSize as usize); - let mut pwsInstanceListBuffer: Vec = - Vec::with_capacity(dwInstanceListSize as usize); - unsafe { - pwsCounterListBuffer.set_len(dwCounterListSize as usize); - pwsInstanceListBuffer.set_len(dwInstanceListSize as usize); - } - let status = unsafe { - PdhEnumObjectItemsW( - ::std::ptr::null(), - ::std::ptr::null(), - network_trans_utf16.as_ptr(), - pwsCounterListBuffer.as_mut_ptr(), - &mut dwCounterListSize, - pwsInstanceListBuffer.as_mut_ptr(), - &mut dwInstanceListSize, - PERF_DETAIL_WIZARD, - 0, - ) - }; - if status != ERROR_SUCCESS as i32 { - eprintln!("PdhEnumObjectItems invalid status: {:x}", status); - } else { - for (pos, x) in pwsInstanceListBuffer - .split(|x| *x == 0) - .filter(|x| x.len() > 0) - .enumerate() - { - let net_interface = String::from_utf16(x).expect("invalid utf16"); - if let Some(ref network_in_trans) = network_in_trans { - let mut key_in = None; - add_counter( - format!( - "\\{}({})\\{}", - network_trans, net_interface, network_in_trans - ), - query, - &mut key_in, - format!("net{}_in", pos), - CounterValue::Integer(0), - ); - if key_in.is_some() { - network::get_keys_in(&mut s.network).push(key_in.unwrap()); - } - } - if let Some(ref network_out_trans) = network_out_trans { - let mut key_out = None; - add_counter( - format!( - "\\{}({})\\{}", - network_trans, net_interface, network_out_trans - ), - query, - &mut key_out, - format!("net{}_out", pos), - CounterValue::Integer(0), - ); - if key_out.is_some() { - network::get_keys_out(&mut s.network).push(key_out.unwrap()); - } - } - } - } - } - } - query.start(); + ; } s.refresh_specifics(refreshes); s From 2333ca7416bb8aa61b91846f83581a913f9f4424 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Mon, 3 Feb 2020 00:19:20 +0100 Subject: [PATCH 101/171] Greatly rework network API --- Cargo.toml | 2 +- src/linux/network.rs | 33 ++++++----- src/linux/system.rs | 18 +++--- src/mac/network.rs | 21 +++++-- src/mac/system.rs | 13 +++-- src/traits.rs | 82 +++++++++++++++++++++++++++- src/windows/ffi.rs | 27 +++++++-- src/windows/mod.rs | 2 +- src/windows/network.rs | 115 +++++++++++++++++++++++++-------------- src/windows/processor.rs | 85 +---------------------------- src/windows/system.rs | 28 +++++----- tests/process.rs | 4 +- 12 files changed, 253 insertions(+), 177 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f3f68f096..072e85039 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ rayon = "^1.0" doc-comment = "0.3" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase", "powerbase"] } +winapi = { version = "0.3", features = ["fileapi", "handleapi", "ifdef", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase", "powerbase", "netioapi"] } ntapi = "0.3" [target.'cfg(not(any(target_os = "unknown", target_arch = "wasm32")))'.dependencies] diff --git a/src/linux/network.rs b/src/linux/network.rs index 698088618..afa59a37d 100644 --- a/src/linux/network.rs +++ b/src/linux/network.rs @@ -14,6 +14,13 @@ use NetworksExt; use NetworksIter; /// Network interfaces. +/// +/// ```no_run +/// use sysinfo::{NetworksExt, System, SystemExt}; +/// +/// let s = System::new(); +/// let networks = s.get_networks(); +/// ``` #[derive(Debug)] pub struct Networks { interfaces: HashMap, @@ -54,20 +61,22 @@ impl Networks { interfaces: HashMap::new(), } } +} - pub(crate) fn update(&mut self) { - if self.interfaces.is_empty() { - self.refresh_interfaces_list(); - } else { - let mut v = vec![0; 30]; +impl NetworksExt for Networks { + fn iter<'a>(&'a self) -> NetworksIter<'a> { + NetworksIter::new(self.interfaces.iter()) + } - for (interface_name, data) in self.interfaces.iter_mut() { - data.update(interface_name, &mut v); - } + fn refresh(&mut self) { + let mut v = vec![0; 30]; + + for (interface_name, data) in self.interfaces.iter_mut() { + data.update(interface_name, &mut v); } } - pub(crate) fn refresh_interfaces_list(&mut self) { + fn refresh_interfaces_list(&mut self) { if let Ok(dir) = std::fs::read_dir("/sys/class/net/") { let mut data = vec![0; 30]; for entry in dir { @@ -117,12 +126,6 @@ impl Networks { } } -impl NetworksExt for Networks { - fn iter<'a>(&'a self) -> NetworksIter<'a> { - NetworksIter::new(self.interfaces.iter()) - } -} - /// Contains network information. #[derive(Debug)] pub struct NetworkData { diff --git a/src/linux/system.rs b/src/linux/system.rs index 86ed8f45e..2e353f7dd 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -8,11 +8,12 @@ use sys::component::{self, Component}; use sys::disk; use sys::process::*; use sys::processor::*; -use sys::Disk; -use sys::Networks; + +use Disk; use LoadAvg; +use Networks; use Pid; -use {DiskExt, ProcessExt, RefreshKind, SystemExt}; +use {DiskExt, NetworksExt, ProcessExt, RefreshKind, SystemExt}; use libc::{self, gid_t, sysconf, uid_t, _SC_CLK_TCK, _SC_PAGESIZE}; use std::cell::UnsafeCell; @@ -224,6 +225,9 @@ impl SystemExt for System { networks: Networks::new(), uptime: get_uptime(), }; + if refreshes.networks() { + s.networks.refresh_interfaces_list(); + } s.refresh_specifics(refreshes); s } @@ -313,10 +317,6 @@ impl SystemExt for System { self.disks = get_all_disks(); } - fn refresh_networks(&mut self) { - self.networks.update(); - } - // COMMON PART // // Need to be moved into a "common" file to avoid duplication. @@ -333,6 +333,10 @@ impl SystemExt for System { &self.networks } + fn get_networks_mut(&mut self) -> &mut Networks { + &mut self.networks + } + fn get_processor_list(&self) -> &[Processor] { &self.processors[..] } diff --git a/src/mac/network.rs b/src/mac/network.rs index 6d7f01573..dc94e5866 100644 --- a/src/mac/network.rs +++ b/src/mac/network.rs @@ -15,6 +15,13 @@ use NetworksExt; use NetworksIter; /// Network interfaces. +/// +/// ```no_run +/// use sysinfo::{NetworksExt, System, SystemExt}; +/// +/// let s = System::new(); +/// let networks = s.get_networks(); +/// ``` pub struct Networks { interfaces: HashMap, } @@ -25,9 +32,15 @@ impl Networks { interfaces: HashMap::new(), } } +} + +impl NetworksExt for Networks { + fn iter<'a>(&'a self) -> NetworksIter<'a> { + NetworksIter::new(self.interfaces.iter()) + } #[allow(clippy::cast_ptr_alignment)] - pub(crate) fn update(&mut self) { + fn refresh_interfaces_list(&mut self) { let mib = &mut [CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0]; let mut len = 0; if unsafe { libc::sysctl(mib.as_mut_ptr(), 6, null_mut(), &mut len, null_mut(), 0) } < 0 { @@ -88,11 +101,9 @@ impl Networks { } } } -} -impl NetworksExt for Networks { - fn iter<'a>(&'a self) -> NetworksIter<'a> { - NetworksIter::new(self.interfaces.iter()) + fn refresh(&mut self) { + self.refresh_interfaces_list(); } } diff --git a/src/mac/system.rs b/src/mac/system.rs index 4683bcf2b..6ca5cddfb 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -11,7 +11,7 @@ use sys::network::Networks; use sys::process::*; use sys::processor::*; -use {DiskExt, LoadAvg, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; +use {DiskExt, LoadAvg, NetworksExt, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; use std::cell::UnsafeCell; use std::collections::HashMap; @@ -86,6 +86,9 @@ impl SystemExt for System { uptime: get_uptime(), port: unsafe { ffi::mach_host_self() }, }; + if refreshes.networks() { + s.networks.refresh_interfaces_list(); + } s.refresh_specifics(refreshes); s } @@ -279,10 +282,6 @@ impl SystemExt for System { } } - fn refresh_networks(&mut self) { - self.networks.update(); - } - fn refresh_processes(&mut self) { let count = unsafe { ffi::proc_listallpids(::std::ptr::null_mut(), 0) }; if count < 1 { @@ -351,6 +350,10 @@ impl SystemExt for System { &self.networks } + fn get_networks_mut(&mut self) -> &mut Networks { + &mut self.networks + } + fn get_total_memory(&self) -> u64 { self.mem_total } diff --git a/src/traits.rs b/src/traits.rs index b234f6c2b..2fcbc2d3c 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -532,10 +532,47 @@ pub trait SystemExt: Sized { /// let mut s = System::new(); /// s.refresh_networks(); /// ``` - fn refresh_networks(&mut self); + /// + /// It is a shortcut for: + /// + /// ```no_run + /// use sysinfo::{NetworksExt, System, SystemExt}; + /// + /// let mut s = System::new(); + /// let networks = s.get_networks_mut(); + /// networks.refresh(); + /// ``` + fn refresh_networks(&mut self) { + self.get_networks_mut().refresh(); + } + + /// The network list will be emptied then completely recomputed. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_network_interfaces(); + /// ``` + /// + /// This is a shortcut for: + /// + /// ```no_run + /// use sysinfo::{NetworksExt, System, SystemExt}; + /// + /// let mut s = System::new(); + /// let networks = s.get_networks_mut(); + /// networks.refresh_interfaces_list(); + /// ``` + fn refresh_network_interfaces(&mut self) { + self.get_networks_mut().refresh_interfaces_list(); + } /// Refreshes all system, processes and disks information. /// + /// Please note that it doesn't recompute disks list, components list nor network interfaces + /// list. + /// /// ```no_run /// use sysinfo::{System, SystemExt}; /// @@ -702,6 +739,17 @@ pub trait SystemExt: Sized { /// ``` fn get_networks(&self) -> &Networks; + /// Returns a mutable access to network interfaces. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let mut s = System::new(); + /// let networks = s.get_networks_mut(); + /// networks.refresh_interfaces_list(); + /// ``` + fn get_networks_mut(&mut self) -> &mut Networks; + /// Returns system uptime. /// /// ```no_run @@ -787,7 +835,39 @@ pub trait NetworkExt { /// Interacting with network interfaces. pub trait NetworksExt { /// Returns an iterator over the network interfaces. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new(); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks.iter() { + /// println!("in: {} B", network.get_income()); + /// } + /// ``` fn iter(&self) -> NetworksIter; + + /// Refreshes the network interfaces list. + /// + /// ```no_run + /// use sysinfo::{NetworksExt, System, SystemExt}; + /// + /// let mut s = System::new(); + /// let networks = s.get_networks_mut(); + /// networks.refresh_interfaces_list(); + /// ``` + fn refresh_interfaces_list(&mut self); + + /// Refreshes the network interfaces' content. + /// + /// ```no_run + /// use sysinfo::{NetworksExt, System, SystemExt}; + /// + /// let mut s = System::new(); + /// let networks = s.get_networks_mut(); + /// networks.refresh(); + /// ``` + fn refresh(&mut self); } /// Getting a component temperature information. diff --git a/src/windows/ffi.rs b/src/windows/ffi.rs index 7f561827a..ff9239598 100644 --- a/src/windows/ffi.rs +++ b/src/windows/ffi.rs @@ -1,9 +1,22 @@ +// +// Sysinfo +// +// Copyright (c) 2020 Guillaume Gomez +// + // TO BE REMOVED ONCE https://github.com/retep998/winapi-rs/pull/802 IS MERGED!!! -use shared::ifdef::{NET_LUID, NET_IFINDEX}; -use shared::ntdef::{UCHAR, ULONG, ULONG64, PVOID, WCHAR}; -use shared::guiddef::GUID; -use shared::minwindef::BYTE; -use shared::netioapi::NETIOAPI_API; + +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] + +use winapi::{ENUM, STRUCT}; +use winapi::shared::basetsd::ULONG64; +use winapi::shared::ifdef::{NET_LUID, NET_IFINDEX}; +use winapi::shared::ntdef::{UCHAR, ULONG, PVOID, WCHAR}; +use winapi::shared::guiddef::GUID; +use winapi::shared::minwindef::BYTE; +use winapi::shared::netioapi::NETIOAPI_API; const ANY_SIZE: usize = 1; @@ -12,6 +25,7 @@ pub const IF_MAX_PHYS_ADDRESS_LENGTH: usize = 32; pub type NET_IF_NETWORK_GUID = GUID; pub type PMIB_IF_TABLE2 = *mut MIB_IF_TABLE2; +pub type PMIB_IF_ROW2 = *mut MIB_IF_ROW2; STRUCT!{struct MIB_IF_TABLE2 { NumEntries: ULONG, @@ -172,6 +186,9 @@ extern "system" { pub fn GetIfTable2( Table: *mut PMIB_IF_TABLE2, ) -> NETIOAPI_API; + pub fn GetIfEntry2( + Row: PMIB_IF_ROW2, + ) -> NETIOAPI_API; pub fn FreeMibTable( Memory: PVOID, ); diff --git a/src/windows/mod.rs b/src/windows/mod.rs index eba780a5d..fa111050e 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -18,7 +18,7 @@ mod ffi; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; -pub use self::network::NetworkData; +pub use self::network::{Networks, NetworkData}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; diff --git a/src/windows/network.rs b/src/windows/network.rs index fc63300fb..98f014c1e 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -4,10 +4,31 @@ // Copyright (c) 2017 Guillaume Gomez // -use windows::processor::Query; -use windows::tools::KeyHandler; +use std::collections::HashMap; + +use windows::ffi::{self, MIB_IF_ROW2, PMIB_IF_TABLE2}; use NetworkExt; +use NetworksExt; +use NetworksIter; + +use winapi::shared::ifdef::NET_LUID; +use winapi::shared::winerror::NO_ERROR; +macro_rules! old_and_new { + ($ty_:expr, $name:ident, $old:ident, $new_val:expr) => {{ + $ty_.$old = $ty_.$name; + $ty_.$name = $new_val; + }}; +} + +/// Network interfaces. +/// +/// ```no_run +/// use sysinfo::{NetworksExt, System, SystemExt}; +/// +/// let s = System::new(); +/// let networks = s.get_networks(); +/// ``` pub struct Networks { interfaces: HashMap, } @@ -18,68 +39,82 @@ impl Networks { interfaces: HashMap::new(), } } +} - pub(crate) fn refresh_list(&mut self) { - ; +impl NetworksExt for Networks { + fn iter<'a>(&'a self) -> NetworksIter<'a> { + NetworksIter::new(self.interfaces.iter()) } - pub(crate) fn refresh(&mut self) { - let mut table: MIB_IF_TABLE2 = zeroed(); + fn refresh_interfaces_list(&mut self) { + let mut table: PMIB_IF_TABLE2 = ::std::ptr::null_mut(); if unsafe { ffi::GetIfTable2(&mut table) } != NO_ERROR { return; } - let ptr = table.Table.as_ptr(); - for _ in 0..table.NumEntries { - // Alias - let entry = self.interfaces.entry() - // InOctets - // OutOctets + let ptr = unsafe { (*table).Table.as_ptr() }; + for i in 0..unsafe { *table }.NumEntries { + let ptr = unsafe { &*ptr.offset(i as _) }; + let mut pos = 0; + for x in ptr.Alias.iter() { + if *x == 0 { + break; + } + pos += 1; + } + let interface_name = match String::from_utf16(&ptr.Alias[..pos]) { + Ok(s) => s, + _ => continue, + }; + let mut interface = self.interfaces.entry(interface_name).or_insert_with(|| { + NetworkData { + id: ptr.InterfaceLuid, + current_out: ptr.OutOctets, + old_out: ptr.OutOctets, + current_in: ptr.InOctets, + old_in: ptr.InOctets, + } + }); + old_and_new!(interface, current_out, old_out, ptr.OutOctets); + old_and_new!(interface, current_in, old_in, ptr.InOctets); + } + unsafe { ffi::FreeMibTable(table as _); } + } + + fn refresh(&mut self) { + let mut entry: MIB_IF_ROW2 = unsafe { ::std::mem::MaybeUninit::uninit().assume_init() }; + for (_, interface) in self.interfaces.iter_mut() { + entry.InterfaceLuid = interface.id; + if unsafe { ffi::GetIfEntry2(&mut entry) } != NO_ERROR { + old_and_new!(interface, current_out, old_out, entry.OutOctets); + old_and_new!(interface, current_in, old_in, entry.InOctets); + } } } } /// Contains network information. pub struct NetworkData { + id: NET_LUID, current_out: u64, + old_out: u64, current_in: u64, + old_in: u64, } impl NetworkExt for NetworkData { fn get_income(&self) -> u64 { - self.current_in + self.current_in - self.old_in } fn get_outcome(&self) -> u64 { - self.current_out + self.current_out - self.old_out } -} -pub fn new() -> NetworkData { - NetworkData { - current_in: 0, - current_out: 0, - keys_in: Vec::new(), - keys_out: Vec::new(), + fn get_total_income(&self) -> u64 { + self.current_in } -} -pub fn refresh(network: &mut NetworkData, query: &Option) { - if let &Some(ref query) = query { - network.current_in = 0; - for key in &network.keys_in { - network.current_in += query.get_u64(&key.unique_id).expect("key disappeared"); - } - network.current_out = 0; - for key in &network.keys_out { - network.current_out += query.get_u64(&key.unique_id).expect("key disappeared"); - } + fn get_total_outcome(&self) -> u64 { + self.current_in } } - -pub fn get_keys_in(network: &mut NetworkData) -> &mut Vec { - &mut network.keys_in -} - -pub fn get_keys_out(network: &mut NetworkData) -> &mut Vec { - &mut network.keys_out -} diff --git a/src/windows/processor.rs b/src/windows/processor.rs index dd3245ca3..3ef2ab8f9 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -7,25 +7,21 @@ use std::collections::HashMap; use std::mem; use std::sync::{Arc, Mutex}; -use std::thread::{self, JoinHandle}; use windows::tools::KeyHandler; use ProcessorExt; use ntapi::ntpoapi::PROCESSOR_POWER_INFORMATION; -use winapi::shared::minwindef::{FALSE, ULONG}; +use winapi::shared::minwindef::FALSE; use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::handleapi::CloseHandle; use winapi::um::pdh::{ - PdhAddCounterW, PdhCloseQuery, PdhCollectQueryData, PdhCollectQueryDataEx, - PdhGetFormattedCounterValue, PdhOpenQueryA, PdhRemoveCounter, PDH_FMT_COUNTERVALUE, - PDH_FMT_DOUBLE, PDH_FMT_LARGE, PDH_HCOUNTER, PDH_HQUERY, + PdhAddCounterW, PdhCloseQuery, PdhOpenQueryA, PdhRemoveCounter, PDH_HCOUNTER, PDH_HQUERY, }; use winapi::um::powerbase::CallNtPowerInformation; -use winapi::um::synchapi::{CreateEventA, WaitForSingleObject}; +use winapi::um::synchapi::CreateEventA; use winapi::um::sysinfoapi::SYSTEM_INFO; -use winapi::um::winbase::{INFINITE, WAIT_OBJECT_0}; use winapi::um::winnt::{ProcessorInformation, HANDLE}; #[derive(Debug)] @@ -41,13 +37,6 @@ impl CounterValue { _ => panic!("not a float"), } } - - pub fn get_u64(&self) -> u64 { - match *self { - CounterValue::Integer(v) => v, - _ => panic!("not an integer"), - } - } } #[allow(dead_code)] @@ -85,56 +74,6 @@ struct InternalQuery { unsafe impl Send for InternalQuery {} unsafe impl Sync for InternalQuery {} -impl InternalQuery { - pub fn record(&self) -> bool { - unsafe { - let status = PdhCollectQueryData(self.query); - if status != ERROR_SUCCESS as i32 { - eprintln!("PdhCollectQueryData error: {:x} {:?}", status, self.query); - return false; - } - if PdhCollectQueryDataEx(self.query, 1, self.event) != ERROR_SUCCESS as i32 { - return false; - } - if WaitForSingleObject(self.event, INFINITE) == WAIT_OBJECT_0 { - if let Ok(ref mut data) = self.data.lock() { - let mut counter_type: ULONG = 0; - let mut display_value: PDH_FMT_COUNTERVALUE = ::std::mem::zeroed(); - for (_, x) in data.iter_mut() { - match x.value { - CounterValue::Float(ref mut value) => { - if PdhGetFormattedCounterValue( - x.counter, - PDH_FMT_DOUBLE, - &mut counter_type, - &mut display_value, - ) == ERROR_SUCCESS as i32 - { - *value = *display_value.u.doubleValue() as f32 / 100f32; - } - } - CounterValue::Integer(ref mut value) => { - if PdhGetFormattedCounterValue( - x.counter, - PDH_FMT_LARGE, - &mut counter_type, - &mut display_value, - ) == ERROR_SUCCESS as i32 - { - *value = *display_value.u.largeValue() as u64; - } - } - } - } - } - true - } else { - false - } - } - } -} - impl Drop for InternalQuery { fn drop(&mut self) { unsafe { @@ -157,7 +96,6 @@ impl Drop for InternalQuery { pub struct Query { internal: Arc, - thread: Option>, } impl Query { @@ -182,7 +120,6 @@ impl Query { }); Some(Query { internal: q, - thread: None, }) } } else { @@ -200,15 +137,6 @@ impl Query { None } - pub fn get_u64(&self, name: &String) -> Option { - if let Ok(data) = self.internal.data.lock() { - if let Some(ref counter) = data.get(name) { - return Some(counter.value.get_u64()); - } - } - None - } - pub fn add_counter(&mut self, name: &String, getter: Vec, value: CounterValue) -> bool { if let Ok(data) = self.internal.data.lock() { if data.contains_key(name) { @@ -237,13 +165,6 @@ impl Query { } true } - - pub fn start(&mut self) { - let internal = Arc::clone(&self.internal); - self.thread = Some(thread::spawn(move || loop { - internal.record(); - })); - } } /// Struct containing a processor information. diff --git a/src/windows/system.rs b/src/windows/system.rs index 4ee575d50..8164614f1 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -14,12 +14,13 @@ use std::mem::{size_of, zeroed}; use DiskExt; use LoadAvg; +use Networks; +use NetworksExt; use Pid; use ProcessExt; use RefreshKind; use SystemExt; -use windows::network::{self, NetworkData}; use windows::process::{ compute_cpu_usage, get_handle, get_system_computation_time, update_proc_info, Process, }; @@ -29,12 +30,10 @@ use windows::tools::*; use ntapi::ntexapi::{ NtQuerySystemInformation, SystemProcessInformation, SYSTEM_PROCESS_INFORMATION, }; -use winapi::shared::minwindef::{DWORD, FALSE}; +use winapi::shared::minwindef::FALSE; use winapi::shared::ntdef::{PVOID, ULONG}; use winapi::shared::ntstatus::STATUS_INFO_LENGTH_MISMATCH; -use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::minwinbase::STILL_ACTIVE; -use winapi::um::pdh::PdhEnumObjectItemsW; use winapi::um::processthreadsapi::GetExitCodeProcess; use winapi::um::sysinfoapi::{GlobalMemoryStatusEx, MEMORYSTATUSEX}; use winapi::um::winnt::HANDLE; @@ -52,7 +51,7 @@ pub struct System { temperatures: Vec, disks: Vec, query: Option, - network: NetworkData, + networks: Networks, uptime: u64, } @@ -75,7 +74,7 @@ impl SystemExt for System { temperatures: component::get_components(), disks: Vec::with_capacity(2), query: Query::new(), - network: network::new(), + networks: Networks::new(), uptime: get_uptime(), }; // TODO: in case a translation fails, it might be nice to log it somewhere... @@ -123,8 +122,9 @@ impl SystemExt for System { } } } - - ; + } + if refreshes.networks() { + s.networks.refresh_interfaces_list(); } s.refresh_specifics(refreshes); s @@ -166,10 +166,6 @@ impl SystemExt for System { } } - fn refresh_network(&mut self) { - network::refresh(&mut self.network, &self.query); - } - fn refresh_process(&mut self, pid: Pid) -> bool { if refresh_existing_process(self, pid, true) == false { self.process_list.remove(&pid); @@ -335,8 +331,12 @@ impl SystemExt for System { &self.disks[..] } - fn get_network(&self) -> &NetworkData { - &self.network + fn get_networks(&self) -> &Networks { + &self.networks + } + + fn get_networks_mut(&mut self) -> &mut Networks { + &mut self.networks } fn get_uptime(&self) -> u64 { diff --git a/tests/process.rs b/tests/process.rs index 75fe8a6b8..ef90f23ec 100644 --- a/tests/process.rs +++ b/tests/process.rs @@ -8,7 +8,9 @@ extern crate sysinfo; #[test] fn test_process() { - use sysinfo::{ProcessExt, SystemExt}; + use sysinfo::SystemExt; + #[cfg(not(windows))] + use sysinfo::ProcessExt; let mut s = sysinfo::System::new(); s.refresh_processes(); From 4da4d6ebbdce3f6288980e6c6a54dadf6915bb34 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 4 Feb 2020 00:52:46 +0100 Subject: [PATCH 102/171] Fix windows network part and remove software interfaces --- src/traits.rs | 21 +++++++++++++--- src/windows/ffi.rs | 31 ++++++++++++++++++++++++ src/windows/network.rs | 55 +++++++++++++++++++++++++++++++++++++++--- src/windows/system.rs | 3 +-- 4 files changed, 100 insertions(+), 10 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 2fcbc2d3c..20d51d0fd 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -356,9 +356,8 @@ pub trait ProcessorExt { /// Contains all the methods of the [`System`] type. pub trait SystemExt: Sized { - /// Creates a new [`System`] instance. It only contains the disks' list and the processes list - /// at this stage. Use the [`refresh_all`] method to update its internal information (or any of - /// the `refresh_` method). + /// Creates a new [`System`] instance with only the processes list loaded. Use the + /// [`refresh_all`] method to update its internal information (or any of the `refresh_` method). /// /// [`refresh_all`]: #method.refresh_all /// @@ -369,7 +368,21 @@ pub trait SystemExt: Sized { /// ``` fn new() -> Self { let mut s = Self::new_with_specifics(RefreshKind::new()); - s.refresh_disk_list(); + s.refresh_all(); + s + } + + /// Creates a new [`System`] instance with everything loaded. + /// + /// It is an equivalent of `SystemExt::new_with_specifics(RefreshKind::everything())`. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let s = System::new_all(); + /// ``` + fn new_all() -> Self { + let mut s = Self::new_with_specifics(RefreshKind::everything()); s.refresh_all(); s } diff --git a/src/windows/ffi.rs b/src/windows/ffi.rs index ff9239598..47565d8a3 100644 --- a/src/windows/ffi.rs +++ b/src/windows/ffi.rs @@ -9,6 +9,7 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(non_upper_case_globals)] +#![allow(dead_code)] use winapi::{ENUM, STRUCT}; use winapi::shared::basetsd::ULONG64; @@ -27,6 +28,26 @@ pub type NET_IF_NETWORK_GUID = GUID; pub type PMIB_IF_TABLE2 = *mut MIB_IF_TABLE2; pub type PMIB_IF_ROW2 = *mut MIB_IF_ROW2; +macro_rules! BITFIELD { + ($base:ident $field:ident: $fieldtype:ty [ + $($thing:ident $set_thing:ident[$r:expr],)+ + ]) => { + impl $base {$( + #[inline] + pub fn $thing(&self) -> $fieldtype { + let size = ::std::mem::size_of::<$fieldtype>() * 8; + self.$field << (size - $r.end) >> (size - $r.end + $r.start) + } + #[inline] + pub fn $set_thing(&mut self, val: $fieldtype) { + let mask = ((1 << ($r.end - $r.start)) - 1) << $r.start; + self.$field &= !mask; + self.$field |= (val << $r.start) & mask; + } + )+} + } +} + STRUCT!{struct MIB_IF_TABLE2 { NumEntries: ULONG, Table: [MIB_IF_ROW2; ANY_SIZE], @@ -137,6 +158,16 @@ ENUM!{enum NET_IF_CONNECTION_TYPE { STRUCT!{struct MIB_IF_ROW2_InterfaceAndOperStatusFlags { bitfield: BYTE, }} +BITFIELD!{MIB_IF_ROW2_InterfaceAndOperStatusFlags bitfield: BYTE [ + HardwareInterface set_HardwareInterface[0..1], + FilterInterface set_FilterInterface[1..2], + ConnectorPresent set_ConnectorPresent[2..3], + NotAuthenticated set_NotAuthenticated[3..4], + NotMediaConnected set_NotMediaConnected[4..5], + Paused set_Paused[5..6], + LowPower set_LowPower[6..7], + EndPointInterface set_EndPointInterface[7..8], +]} STRUCT!{struct MIB_IF_ROW2 { InterfaceLuid: NET_LUID, diff --git a/src/windows/network.rs b/src/windows/network.rs index 98f014c1e..46ff29437 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -4,7 +4,7 @@ // Copyright (c) 2017 Guillaume Gomez // -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use windows::ffi::{self, MIB_IF_ROW2, PMIB_IF_TABLE2}; use NetworkExt; @@ -51,9 +51,50 @@ impl NetworksExt for Networks { if unsafe { ffi::GetIfTable2(&mut table) } != NO_ERROR { return; } + let mut to_be_removed = HashSet::with_capacity(self.interfaces.len()); + + for key in self.interfaces.keys() { + to_be_removed.insert(key.clone()); + } + // In here, this is tricky: we have to filter out the software interfaces to only keep + // the hardware ones. To do so, we first check the connection potential speed (if 0, not + // interesting), then we check its state: if not open, not interesting either. And finally, + // we count the members of a same group: if there is more than 1, then it's software level. + let mut groups = HashMap::new(); + let mut indexes = Vec::new(); let ptr = unsafe { (*table).Table.as_ptr() }; for i in 0..unsafe { *table }.NumEntries { let ptr = unsafe { &*ptr.offset(i as _) }; + if ptr.TransmitLinkSpeed == 0 && ptr.ReceiveLinkSpeed == 0 { + continue; + } else if ptr.MediaConnectState == ffi::MediaConnectStateDisconnected + || ptr.PhysicalAddressLength == 0 { + continue; + } + let id = vec![ + ptr.InterfaceGuid.Data2, + ptr.InterfaceGuid.Data3, + ptr.InterfaceGuid.Data4[0] as _, + ptr.InterfaceGuid.Data4[1] as _, + ptr.InterfaceGuid.Data4[2] as _, + ptr.InterfaceGuid.Data4[3] as _, + ptr.InterfaceGuid.Data4[4] as _, + ptr.InterfaceGuid.Data4[5] as _, + ptr.InterfaceGuid.Data4[6] as _, + ptr.InterfaceGuid.Data4[7] as _, + ]; + let entry = groups.entry(id.clone()).or_insert(0); + *entry += 1; + if *entry > 1 { + continue; + } + indexes.push((i, id)); + } + for (i, id) in indexes { + let ptr = unsafe { &*ptr.offset(i as _) }; + if *groups.get(&id).unwrap_or(&0) > 1 { + continue; + } let mut pos = 0; for x in ptr.Alias.iter() { if *x == 0 { @@ -65,6 +106,7 @@ impl NetworksExt for Networks { Ok(s) => s, _ => continue, }; + to_be_removed.remove(&interface_name); let mut interface = self.interfaces.entry(interface_name).or_insert_with(|| { NetworkData { id: ptr.InterfaceLuid, @@ -78,16 +120,21 @@ impl NetworksExt for Networks { old_and_new!(interface, current_in, old_in, ptr.InOctets); } unsafe { ffi::FreeMibTable(table as _); } + for key in to_be_removed { + self.interfaces.remove(&key); + } } fn refresh(&mut self) { let mut entry: MIB_IF_ROW2 = unsafe { ::std::mem::MaybeUninit::uninit().assume_init() }; for (_, interface) in self.interfaces.iter_mut() { entry.InterfaceLuid = interface.id; + entry.InterfaceIndex = 0; // to prevent the function to pick this one as index if unsafe { ffi::GetIfEntry2(&mut entry) } != NO_ERROR { - old_and_new!(interface, current_out, old_out, entry.OutOctets); - old_and_new!(interface, current_in, old_in, entry.InOctets); + continue; } + old_and_new!(interface, current_out, old_out, entry.OutOctets); + old_and_new!(interface, current_in, old_in, entry.InOctets); } } } @@ -115,6 +162,6 @@ impl NetworkExt for NetworkData { } fn get_total_outcome(&self) -> u64 { - self.current_in + self.current_out } } diff --git a/src/windows/system.rs b/src/windows/system.rs index 8164614f1..bc7fe0336 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -15,7 +15,6 @@ use std::mem::{size_of, zeroed}; use DiskExt; use LoadAvg; use Networks; -use NetworksExt; use Pid; use ProcessExt; use RefreshKind; @@ -124,7 +123,7 @@ impl SystemExt for System { } } if refreshes.networks() { - s.networks.refresh_interfaces_list(); + s.refresh_network_interfaces(); } s.refresh_specifics(refreshes); s From 1dabf925e967b280c9247a1817a4f22e3e681be5 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 4 Feb 2020 00:52:58 +0100 Subject: [PATCH 103/171] Improve network display in example --- examples/src/simple.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index d4fa7ca9f..56b9cad20 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -366,7 +366,7 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { fn main() { println!("Getting processes' information..."); - let mut t = System::new(); + let mut t = System::new_all(); println!("Done."); let t_stin = io::stdin(); let mut stin = t_stin.lock(); From b16d9c9bbf4c7c499eb4aff394aebf62f6f1d292 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 4 Feb 2020 17:05:41 +0100 Subject: [PATCH 104/171] Add load average support for windows --- Cargo.toml | 4 +- src/windows/ffi.rs | 44 +++++++-------- src/windows/mod.rs | 2 +- src/windows/network.rs | 26 +++++---- src/windows/processor.rs | 118 ++++++++++++++++++++++++++++++++++----- src/windows/system.rs | 7 +-- tests/process.rs | 2 +- 7 files changed, 142 insertions(+), 61 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 072e85039..ee1183852 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,13 +20,11 @@ doc-comment = "0.3" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "handleapi", "ifdef", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase", "powerbase", "netioapi"] } ntapi = "0.3" +once_cell = "1.0" [target.'cfg(not(any(target_os = "unknown", target_arch = "wasm32")))'.dependencies] libc = "0.2" -[target.'cfg(unix)'.dependencies] -once_cell = "1.0" - [lib] name = "sysinfo" crate_type = ["rlib", "cdylib"] diff --git a/src/windows/ffi.rs b/src/windows/ffi.rs index 47565d8a3..e57c67515 100644 --- a/src/windows/ffi.rs +++ b/src/windows/ffi.rs @@ -11,13 +11,13 @@ #![allow(non_upper_case_globals)] #![allow(dead_code)] -use winapi::{ENUM, STRUCT}; use winapi::shared::basetsd::ULONG64; -use winapi::shared::ifdef::{NET_LUID, NET_IFINDEX}; -use winapi::shared::ntdef::{UCHAR, ULONG, PVOID, WCHAR}; use winapi::shared::guiddef::GUID; +use winapi::shared::ifdef::{NET_IFINDEX, NET_LUID}; use winapi::shared::minwindef::BYTE; use winapi::shared::netioapi::NETIOAPI_API; +use winapi::shared::ntdef::{PVOID, UCHAR, ULONG, WCHAR}; +use winapi::{ENUM, STRUCT}; const ANY_SIZE: usize = 1; @@ -48,12 +48,12 @@ macro_rules! BITFIELD { } } -STRUCT!{struct MIB_IF_TABLE2 { +STRUCT! {struct MIB_IF_TABLE2 { NumEntries: ULONG, Table: [MIB_IF_ROW2; ANY_SIZE], }} -ENUM!{enum NDIS_MEDIUM { +ENUM! {enum NDIS_MEDIUM { NdisMedium802_3 = 0, NdisMedium802_5 = 1, NdisMediumFddi = 2, @@ -77,7 +77,7 @@ ENUM!{enum NDIS_MEDIUM { NdisMediumMax = 20, // Not a real medium, defined as an upper-bound }} -ENUM!{enum TUNNEL_TYPE { +ENUM! {enum TUNNEL_TYPE { TUNNEL_TYPE_NONE = 0, TUNNEL_TYPE_OTHER = 1, TUNNEL_TYPE_DIRECT = 2, @@ -87,7 +87,7 @@ ENUM!{enum TUNNEL_TYPE { TUNNEL_TYPE_IPHTTPS = 15, }} -ENUM!{enum NDIS_PHYSICAL_MEDIUM { +ENUM! {enum NDIS_PHYSICAL_MEDIUM { NdisPhysicalMediumUnspecified = 0, NdisPhysicalMediumWirelessLan = 1, NdisPhysicalMediumCableModem = 2, @@ -111,7 +111,7 @@ ENUM!{enum NDIS_PHYSICAL_MEDIUM { NdisPhysicalMediumMax = 20, // Not a real physical type, defined as an upper-bound }} -ENUM!{enum NET_IF_ACCESS_TYPE { +ENUM! {enum NET_IF_ACCESS_TYPE { NET_IF_ACCESS_LOOPBACK = 1, NET_IF_ACCESS_BROADCAST = 2, NET_IF_ACCESS_POINT_TO_POINT = 3, @@ -119,14 +119,14 @@ ENUM!{enum NET_IF_ACCESS_TYPE { NET_IF_ACCESS_MAXIMUM = 5, }} -ENUM!{enum NET_IF_DIRECTION_TYPE { +ENUM! {enum NET_IF_DIRECTION_TYPE { NET_IF_DIRECTION_SENDRECEIVE = 0, NET_IF_DIRECTION_SENDONLY = 1, NET_IF_DIRECTION_RECEIVEONLY = 2, NET_IF_DIRECTION_MAXIMUM = 3, }} -ENUM!{enum IF_OPER_STATUS { +ENUM! {enum IF_OPER_STATUS { IfOperStatusUp = 1, IfOperStatusDown = 2, IfOperStatusTesting = 3, @@ -136,29 +136,29 @@ ENUM!{enum IF_OPER_STATUS { IfOperStatusLowerLayerDown = 7, }} -ENUM!{enum NET_IF_ADMIN_STATUS { +ENUM! {enum NET_IF_ADMIN_STATUS { NET_IF_ADMIN_STATUS_UP = 1, NET_IF_ADMIN_STATUS_DOWN = 2, NET_IF_ADMIN_STATUS_TESTING = 3, }} -ENUM!{enum NET_IF_MEDIA_CONNECT_STATE { +ENUM! {enum NET_IF_MEDIA_CONNECT_STATE { MediaConnectStateUnknown = 0, MediaConnectStateConnected = 1, MediaConnectStateDisconnected = 2, }} -ENUM!{enum NET_IF_CONNECTION_TYPE { +ENUM! {enum NET_IF_CONNECTION_TYPE { NET_IF_CONNECTION_DEDICATED = 1, NET_IF_CONNECTION_PASSIVE = 2, NET_IF_CONNECTION_DEMAND = 3, NET_IF_CONNECTION_MAXIMUM = 4, }} -STRUCT!{struct MIB_IF_ROW2_InterfaceAndOperStatusFlags { +STRUCT! {struct MIB_IF_ROW2_InterfaceAndOperStatusFlags { bitfield: BYTE, }} -BITFIELD!{MIB_IF_ROW2_InterfaceAndOperStatusFlags bitfield: BYTE [ +BITFIELD! {MIB_IF_ROW2_InterfaceAndOperStatusFlags bitfield: BYTE [ HardwareInterface set_HardwareInterface[0..1], FilterInterface set_FilterInterface[1..2], ConnectorPresent set_ConnectorPresent[2..3], @@ -169,7 +169,7 @@ BITFIELD!{MIB_IF_ROW2_InterfaceAndOperStatusFlags bitfield: BYTE [ EndPointInterface set_EndPointInterface[7..8], ]} -STRUCT!{struct MIB_IF_ROW2 { +STRUCT! {struct MIB_IF_ROW2 { InterfaceLuid: NET_LUID, InterfaceIndex: NET_IFINDEX, InterfaceGuid: GUID, @@ -214,13 +214,7 @@ STRUCT!{struct MIB_IF_ROW2 { }} extern "system" { - pub fn GetIfTable2( - Table: *mut PMIB_IF_TABLE2, - ) -> NETIOAPI_API; - pub fn GetIfEntry2( - Row: PMIB_IF_ROW2, - ) -> NETIOAPI_API; - pub fn FreeMibTable( - Memory: PVOID, - ); + pub fn GetIfTable2(Table: *mut PMIB_IF_TABLE2) -> NETIOAPI_API; + pub fn GetIfEntry2(Row: PMIB_IF_ROW2) -> NETIOAPI_API; + pub fn FreeMibTable(Memory: PVOID); } diff --git a/src/windows/mod.rs b/src/windows/mod.rs index fa111050e..633234aa9 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -18,7 +18,7 @@ mod ffi; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; -pub use self::network::{Networks, NetworkData}; +pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; diff --git a/src/windows/network.rs b/src/windows/network.rs index 46ff29437..79a6a9840 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -68,7 +68,8 @@ impl NetworksExt for Networks { if ptr.TransmitLinkSpeed == 0 && ptr.ReceiveLinkSpeed == 0 { continue; } else if ptr.MediaConnectState == ffi::MediaConnectStateDisconnected - || ptr.PhysicalAddressLength == 0 { + || ptr.PhysicalAddressLength == 0 + { continue; } let id = vec![ @@ -107,19 +108,22 @@ impl NetworksExt for Networks { _ => continue, }; to_be_removed.remove(&interface_name); - let mut interface = self.interfaces.entry(interface_name).or_insert_with(|| { - NetworkData { - id: ptr.InterfaceLuid, - current_out: ptr.OutOctets, - old_out: ptr.OutOctets, - current_in: ptr.InOctets, - old_in: ptr.InOctets, - } - }); + let mut interface = + self.interfaces + .entry(interface_name) + .or_insert_with(|| NetworkData { + id: ptr.InterfaceLuid, + current_out: ptr.OutOctets, + old_out: ptr.OutOctets, + current_in: ptr.InOctets, + old_in: ptr.InOctets, + }); old_and_new!(interface, current_out, old_out, ptr.OutOctets); old_and_new!(interface, current_in, old_in, ptr.InOctets); } - unsafe { ffi::FreeMibTable(table as _); } + unsafe { + ffi::FreeMibTable(table as _); + } for key in to_be_removed { self.interfaces.remove(&key); } diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 3ef2ab8f9..01329be52 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -6,9 +6,12 @@ use std::collections::HashMap; use std::mem; +use std::ops::DerefMut; +use std::ptr::null_mut; use std::sync::{Arc, Mutex}; use windows::tools::KeyHandler; +use LoadAvg; use ProcessorExt; use ntapi::ntpoapi::PROCESSOR_POWER_INFORMATION; @@ -17,12 +20,105 @@ use winapi::shared::minwindef::FALSE; use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::handleapi::CloseHandle; use winapi::um::pdh::{ - PdhAddCounterW, PdhCloseQuery, PdhOpenQueryA, PdhRemoveCounter, PDH_HCOUNTER, PDH_HQUERY, + PdhAddCounterW, PdhAddEnglishCounterA, PdhCloseQuery, PdhCollectQueryDataEx, + PdhGetFormattedCounterValue, PdhOpenQueryA, PdhRemoveCounter, PDH_FMT_COUNTERVALUE, + PDH_FMT_DOUBLE, PDH_HCOUNTER, PDH_HQUERY, }; use winapi::um::powerbase::CallNtPowerInformation; use winapi::um::synchapi::CreateEventA; use winapi::um::sysinfoapi::SYSTEM_INFO; -use winapi::um::winnt::{ProcessorInformation, HANDLE}; +use winapi::um::winbase::{RegisterWaitForSingleObject, INFINITE}; +use winapi::um::winnt::{ProcessorInformation, BOOLEAN, HANDLE, PVOID, WT_EXECUTEDEFAULT}; + +// This formula comes from linux's include/linux/sched/loadavg.h +// https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L20-L23 +const LOADAVG_FACTOR_1F: f64 = 0.9200444146293232478931553241; +const LOADAVG_FACTOR_5F: f64 = 0.6592406302004437462547604110; +const LOADAVG_FACTOR_15F: f64 = 0.2865047968601901003248854266; +// The time interval in seconds between taking load counts, same as Linux +const SAMPLING_INTERVAL: usize = 5; + +// maybe use a read/write lock instead? +static LOAD_AVG: once_cell::sync::Lazy>> = + once_cell::sync::Lazy::new(|| unsafe { init_load_avg() }); + +pub(crate) fn get_load_average() -> LoadAvg { + if let Ok(avg) = LOAD_AVG.lock() { + if let Some(avg) = &*avg { + return avg.clone(); + } + } + return LoadAvg::default(); +} + +unsafe extern "system" fn load_avg_callback(counter: PVOID, _: BOOLEAN) { + let mut display_value: PDH_FMT_COUNTERVALUE = mem::MaybeUninit::uninit().assume_init(); + + if PdhGetFormattedCounterValue(counter as _, PDH_FMT_DOUBLE, null_mut(), &mut display_value) + != ERROR_SUCCESS as _ + { + return; + } + if let Ok(mut avg) = LOAD_AVG.lock() { + if let Some(avg) = avg.deref_mut() { + let current_load = display_value.u.doubleValue(); + + avg.one = avg.one * LOADAVG_FACTOR_1F + current_load * (1.0 - LOADAVG_FACTOR_1F); + avg.five = avg.five * LOADAVG_FACTOR_5F + current_load * (1.0 - LOADAVG_FACTOR_5F); + avg.fifteen = + avg.fifteen * LOADAVG_FACTOR_15F + current_load * (1.0 - LOADAVG_FACTOR_15F); + } + } +} + +unsafe fn init_load_avg() -> Mutex> { + // You can see the original implementation here: https://github.com/giampaolo/psutil + let mut query = null_mut(); + + if PdhOpenQueryA(null_mut(), 0, &mut query) != ERROR_SUCCESS as _ { + return Mutex::new(None); + } + + let mut counter: PDH_HCOUNTER = mem::zeroed(); + if PdhAddEnglishCounterA( + query, + b"\\System\\Processor Queue Length\0".as_ptr() as _, + 0, + &mut counter, + ) != ERROR_SUCCESS as _ + { + PdhCloseQuery(query); + return Mutex::new(None); + } + + let event = CreateEventA(null_mut(), FALSE, FALSE, b"LoadUpdateEvent\0".as_ptr() as _); + if event.is_null() { + PdhCloseQuery(query); + return Mutex::new(None); + } + + if PdhCollectQueryDataEx(query, SAMPLING_INTERVAL as _, event) != ERROR_SUCCESS as _ { + PdhCloseQuery(query); + return Mutex::new(None); + } + + let mut wait_handle = null_mut(); + if RegisterWaitForSingleObject( + &mut wait_handle, + event, + Some(load_avg_callback), + counter as _, + INFINITE, + WT_EXECUTEDEFAULT, + ) == 0 + { + PdhRemoveCounter(counter); + PdhCloseQuery(query); + return Mutex::new(None); + } + + return Mutex::new(Some(LoadAvg::default())); +} #[derive(Debug)] pub enum CounterValue { @@ -100,15 +196,11 @@ pub struct Query { impl Query { pub fn new() -> Option { - let mut query = ::std::ptr::null_mut(); + let mut query = null_mut(); unsafe { - if PdhOpenQueryA(::std::ptr::null_mut(), 0, &mut query) == ERROR_SUCCESS as i32 { - let event = CreateEventA( - ::std::ptr::null_mut(), - FALSE, - FALSE, - b"some_ev\0".as_ptr() as *const i8, - ); + if PdhOpenQueryA(null_mut(), 0, &mut query) == ERROR_SUCCESS as i32 { + let event = + CreateEventA(null_mut(), FALSE, FALSE, b"some_ev\0".as_ptr() as *const i8); if event.is_null() { PdhCloseQuery(query); None @@ -118,9 +210,7 @@ impl Query { event: event, data: Mutex::new(HashMap::new()), }); - Some(Query { - internal: q, - }) + Some(Query { internal: q }) } } else { None @@ -341,7 +431,7 @@ pub fn get_frequencies(nb_processors: usize) -> Vec { if unsafe { CallNtPowerInformation( ProcessorInformation, - ::std::ptr::null_mut(), + null_mut(), 0, infos.as_mut_ptr() as _, size as _, diff --git a/src/windows/system.rs b/src/windows/system.rs index bc7fe0336..270ffdfd4 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -342,13 +342,8 @@ impl SystemExt for System { self.uptime } - /// Not yet implemented. fn get_load_average(&self) -> LoadAvg { - LoadAvg { - one: 0., - five: 0., - fifteen: 0., - } + get_load_average() } } diff --git a/tests/process.rs b/tests/process.rs index ef90f23ec..caaf6dc07 100644 --- a/tests/process.rs +++ b/tests/process.rs @@ -8,9 +8,9 @@ extern crate sysinfo; #[test] fn test_process() { - use sysinfo::SystemExt; #[cfg(not(windows))] use sysinfo::ProcessExt; + use sysinfo::SystemExt; let mut s = sysinfo::System::new(); s.refresh_processes(); From 1691e9f4185a68c5add1f0b84a113a23fb2ab97d Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 4 Feb 2020 17:46:49 +0100 Subject: [PATCH 105/171] Remove duplicate calls on refresh --- src/traits.rs | 10 +++------- src/windows/network.rs | 1 + src/windows/system.rs | 9 +++++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 20d51d0fd..1af987b3e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -367,9 +367,7 @@ pub trait SystemExt: Sized { /// let s = System::new(); /// ``` fn new() -> Self { - let mut s = Self::new_with_specifics(RefreshKind::new()); - s.refresh_all(); - s + Self::new_with_specifics(RefreshKind::new()) } /// Creates a new [`System`] instance with everything loaded. @@ -382,9 +380,7 @@ pub trait SystemExt: Sized { /// let s = System::new_all(); /// ``` fn new_all() -> Self { - let mut s = Self::new_with_specifics(RefreshKind::everything()); - s.refresh_all(); - s + Self::new_with_specifics(RefreshKind::everything()) } /// Creates a new [`System`] instance and refresh the data corresponding to the @@ -581,7 +577,7 @@ pub trait SystemExt: Sized { self.get_networks_mut().refresh_interfaces_list(); } - /// Refreshes all system, processes and disks information. + /// Refreshes all system, processes, disks and network interfaces information. /// /// Please note that it doesn't recompute disks list, components list nor network interfaces /// list. diff --git a/src/windows/network.rs b/src/windows/network.rs index 79a6a9840..470457741 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -130,6 +130,7 @@ impl NetworksExt for Networks { } fn refresh(&mut self) { + println!("refresh network!"); let mut entry: MIB_IF_ROW2 = unsafe { ::std::mem::MaybeUninit::uninit().assume_init() }; for (_, interface) in self.interfaces.iter_mut() { entry.InterfaceLuid = interface.id; diff --git a/src/windows/system.rs b/src/windows/system.rs index 270ffdfd4..5d63cb993 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -157,8 +157,17 @@ impl SystemExt for System { } } + /// Refresh components' temperature. + /// /// Please note that on Windows, you need to have Administrator priviledges to get this /// information. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_temperatures(); + /// ``` fn refresh_temperatures(&mut self) { for component in &mut self.temperatures { component.refresh(); From b3f6c3c2bf29b414cc8d5bbd9e3347c810bec988 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 4 Feb 2020 17:49:26 +0100 Subject: [PATCH 106/171] Add networks_list entry for RefreshKind --- src/common.rs | 5 +++++ src/linux/system.rs | 3 --- src/mac/system.rs | 3 --- src/traits.rs | 3 +++ src/windows/system.rs | 3 --- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/common.rs b/src/common.rs index 4ccf9be36..854e2339c 100644 --- a/src/common.rs +++ b/src/common.rs @@ -115,6 +115,7 @@ assert_eq!(r.", stringify!($name), "(), false); #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct RefreshKind { networks: bool, + networks_list: bool, processes: bool, disk_list: bool, disks: bool, @@ -134,6 +135,7 @@ impl RefreshKind { /// let r = RefreshKind::new(); /// /// assert_eq!(r.networks(), false); + /// assert_eq!(r.networks_list(), false); /// assert_eq!(r.processes(), false); /// assert_eq!(r.disk_list(), false); /// assert_eq!(r.disks(), false); @@ -163,6 +165,7 @@ impl RefreshKind { /// let r = RefreshKind::everything(); /// /// assert_eq!(r.networks(), true); + /// assert_eq!(r.networks_list(), true); /// assert_eq!(r.processes(), true); /// assert_eq!(r.disk_list(), true); /// assert_eq!(r.disks(), true); @@ -173,6 +176,7 @@ impl RefreshKind { pub fn everything() -> RefreshKind { RefreshKind { networks: true, + networks_list: true, processes: true, disks: true, disk_list: true, @@ -183,6 +187,7 @@ impl RefreshKind { } impl_get_set!(networks, with_networks, without_networks); + impl_get_set!(networks_list, with_networks_list, without_networks_list); impl_get_set!(processes, with_processes, without_processes); impl_get_set!(disks, with_disks, without_disks); impl_get_set!(disk_list, with_disk_list, without_disk_list); diff --git a/src/linux/system.rs b/src/linux/system.rs index 2e353f7dd..79e3156db 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -225,9 +225,6 @@ impl SystemExt for System { networks: Networks::new(), uptime: get_uptime(), }; - if refreshes.networks() { - s.networks.refresh_interfaces_list(); - } s.refresh_specifics(refreshes); s } diff --git a/src/mac/system.rs b/src/mac/system.rs index 6ca5cddfb..eb642f158 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -86,9 +86,6 @@ impl SystemExt for System { uptime: get_uptime(), port: unsafe { ffi::mach_host_self() }, }; - if refreshes.networks() { - s.networks.refresh_interfaces_list(); - } s.refresh_specifics(refreshes); s } diff --git a/src/traits.rs b/src/traits.rs index 1af987b3e..bb57f70fc 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -427,6 +427,9 @@ pub trait SystemExt: Sized { if refreshes.temperatures() { self.refresh_temperatures(); } + if refreshes.networks_list() { + self.refresh_network_interfaces(); + } if refreshes.networks() { self.refresh_networks(); } diff --git a/src/windows/system.rs b/src/windows/system.rs index 5d63cb993..ef9db0827 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -122,9 +122,6 @@ impl SystemExt for System { } } } - if refreshes.networks() { - s.refresh_network_interfaces(); - } s.refresh_specifics(refreshes); s } From 088bf1d62287281a40ed3699f67f42cf47bb6d2c Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 4 Feb 2020 17:57:34 +0100 Subject: [PATCH 107/171] renaming for some methods --- examples/src/simple.rs | 2 +- src/common.rs | 15 +++--- src/linux/network.rs | 4 +- src/linux/system.rs | 2 +- src/mac/network.rs | 4 +- src/mac/system.rs | 2 +- src/traits.rs | 108 ++++++++++++++++++++--------------------- src/unknown/system.rs | 2 +- src/windows/network.rs | 4 +- src/windows/system.rs | 2 +- 10 files changed, 73 insertions(+), 72 deletions(-) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index 56b9cad20..c50e7d231 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -129,7 +129,7 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { "help" => print_help(), "refresh_disks" => { writeln!(&mut io::stdout(), "Refreshing disk list..."); - sys.refresh_disk_list(); + sys.refresh_disks_list(); writeln!(&mut io::stdout(), "Done."); } "signals" => { diff --git a/src/common.rs b/src/common.rs index 854e2339c..3e857716b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -107,7 +107,7 @@ assert_eq!(r.", stringify!($name), "(), false); /// use sysinfo::{RefreshKind, System, SystemExt}; /// /// // We want everything except disks. -/// let mut system = System::new_with_specifics(RefreshKind::everything().without_disk_list()); +/// let mut system = System::new_with_specifics(RefreshKind::everything().without_disks_list()); /// /// assert_eq!(system.get_disks().len(), 0); /// assert!(system.get_process_list().len() > 0); @@ -117,7 +117,7 @@ pub struct RefreshKind { networks: bool, networks_list: bool, processes: bool, - disk_list: bool, + disks_list: bool, disks: bool, memory: bool, cpu: bool, @@ -137,7 +137,7 @@ impl RefreshKind { /// assert_eq!(r.networks(), false); /// assert_eq!(r.networks_list(), false); /// assert_eq!(r.processes(), false); - /// assert_eq!(r.disk_list(), false); + /// assert_eq!(r.disks_list(), false); /// assert_eq!(r.disks(), false); /// assert_eq!(r.memory(), false); /// assert_eq!(r.cpu(), false); @@ -146,9 +146,10 @@ impl RefreshKind { pub fn new() -> RefreshKind { RefreshKind { networks: false, + networks_list: true, processes: false, disks: false, - disk_list: false, + disks_list: false, memory: false, cpu: false, temperatures: false, @@ -167,7 +168,7 @@ impl RefreshKind { /// assert_eq!(r.networks(), true); /// assert_eq!(r.networks_list(), true); /// assert_eq!(r.processes(), true); - /// assert_eq!(r.disk_list(), true); + /// assert_eq!(r.disks_list(), true); /// assert_eq!(r.disks(), true); /// assert_eq!(r.memory(), true); /// assert_eq!(r.cpu(), true); @@ -179,7 +180,7 @@ impl RefreshKind { networks_list: true, processes: true, disks: true, - disk_list: true, + disks_list: true, memory: true, cpu: true, temperatures: true, @@ -190,7 +191,7 @@ impl RefreshKind { impl_get_set!(networks_list, with_networks_list, without_networks_list); impl_get_set!(processes, with_processes, without_processes); impl_get_set!(disks, with_disks, without_disks); - impl_get_set!(disk_list, with_disk_list, without_disk_list); + impl_get_set!(disks_list, with_disks_list, without_disks_list); impl_get_set!(memory, with_memory, without_memory); impl_get_set!(cpu, with_cpu, without_cpu); impl_get_set!(temperatures, with_temperatures, without_temperatures); diff --git a/src/linux/network.rs b/src/linux/network.rs index afa59a37d..f08ebef0f 100644 --- a/src/linux/network.rs +++ b/src/linux/network.rs @@ -18,7 +18,7 @@ use NetworksIter; /// ```no_run /// use sysinfo::{NetworksExt, System, SystemExt}; /// -/// let s = System::new(); +/// let s = System::new_all(); /// let networks = s.get_networks(); /// ``` #[derive(Debug)] @@ -76,7 +76,7 @@ impl NetworksExt for Networks { } } - fn refresh_interfaces_list(&mut self) { + fn refresh_networks_list(&mut self) { if let Ok(dir) = std::fs::read_dir("/sys/class/net/") { let mut data = vec![0; 30]; for entry in dir { diff --git a/src/linux/system.rs b/src/linux/system.rs index 79e3156db..709506083 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -310,7 +310,7 @@ impl SystemExt for System { } } - fn refresh_disk_list(&mut self) { + fn refresh_disks_list(&mut self) { self.disks = get_all_disks(); } diff --git a/src/mac/network.rs b/src/mac/network.rs index dc94e5866..55dbe953d 100644 --- a/src/mac/network.rs +++ b/src/mac/network.rs @@ -19,7 +19,7 @@ use NetworksIter; /// ```no_run /// use sysinfo::{NetworksExt, System, SystemExt}; /// -/// let s = System::new(); +/// let s = System::new_all(); /// let networks = s.get_networks(); /// ``` pub struct Networks { @@ -40,7 +40,7 @@ impl NetworksExt for Networks { } #[allow(clippy::cast_ptr_alignment)] - fn refresh_interfaces_list(&mut self) { + fn refresh_networks_list(&mut self) { let mib = &mut [CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0]; let mut len = 0; if unsafe { libc::sysctl(mib.as_mut_ptr(), 6, null_mut(), &mut len, null_mut(), 0) } < 0 { diff --git a/src/mac/system.rs b/src/mac/system.rs index eb642f158..6c02d70ad 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -323,7 +323,7 @@ impl SystemExt for System { } } - fn refresh_disk_list(&mut self) { + fn refresh_disks_list(&mut self) { self.disks = crate::mac::disk::get_disks(); } diff --git a/src/traits.rs b/src/traits.rs index bb57f70fc..48a4aa736 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -392,14 +392,14 @@ pub trait SystemExt: Sized { /// use sysinfo::{RefreshKind, System, SystemExt}; /// /// // We want everything except disks. - /// let mut system = System::new_with_specifics(RefreshKind::everything().without_disk_list()); + /// let mut system = System::new_with_specifics(RefreshKind::everything().without_disks_list()); /// /// assert_eq!(system.get_disks().len(), 0); /// assert!(system.get_process_list().len() > 0); /// /// // If you want the disks list afterwards, just call the corresponding - /// // "refresh_disk_list": - /// system.refresh_disk_list(); + /// // "refresh_disks_list": + /// system.refresh_disks_list(); /// let disks = system.get_disks(); /// ``` fn new_with_specifics(refreshes: RefreshKind) -> Self; @@ -412,7 +412,7 @@ pub trait SystemExt: Sized { /// ``` /// use sysinfo::{RefreshKind, System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// /// // Let's just update networks and processes: /// s.refresh_specifics(RefreshKind::new().with_networks().with_processes()); @@ -428,7 +428,7 @@ pub trait SystemExt: Sized { self.refresh_temperatures(); } if refreshes.networks_list() { - self.refresh_network_interfaces(); + self.refresh_networks_list(); } if refreshes.networks() { self.refresh_networks(); @@ -436,8 +436,8 @@ pub trait SystemExt: Sized { if refreshes.processes() { self.refresh_processes(); } - if refreshes.disk_list() { - self.refresh_disk_list(); + if refreshes.disks_list() { + self.refresh_disks_list(); } if refreshes.disks() { self.refresh_disks(); @@ -456,7 +456,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_system(); /// ``` fn refresh_system(&mut self) { @@ -470,7 +470,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_memory(); /// ``` fn refresh_memory(&mut self); @@ -480,7 +480,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_cpu(); /// ``` fn refresh_cpu(&mut self); @@ -490,7 +490,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_temperatures(); /// ``` fn refresh_temperatures(&mut self); @@ -500,7 +500,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_processes(); /// ``` fn refresh_processes(&mut self); @@ -511,7 +511,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_process(1337); /// ``` fn refresh_process(&mut self, pid: Pid) -> bool; @@ -521,7 +521,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_disks(); /// ``` fn refresh_disks(&mut self); @@ -531,17 +531,17 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); - /// s.refresh_disk_list(); + /// let mut s = System::new_all(); + /// s.refresh_disks_list(); /// ``` - fn refresh_disk_list(&mut self); + fn refresh_disks_list(&mut self); /// Refresh networks data. /// /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_networks(); /// ``` /// @@ -550,7 +550,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{NetworksExt, System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// let networks = s.get_networks_mut(); /// networks.refresh(); /// ``` @@ -563,7 +563,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_network_interfaces(); /// ``` /// @@ -572,12 +572,12 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{NetworksExt, System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// let networks = s.get_networks_mut(); - /// networks.refresh_interfaces_list(); + /// networks.refresh_networks_list(); /// ``` - fn refresh_network_interfaces(&mut self) { - self.get_networks_mut().refresh_interfaces_list(); + fn refresh_networks_list(&mut self) { + self.get_networks_mut().refresh_networks_list(); } /// Refreshes all system, processes, disks and network interfaces information. @@ -588,7 +588,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// s.refresh_all(); /// ``` fn refresh_all(&mut self) { @@ -603,7 +603,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{ProcessExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// for (pid, process) in s.get_process_list() { /// println!("{} {}", pid, process.name()); /// } @@ -615,7 +615,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{ProcessExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// if let Some(process) = s.get_process(1337) { /// println!("{}", process.name()); /// } @@ -627,7 +627,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{ProcessExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// for process in s.get_process_by_name("htop") { /// println!("{} {}", process.pid(), process.name()); /// } @@ -647,7 +647,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{ProcessorExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// for processor in s.get_processor_list() { /// println!("{}%", processor.get_cpu_usage()); /// } @@ -659,7 +659,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// println!("{} KiB", s.get_total_memory()); /// ``` fn get_total_memory(&self) -> u64; @@ -669,7 +669,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// println!("{} KiB", s.get_free_memory()); /// ``` fn get_free_memory(&self) -> u64; @@ -679,7 +679,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// println!("{} KiB", s.get_used_memory()); /// ``` fn get_used_memory(&self) -> u64; @@ -689,7 +689,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// println!("{} KiB", s.get_total_swap()); /// ``` fn get_total_swap(&self) -> u64; @@ -699,7 +699,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// println!("{} KiB", s.get_free_swap()); /// ``` fn get_free_swap(&self) -> u64; @@ -709,7 +709,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// println!("{} KiB", s.get_used_swap()); /// ``` fn get_used_swap(&self) -> u64; @@ -719,7 +719,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{ComponentExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// for component in s.get_components_list() { /// println!("{}: {}°C", component.get_label(), component.get_temperature()); /// } @@ -731,7 +731,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{DiskExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// for disk in s.get_disks() { /// println!("{:?}", disk.get_name()); /// } @@ -743,7 +743,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// let networks = s.get_networks(); /// for (interface_name, data) in networks.iter() { /// println!("[{}] in: {}, out: {}", interface_name, data.get_income(), data.get_outcome()); @@ -756,7 +756,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// let networks = s.get_networks_mut(); /// networks.refresh_interfaces_list(); /// ``` @@ -767,7 +767,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// println!("{}", s.get_uptime()); /// ``` fn get_uptime(&self) -> u64; @@ -777,7 +777,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// let load_avg = s.get_load_average(); /// println!( /// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%", @@ -796,7 +796,7 @@ pub trait NetworkExt { /// ```no_run /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// let networks = s.get_networks(); /// for (interface_name, network) in networks.iter() { /// println!("in: {} B", network.get_income()); @@ -809,7 +809,7 @@ pub trait NetworkExt { /// ```no_run /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// let networks = s.get_networks(); /// for (interface_name, network) in networks.iter() { /// println!("in: {} B", network.get_outcome()); @@ -822,7 +822,7 @@ pub trait NetworkExt { /// ```no_run /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// let networks = s.get_networks(); /// for (interface_name, network) in networks.iter() { /// println!("in: {} B", network.get_total_income()); @@ -835,7 +835,7 @@ pub trait NetworkExt { /// ```no_run /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// let networks = s.get_networks(); /// for (interface_name, network) in networks.iter() { /// println!("in: {} B", network.get_total_outcome()); @@ -851,7 +851,7 @@ pub trait NetworksExt { /// ```no_run /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// let networks = s.get_networks(); /// for (interface_name, network) in networks.iter() { /// println!("in: {} B", network.get_income()); @@ -864,18 +864,18 @@ pub trait NetworksExt { /// ```no_run /// use sysinfo::{NetworksExt, System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// let networks = s.get_networks_mut(); - /// networks.refresh_interfaces_list(); + /// networks.refresh_networks_list(); /// ``` - fn refresh_interfaces_list(&mut self); + fn refresh_networks_list(&mut self); /// Refreshes the network interfaces' content. /// /// ```no_run /// use sysinfo::{NetworksExt, System, SystemExt}; /// - /// let mut s = System::new(); + /// let mut s = System::new_all(); /// let networks = s.get_networks_mut(); /// networks.refresh(); /// ``` @@ -889,7 +889,7 @@ pub trait ComponentExt { /// ```no_run /// use sysinfo::{ComponentExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// for component in s.get_components_list() { /// println!("{}°C", component.get_temperature()); /// } @@ -901,7 +901,7 @@ pub trait ComponentExt { /// ```no_run /// use sysinfo::{ComponentExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// for component in s.get_components_list() { /// println!("{}°C", component.get_max()); /// } @@ -913,7 +913,7 @@ pub trait ComponentExt { /// ```no_run /// use sysinfo::{ComponentExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// for component in s.get_components_list() { /// println!("{:?}°C", component.get_critical()); /// } @@ -925,7 +925,7 @@ pub trait ComponentExt { /// ```no_run /// use sysinfo::{ComponentExt, System, SystemExt}; /// - /// let s = System::new(); + /// let s = System::new_all(); /// for component in s.get_components_list() { /// println!("{}", component.get_label()); /// } diff --git a/src/unknown/system.rs b/src/unknown/system.rs index d321fdd01..42902d8bc 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -43,7 +43,7 @@ impl SystemExt for System { fn refresh_disks(&mut self) {} - fn refresh_disk_list(&mut self) {} + fn refresh_disks_list(&mut self) {} fn refresh_network(&mut self) {} diff --git a/src/windows/network.rs b/src/windows/network.rs index 470457741..c98197054 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -26,7 +26,7 @@ macro_rules! old_and_new { /// ```no_run /// use sysinfo::{NetworksExt, System, SystemExt}; /// -/// let s = System::new(); +/// let s = System::new_all(); /// let networks = s.get_networks(); /// ``` pub struct Networks { @@ -46,7 +46,7 @@ impl NetworksExt for Networks { NetworksIter::new(self.interfaces.iter()) } - fn refresh_interfaces_list(&mut self) { + fn refresh_networks_list(&mut self) { let mut table: PMIB_IF_TABLE2 = ::std::ptr::null_mut(); if unsafe { ffi::GetIfTable2(&mut table) } != NO_ERROR { return; diff --git a/src/windows/system.rs b/src/windows/system.rs index ef9db0827..1e46a4d34 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -288,7 +288,7 @@ impl SystemExt for System { }); } - fn refresh_disk_list(&mut self) { + fn refresh_disks_list(&mut self) { self.disks = unsafe { get_disks() }; } From d4d47f1c1035fc8ec99cc4fb8a6ec14f040ce251 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 4 Feb 2020 18:18:53 +0100 Subject: [PATCH 108/171] Update docs and benchmarks --- benches/basic.rs | 35 +++++++++++++++++++++++++++-------- src/common.rs | 2 +- src/system.rs | 7 ++++++- src/traits.rs | 10 +++++----- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/benches/basic.rs b/benches/basic.rs index a6f3833fd..5e6b63351 100644 --- a/benches/basic.rs +++ b/benches/basic.rs @@ -4,6 +4,7 @@ extern crate sysinfo; extern crate test; use sysinfo::SystemExt; +use sysinfo::get_current_pid; #[bench] fn bench_new(b: &mut test::Bencher) { @@ -12,9 +13,16 @@ fn bench_new(b: &mut test::Bencher) { }); } +#[bench] +fn bench_new_all(b: &mut test::Bencher) { + b.iter(|| { + sysinfo::System::new_all(); + }); +} + #[bench] fn bench_refresh_all(b: &mut test::Bencher) { - let mut s = sysinfo::System::new(); + let mut s = sysinfo::System::new_all(); b.iter(move || { s.refresh_all(); @@ -23,7 +31,7 @@ fn bench_refresh_all(b: &mut test::Bencher) { #[bench] fn bench_refresh_system(b: &mut test::Bencher) { - let mut s = sysinfo::System::new(); + let mut s = sysinfo::System::new_all(); s.refresh_system(); b.iter(move || { @@ -35,6 +43,7 @@ fn bench_refresh_system(b: &mut test::Bencher) { fn bench_refresh_processes(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); + s.refresh_processes(); // to load the whole processes list a first time. b.iter(move || { s.refresh_processes(); }); @@ -45,7 +54,8 @@ fn bench_refresh_process(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); s.refresh_all(); - let pid = *s.get_process_list().iter().take(1).next().unwrap().0; + // to be sure it'll exist for at least as long as we run + let pid = get_current_pid().expect("failed to get current pid"); b.iter(move || { s.refresh_process(pid); }); @@ -53,7 +63,7 @@ fn bench_refresh_process(b: &mut test::Bencher) { #[bench] fn bench_refresh_disks(b: &mut test::Bencher) { - let mut s = sysinfo::System::new(); + let mut s = sysinfo::System::new_all(); b.iter(move || { s.refresh_disks(); @@ -61,23 +71,32 @@ fn bench_refresh_disks(b: &mut test::Bencher) { } #[bench] -fn bench_refresh_disk_lists(b: &mut test::Bencher) { +fn bench_refresh_disks_lists(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); b.iter(move || { - s.refresh_disk_list(); + s.refresh_disks_list(); }); } #[bench] fn bench_refresh_networks(b: &mut test::Bencher) { - let mut s = sysinfo::System::new(); + let mut s = sysinfo::System::new_all(); b.iter(move || { s.refresh_networks(); }); } +#[bench] +fn bench_refresh_networks_list(b: &mut test::Bencher) { + let mut s = sysinfo::System::new(); + + b.iter(move || { + s.refresh_networks_list(); + }); +} + #[bench] fn bench_refresh_memory(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); @@ -98,7 +117,7 @@ fn bench_refresh_cpu(b: &mut test::Bencher) { #[bench] fn bench_refresh_temperatures(b: &mut test::Bencher) { - let mut s = sysinfo::System::new(); + let mut s = sysinfo::System::new_all(); b.iter(move || { s.refresh_temperatures(); diff --git a/src/common.rs b/src/common.rs index 3e857716b..a63736586 100644 --- a/src/common.rs +++ b/src/common.rs @@ -146,7 +146,7 @@ impl RefreshKind { pub fn new() -> RefreshKind { RefreshKind { networks: false, - networks_list: true, + networks_list: false, processes: false, disks: false, disks_list: false, diff --git a/src/system.rs b/src/system.rs index d5aac83f8..121f5ac63 100644 --- a/src/system.rs +++ b/src/system.rs @@ -25,7 +25,12 @@ mod tests { #[test] fn test_refresh_process() { let mut sys = System::new(); - assert!(sys.refresh_process(utils::get_current_pid().expect("failed to get current pid"))); + assert!(sys.get_process_list().is_empty(), "no process should be listed!"); + sys.refresh_processes(); + assert!( + sys.refresh_process(utils::get_current_pid().expect("failed to get current pid")), + "process not listed", + ); } #[test] diff --git a/src/traits.rs b/src/traits.rs index 48a4aa736..61b09bd36 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -356,8 +356,8 @@ pub trait ProcessorExt { /// Contains all the methods of the [`System`] type. pub trait SystemExt: Sized { - /// Creates a new [`System`] instance with only the processes list loaded. Use the - /// [`refresh_all`] method to update its internal information (or any of the `refresh_` method). + /// Creates a new [`System`] instance with nothing loaded. Use the [`refresh_all`] method to + /// update its internal information (or any of the `refresh_` method). /// /// [`refresh_all`]: #method.refresh_all /// @@ -506,7 +506,7 @@ pub trait SystemExt: Sized { fn refresh_processes(&mut self); /// Refresh *only* the process corresponding to `pid`. Returns `false` if the process doesn't - /// exist. + /// exist or isn't listed. /// /// ```no_run /// use sysinfo::{System, SystemExt}; @@ -564,7 +564,7 @@ pub trait SystemExt: Sized { /// use sysinfo::{System, SystemExt}; /// /// let mut s = System::new_all(); - /// s.refresh_network_interfaces(); + /// s.refresh_networks_list(); /// ``` /// /// This is a shortcut for: @@ -758,7 +758,7 @@ pub trait SystemExt: Sized { /// /// let mut s = System::new_all(); /// let networks = s.get_networks_mut(); - /// networks.refresh_interfaces_list(); + /// networks.refresh_networks_list(); /// ``` fn get_networks_mut(&mut self) -> &mut Networks; From 73dbc0e3d1ecf6a096b09fe9eb04b94c49fc5a4e Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Tue, 4 Feb 2020 18:25:33 +0100 Subject: [PATCH 109/171] Update benchmarks results for windows --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3368c3f35..98ece486a 100644 --- a/README.md +++ b/README.md @@ -113,17 +113,19 @@ test bench_refresh_temperatures ... bench: 25,770 ns/iter (+/- 1,164)
```text -test bench_new ... bench: 61,548,071 ns/iter (+/- 196,093,742) -test bench_refresh_all ... bench: 2,541,951 ns/iter (+/- 482,285) -test bench_refresh_cpu ... bench: 460 ns/iter (+/- 478) -test bench_refresh_disk_lists ... bench: 152,940 ns/iter (+/- 8,330) -test bench_refresh_disks ... bench: 55,597 ns/iter (+/- 9,629) -test bench_refresh_memory ... bench: 2,130 ns/iter (+/- 486) -test bench_refresh_network ... bench: 212 ns/iter (+/- 216) -test bench_refresh_process ... bench: 38 ns/iter (+/- 33) -test bench_refresh_processes ... bench: 2,175,034 ns/iter (+/- 315,585) -test bench_refresh_system ... bench: 2,508 ns/iter (+/- 224) -test bench_refresh_temperatures ... bench: 1 ns/iter (+/- 0) +test bench_new ... bench: 14,738,570 ns/iter (+/- 586,107) +test bench_new_all ... bench: 27,132,490 ns/iter (+/- 1,292,307) +test bench_refresh_all ... bench: 3,075,022 ns/iter (+/- 110,711) +test bench_refresh_cpu ... bench: 392 ns/iter (+/- 30) +test bench_refresh_disks ... bench: 41,778 ns/iter (+/- 954) +test bench_refresh_disks_lists ... bench: 113,942 ns/iter (+/- 4,240) +test bench_refresh_memory ... bench: 578 ns/iter (+/- 41) +test bench_refresh_networks ... bench: 38,178 ns/iter (+/- 3,718) +test bench_refresh_networks_list ... bench: 668,390 ns/iter (+/- 30,642) +test bench_refresh_process ... bench: 745 ns/iter (+/- 62) +test bench_refresh_processes ... bench: 1,179,581 ns/iter (+/- 188,119) +test bench_refresh_system ... bench: 1,230,542 ns/iter (+/- 64,231) +test bench_refresh_temperatures ... bench: 1,231,260 ns/iter (+/- 111,274) ```
From bb7388f9d6a8ca867305c1481fb2e2be7994c1e7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Feb 2020 19:58:01 +0100 Subject: [PATCH 110/171] Fix mac errors --- Cargo.toml | 2 +- src/mac/network.rs | 28 ++++++++++++++++++++-------- src/mac/system.rs | 2 +- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ee1183852..79a619271 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,11 @@ build = "build.rs" cfg-if = "0.1" rayon = "^1.0" doc-comment = "0.3" +once_cell = "1.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "handleapi", "ifdef", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase", "powerbase", "netioapi"] } ntapi = "0.3" -once_cell = "1.0" [target.'cfg(not(any(target_os = "unknown", target_arch = "wasm32")))'.dependencies] libc = "0.2" diff --git a/src/mac/network.rs b/src/mac/network.rs index 55dbe953d..55a45bece 100644 --- a/src/mac/network.rs +++ b/src/mac/network.rs @@ -32,15 +32,9 @@ impl Networks { interfaces: HashMap::new(), } } -} - -impl NetworksExt for Networks { - fn iter<'a>(&'a self) -> NetworksIter<'a> { - NetworksIter::new(self.interfaces.iter()) - } #[allow(clippy::cast_ptr_alignment)] - fn refresh_networks_list(&mut self) { + fn update_networks(&mut self) { let mib = &mut [CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0]; let mut len = 0; if unsafe { libc::sysctl(mib.as_mut_ptr(), 6, null_mut(), &mut len, null_mut(), 0) } < 0 { @@ -92,27 +86,45 @@ impl NetworksExt for Networks { current_in: ibytes, old_out: obytes, current_out: obytes, + updated: true, }); interface.old_in = interface.current_in; interface.current_in = ibytes; interface.old_out = interface.current_out; interface.current_out = obytes; + interface.updated = true; } } } } +} + +impl NetworksExt for Networks { + fn iter<'a>(&'a self) -> NetworksIter<'a> { + NetworksIter::new(self.interfaces.iter()) + } + + fn refresh_networks_list(&mut self) { + for (_, data) in self.interfaces.iter_mut() { + data.updated = false; + } + self.update_networks(); + self.interfaces.retain(|_, data| data.updated); + } fn refresh(&mut self) { - self.refresh_interfaces_list(); + self.update_networks(); } } /// Contains network information. +#[derive(PartialEq, Eq)] pub struct NetworkData { old_in: u64, old_out: u64, current_in: u64, current_out: u64, + updated: bool, } impl NetworkExt for NetworkData { diff --git a/src/mac/system.rs b/src/mac/system.rs index 6c02d70ad..1d8fe0265 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -11,7 +11,7 @@ use sys::network::Networks; use sys::process::*; use sys::processor::*; -use {DiskExt, LoadAvg, NetworksExt, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; +use {DiskExt, LoadAvg, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; use std::cell::UnsafeCell; use std::collections::HashMap; From ceae8b322e62aa900f0e68c00734f581812e36f3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Feb 2020 21:18:12 +0100 Subject: [PATCH 111/171] Update benchmark results for macos --- README.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 98ece486a..8da12424b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Support the following platforms: * Linux * Raspberry * Android - * Mac OSX + * macOS * Windows It also compiles for Android but never been tested on it. @@ -129,22 +129,24 @@ test bench_refresh_temperatures ... bench: 1,231,260 ns/iter (+/- 111,274) ``` -**OSX** +**macOS**
```text -test bench_new ... bench: 4,713,851 ns/iter (+/- 1,080,986) -test bench_refresh_all ... bench: 1,639,098 ns/iter (+/- 191,147) -test bench_refresh_cpu ... bench: 10,651 ns/iter (+/- 1,635) -test bench_refresh_disk_lists ... bench: 29,327 ns/iter (+/- 3,104) -test bench_refresh_disks ... bench: 942 ns/iter (+/- 79) -test bench_refresh_memory ... bench: 3,417 ns/iter (+/- 654) -test bench_refresh_network ... bench: 34,497 ns/iter (+/- 2,681) -test bench_refresh_process ... bench: 4,272 ns/iter (+/- 549) -test bench_refresh_processes ... bench: 782,977 ns/iter (+/- 30,958) -test bench_refresh_system ... bench: 336,008 ns/iter (+/- 43,015) -test bench_refresh_temperatures ... bench: 294,323 ns/iter (+/- 41,612) +test bench_new ... bench: 54,862 ns/iter (+/- 6,528) +test bench_new_all ... bench: 4,989,120 ns/iter (+/- 1,001,529) +test bench_refresh_all ... bench: 1,924,596 ns/iter (+/- 341,209) +test bench_refresh_cpu ... bench: 10,521 ns/iter (+/- 1,623) +test bench_refresh_disks ... bench: 945 ns/iter (+/- 95) +test bench_refresh_disks_lists ... bench: 29,315 ns/iter (+/- 3,076) +test bench_refresh_memory ... bench: 3,275 ns/iter (+/- 143) +test bench_refresh_networks ... bench: 200,670 ns/iter (+/- 28,674) +test bench_refresh_networks_list ... bench: 200,263 ns/iter (+/- 31,473) +test bench_refresh_process ... bench: 4,009 ns/iter (+/- 584) +test bench_refresh_processes ... bench: 790,834 ns/iter (+/- 61,236) +test bench_refresh_system ... bench: 335,144 ns/iter (+/- 35,713) +test bench_refresh_temperatures ... bench: 298,823 ns/iter (+/- 77,589) ```
From 0a639fd94bca23251dd34a049c5526f0aa2832f0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Feb 2020 22:19:33 +0100 Subject: [PATCH 112/171] Add missing parts for unknown targets --- src/unknown/mod.rs | 2 +- src/unknown/network.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/unknown/system.rs | 14 +++++++++----- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/unknown/mod.rs b/src/unknown/mod.rs index 9238248b9..bfb7215ff 100644 --- a/src/unknown/mod.rs +++ b/src/unknown/mod.rs @@ -13,7 +13,7 @@ pub mod system; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; -pub use self::network::NetworkData; +pub use self::network::{Networks, NetworkData}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; diff --git a/src/unknown/network.rs b/src/unknown/network.rs index b53e54ddd..ea3891df5 100644 --- a/src/unknown/network.rs +++ b/src/unknown/network.rs @@ -4,7 +4,41 @@ // Copyright (c) 2017 Guillaume Gomez // +use std::collections::HashMap; + use NetworkExt; +use NetworksExt; +use NetworksIter; + +/// Network interfaces. +/// +/// ```no_run +/// use sysinfo::{NetworksExt, System, SystemExt}; +/// +/// let s = System::new_all(); +/// let networks = s.get_networks(); +/// ``` +pub struct Networks { + interfaces: HashMap, +} + +impl Networks { + pub(crate) fn new() -> Networks { + Networks { + interfaces: HashMap::new(), + } + } +} + +impl NetworksExt for Networks { + fn iter<'a>(&'a self) -> NetworksIter<'a> { + NetworksIter::new(self.interfaces.iter()) + } + + fn refresh_networks_list(&mut self) {} + + fn refresh(&mut self) {} +} /// Contains network information. #[derive(Debug)] @@ -18,4 +52,12 @@ impl NetworkExt for NetworkData { fn get_outcome(&self) -> u64 { 0 } + + fn get_total_income(&self) -> u64 { + 0 + } + + fn get_total_outcome(&self) -> u64 { + 0 + } } diff --git a/src/unknown/system.rs b/src/unknown/system.rs index 42902d8bc..745e42af9 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -8,7 +8,7 @@ use sys::component::Component; use sys::process::*; use sys::processor::*; use sys::Disk; -use sys::NetworkData; +use sys::Networks; use Pid; use {RefreshKind, SystemExt}; @@ -18,14 +18,14 @@ use std::collections::HashMap; #[derive(Debug)] pub struct System { processes_list: HashMap, - network: NetworkData, + networks: Networks, } impl SystemExt for System { fn new_with_specifics(_: RefreshKind) -> System { System { processes_list: Default::default(), - network: NetworkData, + networks: Networks::new(), } } @@ -59,8 +59,12 @@ impl SystemExt for System { None } - fn get_network(&self) -> &NetworkData { - &self.network + fn get_networks(&self) -> &Networks { + &self.networks + } + + fn get_networks_mut(&mut self) -> &mut Networks { + &mut self.networks } fn get_processor_list(&self) -> &[Processor] { From 10213551e73610d6e6d73aa4b36a436479b65c36 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Feb 2020 22:19:41 +0100 Subject: [PATCH 113/171] small cleanup --- src/linux/system.rs | 2 +- src/windows/network.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/linux/system.rs b/src/linux/system.rs index 709506083..947b0a840 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -13,7 +13,7 @@ use Disk; use LoadAvg; use Networks; use Pid; -use {DiskExt, NetworksExt, ProcessExt, RefreshKind, SystemExt}; +use {DiskExt, ProcessExt, RefreshKind, SystemExt}; use libc::{self, gid_t, sysconf, uid_t, _SC_CLK_TCK, _SC_PAGESIZE}; use std::cell::UnsafeCell; diff --git a/src/windows/network.rs b/src/windows/network.rs index c98197054..a866d209a 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -130,7 +130,6 @@ impl NetworksExt for Networks { } fn refresh(&mut self) { - println!("refresh network!"); let mut entry: MIB_IF_ROW2 = unsafe { ::std::mem::MaybeUninit::uninit().assume_init() }; for (_, interface) in self.interfaces.iter_mut() { entry.InterfaceLuid = interface.id; From 1cc6b886ac9729c5530e71372a4d70836f2a5812 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Feb 2020 22:33:21 +0100 Subject: [PATCH 114/171] Implement IntoIterator on Networks --- src/common.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/common.rs b/src/common.rs index a63736586..5bdc9c3df 100644 --- a/src/common.rs +++ b/src/common.rs @@ -5,6 +5,8 @@ // use NetworkData; +use Networks; +use NetworksExt; /// Trait to have a common fallback for the `Pid` type. pub trait AsU32 { @@ -215,3 +217,12 @@ impl<'a> Iterator for NetworksIter<'a> { self.inner.next() } } + +impl<'a> IntoIterator for &'a Networks { + type Item = (&'a String, &'a NetworkData); + type IntoIter = NetworksIter<'a>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} From a9e2eb970c476f376db944e3b996c5a13554c36e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Feb 2020 22:33:58 +0100 Subject: [PATCH 115/171] Improve doc examples with removal of .iter() call --- src/traits.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 61b09bd36..24e7dd3c8 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -745,7 +745,7 @@ pub trait SystemExt: Sized { /// /// let s = System::new_all(); /// let networks = s.get_networks(); - /// for (interface_name, data) in networks.iter() { + /// for (interface_name, data) in networks { /// println!("[{}] in: {}, out: {}", interface_name, data.get_income(), data.get_outcome()); /// } /// ``` @@ -798,7 +798,7 @@ pub trait NetworkExt { /// /// let s = System::new_all(); /// let networks = s.get_networks(); - /// for (interface_name, network) in networks.iter() { + /// for (interface_name, network) in networks { /// println!("in: {} B", network.get_income()); /// } /// ``` @@ -811,7 +811,7 @@ pub trait NetworkExt { /// /// let s = System::new_all(); /// let networks = s.get_networks(); - /// for (interface_name, network) in networks.iter() { + /// for (interface_name, network) in networks { /// println!("in: {} B", network.get_outcome()); /// } /// ``` @@ -824,7 +824,7 @@ pub trait NetworkExt { /// /// let s = System::new_all(); /// let networks = s.get_networks(); - /// for (interface_name, network) in networks.iter() { + /// for (interface_name, network) in networks { /// println!("in: {} B", network.get_total_income()); /// } /// ``` @@ -837,7 +837,7 @@ pub trait NetworkExt { /// /// let s = System::new_all(); /// let networks = s.get_networks(); - /// for (interface_name, network) in networks.iter() { + /// for (interface_name, network) in networks { /// println!("in: {} B", network.get_total_outcome()); /// } /// ``` @@ -853,7 +853,7 @@ pub trait NetworksExt { /// /// let s = System::new_all(); /// let networks = s.get_networks(); - /// for (interface_name, network) in networks.iter() { + /// for (interface_name, network) in networks { /// println!("in: {} B", network.get_income()); /// } /// ``` From 9c6e411eb40338f8d1ed1301d3aaac0b69f445fe Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Feb 2020 22:34:14 +0100 Subject: [PATCH 116/171] Update linux benchmarks results --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8da12424b..7de8c5e8e 100644 --- a/README.md +++ b/README.md @@ -94,17 +94,19 @@ Here are the current results:
```text -test bench_new ... bench: 10,437,759 ns/iter (+/- 531,424) -test bench_refresh_all ... bench: 2,658,946 ns/iter (+/- 189,612) -test bench_refresh_cpu ... bench: 13,429 ns/iter (+/- 537) -test bench_refresh_disk_lists ... bench: 50,688 ns/iter (+/- 8,032) -test bench_refresh_disks ... bench: 2,582 ns/iter (+/- 226) -test bench_refresh_memory ... bench: 12,015 ns/iter (+/- 537) -test bench_refresh_network ... bench: 23,661 ns/iter (+/- 617) -test bench_refresh_process ... bench: 56,157 ns/iter (+/- 2,445) -test bench_refresh_processes ... bench: 2,486,534 ns/iter (+/- 121,187) -test bench_refresh_system ... bench: 53,739 ns/iter (+/- 6,793) -test bench_refresh_temperatures ... bench: 25,770 ns/iter (+/- 1,164) +test bench_new ... bench: 376,960 ns/iter (+/- 4,905) +test bench_new_all ... bench: 10,329,744 ns/iter (+/- 330,898) +test bench_refresh_all ... bench: 2,836,934 ns/iter (+/- 155,357) +test bench_refresh_cpu ... bench: 13,494 ns/iter (+/- 460) +test bench_refresh_disks ... bench: 2,542 ns/iter (+/- 37) +test bench_refresh_disks_lists ... bench: 50,740 ns/iter (+/- 1,252) +test bench_refresh_memory ... bench: 11,933 ns/iter (+/- 1,222) +test bench_refresh_networks ... bench: 293,706 ns/iter (+/- 36,558) +test bench_refresh_networks_list ... bench: 300,782 ns/iter (+/- 26,761) +test bench_refresh_process ... bench: 75,210 ns/iter (+/- 3,211) +test bench_refresh_processes ... bench: 2,210,766 ns/iter (+/- 172,166) +test bench_refresh_system ... bench: 51,037 ns/iter (+/- 2,083) +test bench_refresh_temperatures ... bench: 24,812 ns/iter (+/- 2,644) ```
From f91999f3d196698c5d60ec8e2985e74ef2fb662e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Feb 2020 22:37:14 +0100 Subject: [PATCH 117/171] Don't read network compressed packets on linux for the moment --- src/linux/network.rs | 60 ++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/linux/network.rs b/src/linux/network.rs index f08ebef0f..4068c7861 100644 --- a/src/linux/network.rs +++ b/src/linux/network.rs @@ -92,8 +92,8 @@ impl NetworksExt for Networks { let tx_packets = read(parent, "tx_packets", &mut data); let rx_errors = read(parent, "rx_errors", &mut data); let tx_errors = read(parent, "tx_errors", &mut data); - let rx_compressed = read(parent, "rx_compressed", &mut data); - let tx_compressed = read(parent, "tx_compressed", &mut data); + // let rx_compressed = read(parent, "rx_compressed", &mut data); + // let tx_compressed = read(parent, "tx_compressed", &mut data); let interface = self.interfaces.entry(entry).or_insert_with(|| NetworkData { rx_bytes, old_rx_bytes: rx_bytes, @@ -107,10 +107,10 @@ impl NetworksExt for Networks { old_rx_errors: rx_errors, tx_errors, old_tx_errors: tx_errors, - rx_compressed, - old_rx_compressed: rx_compressed, - tx_compressed, - old_tx_compressed: tx_compressed, + // rx_compressed, + // old_rx_compressed: rx_compressed, + // tx_compressed, + // old_tx_compressed: tx_compressed, }); old_and_new!(interface, rx_bytes, old_rx_bytes); old_and_new!(interface, tx_bytes, old_tx_bytes); @@ -118,8 +118,8 @@ impl NetworksExt for Networks { old_and_new!(interface, tx_packets, old_tx_packets); old_and_new!(interface, rx_errors, old_rx_errors); old_and_new!(interface, tx_errors, old_tx_errors); - old_and_new!(interface, rx_compressed, old_rx_compressed); - old_and_new!(interface, tx_compressed, old_tx_compressed); + // old_and_new!(interface, rx_compressed, old_rx_compressed); + // old_and_new!(interface, tx_compressed, old_tx_compressed); } } } @@ -149,16 +149,16 @@ pub struct NetworkData { /// similar to `rx_errors` tx_errors: usize, old_tx_errors: usize, - /// Indicates the number of compressed packets received by this - /// network device. This value might only be relevant for interfaces - /// that support packet compression (e.g: PPP). - rx_compressed: usize, - old_rx_compressed: usize, - /// Indicates the number of transmitted compressed packets. Note - /// this might only be relevant for devices that support - /// compression (e.g: PPP). - tx_compressed: usize, - old_tx_compressed: usize, + // /// Indicates the number of compressed packets received by this + // /// network device. This value might only be relevant for interfaces + // /// that support packet compression (e.g: PPP). + // rx_compressed: usize, + // old_rx_compressed: usize, + // /// Indicates the number of transmitted compressed packets. Note + // /// this might only be relevant for devices that support + // /// compression (e.g: PPP). + // tx_compressed: usize, + // old_tx_compressed: usize, } impl NetworkData { @@ -190,18 +190,18 @@ impl NetworkData { old_tx_errors, read(path, "tx_errors", data) ); - old_and_new!( - self, - rx_compressed, - old_rx_compressed, - read(path, "rx_compressed", data) - ); - old_and_new!( - self, - tx_compressed, - old_tx_compressed, - read(path, "tx_compressed", data) - ); + // old_and_new!( + // self, + // rx_compressed, + // old_rx_compressed, + // read(path, "rx_compressed", data) + // ); + // old_and_new!( + // self, + // tx_compressed, + // old_tx_compressed, + // read(path, "tx_compressed", data) + // ); } } From 83f86a72aed7b38d0970b717edf5eebb8c193cb5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Feb 2020 22:37:28 +0100 Subject: [PATCH 118/171] Update linux benchmarks --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 7de8c5e8e..1fd07ef92 100644 --- a/README.md +++ b/README.md @@ -94,19 +94,19 @@ Here are the current results:
```text -test bench_new ... bench: 376,960 ns/iter (+/- 4,905) -test bench_new_all ... bench: 10,329,744 ns/iter (+/- 330,898) -test bench_refresh_all ... bench: 2,836,934 ns/iter (+/- 155,357) -test bench_refresh_cpu ... bench: 13,494 ns/iter (+/- 460) -test bench_refresh_disks ... bench: 2,542 ns/iter (+/- 37) -test bench_refresh_disks_lists ... bench: 50,740 ns/iter (+/- 1,252) -test bench_refresh_memory ... bench: 11,933 ns/iter (+/- 1,222) -test bench_refresh_networks ... bench: 293,706 ns/iter (+/- 36,558) -test bench_refresh_networks_list ... bench: 300,782 ns/iter (+/- 26,761) -test bench_refresh_process ... bench: 75,210 ns/iter (+/- 3,211) -test bench_refresh_processes ... bench: 2,210,766 ns/iter (+/- 172,166) -test bench_refresh_system ... bench: 51,037 ns/iter (+/- 2,083) -test bench_refresh_temperatures ... bench: 24,812 ns/iter (+/- 2,644) +test bench_new ... bench: 375,774 ns/iter (+/- 7,119) +test bench_new_all ... bench: 10,308,642 ns/iter (+/- 422,803) +test bench_refresh_all ... bench: 2,824,911 ns/iter (+/- 169,153) +test bench_refresh_cpu ... bench: 13,630 ns/iter (+/- 702) +test bench_refresh_disks ... bench: 2,558 ns/iter (+/- 14) +test bench_refresh_disks_lists ... bench: 51,737 ns/iter (+/- 5,712) +test bench_refresh_memory ... bench: 12,006 ns/iter (+/- 277) +test bench_refresh_networks ... bench: 223,858 ns/iter (+/- 28,537) +test bench_refresh_networks_list ... bench: 232,934 ns/iter (+/- 34,344) +test bench_refresh_process ... bench: 78,925 ns/iter (+/- 12,421) +test bench_refresh_processes ... bench: 2,235,119 ns/iter (+/- 137,403) +test bench_refresh_system ... bench: 52,832 ns/iter (+/- 6,704) +test bench_refresh_temperatures ... bench: 25,079 ns/iter (+/- 2,258) ```
From cd68da3450c82cf39374d4e9b076a8821cbba255 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 10:27:04 +0100 Subject: [PATCH 119/171] Update C interface --- src/c_interface.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/c_interface.rs b/src/c_interface.rs index 4b9eef011..f7765cc23 100644 --- a/src/c_interface.rs +++ b/src/c_interface.rs @@ -131,14 +131,14 @@ pub extern "C" fn sysinfo_refresh_disks(system: CSystem) { Box::into_raw(system); } -/// Equivalent of `System::refresh_disk_list()`. +/// Equivalent of `System::refresh_disks_list()`. #[no_mangle] -pub extern "C" fn sysinfo_refresh_disk_list(system: CSystem) { +pub extern "C" fn sysinfo_refresh_disks_list(system: CSystem) { assert!(!system.is_null()); let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; { let system: &mut System = system.borrow_mut(); - system.refresh_disk_list(); + system.refresh_disks_list(); } Box::into_raw(system); } From 01eaae26760ef5c27827cc5f4102df0629fb9b0b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 13:36:42 +0100 Subject: [PATCH 120/171] Extend NetworkExt interface --- src/traits.rs | 118 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 7 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 24e7dd3c8..e8fccf481 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -804,7 +804,7 @@ pub trait NetworkExt { /// ``` fn get_income(&self) -> u64; - /// Returns the number of outgoing bytes since the last refresh. + /// Returns the total number of incoming bytes. /// /// ```no_run /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; @@ -812,12 +812,12 @@ pub trait NetworkExt { /// let s = System::new_all(); /// let networks = s.get_networks(); /// for (interface_name, network) in networks { - /// println!("in: {} B", network.get_outcome()); + /// println!("in: {} B", network.get_total_income()); /// } /// ``` - fn get_outcome(&self) -> u64; + fn get_total_income(&self) -> u64; - /// Returns the total number of incoming bytes. + /// Returns the number of outgoing bytes since the last refresh. /// /// ```no_run /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; @@ -825,10 +825,10 @@ pub trait NetworkExt { /// let s = System::new_all(); /// let networks = s.get_networks(); /// for (interface_name, network) in networks { - /// println!("in: {} B", network.get_total_income()); + /// println!("out: {} B", network.get_outcome()); /// } /// ``` - fn get_total_income(&self) -> u64; + fn get_outcome(&self) -> u64; /// Returns the total number of outgoing bytes. /// @@ -838,10 +838,114 @@ pub trait NetworkExt { /// let s = System::new_all(); /// let networks = s.get_networks(); /// for (interface_name, network) in networks { - /// println!("in: {} B", network.get_total_outcome()); + /// println!("out: {} B", network.get_total_outcome()); /// } /// ``` fn get_total_outcome(&self) -> u64; + + /// Returns the number of incoming packets since the last refresh. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new_all(); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks { + /// println!("in: {}", network.get_packets_income()); + /// } + /// ``` + fn get_packets_income(&self) -> u64; + + /// Returns the total number of incoming packets. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new_all(); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks { + /// println!("in: {}", network.get_total_packets_income()); + /// } + /// ``` + fn get_total_packets_income(&self) -> u64; + + /// Returns the number of outcoming packets since the last refresh. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new_all(); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks { + /// println!("out: {}", network.get_packets_outcome()); + /// } + /// ``` + fn get_packets_outcome(&self) -> u64; + + /// Returns the total number of outcoming packets. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new_all(); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks { + /// println!("out: {}", network.get_total_packets_outcome()); + /// } + /// ``` + fn get_total_packets_outcome(&self) -> u64; + + /// Returns the number of incoming errors since the last refresh. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new_all(); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks { + /// println!("in: {}", network.get_errors_income()); + /// } + /// ``` + fn get_errors_income(&self) -> u64; + + /// Returns the total number of incoming errors. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new_all(); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks { + /// println!("in: {}", network.get_total_errors_income()); + /// } + /// ``` + fn get_total_errors_income(&self) -> u64; + + /// Returns the number of outcoming errors since the last refresh. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new_all(); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks { + /// println!("out: {}", network.get_errors_outcome()); + /// } + /// ``` + fn get_errors_outcome(&self) -> u64; + + /// Returns the total number of outcoming errors. + /// + /// ```no_run + /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; + /// + /// let s = System::new_all(); + /// let networks = s.get_networks(); + /// for (interface_name, network) in networks { + /// println!("out: {}", network.get_total_errors_outcome()); + /// } + /// ``` + fn get_total_errors_outcome(&self) -> u64; } /// Interacting with network interfaces. From 331206dd1634160994997d6228235e76a8b7f5e5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 13:36:53 +0100 Subject: [PATCH 121/171] Extend mac network interface --- src/mac/network.rs | 87 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/src/mac/network.rs b/src/mac/network.rs index 55a45bece..d006a1a69 100644 --- a/src/mac/network.rs +++ b/src/mac/network.rs @@ -14,6 +14,13 @@ use NetworkExt; use NetworksExt; use NetworksIter; +macro_rules! old_and_new { + ($ty_:expr, $name:ident, $old:ident, $new_val:expr) => {{ + $ty_.$old = $ty_.$name; + $ty_.$name = $new_val; + }}; +} + /// Network interfaces. /// /// ```no_run @@ -79,19 +86,27 @@ impl Networks { } name.set_len(libc::strlen(pname)); let name = String::from_utf8_unchecked(name); - let ibytes = (*if2m).ifm_data.ifi_ibytes; - let obytes = (*if2m).ifm_data.ifi_obytes; let interface = self.interfaces.entry(name).or_insert_with(|| NetworkData { - old_in: ibytes, - current_in: ibytes, - old_out: obytes, - current_out: obytes, + current_in: (*if2m).ifm_data.ifi_ibytes, + old_in: 0, + current_out: (*if2m).ifm_data.ifi_obytes, + old_out: 0, + packets_in: (*if2m).ifm_data.ifi_ipackets, + old_packets_in: 0, + packets_out: (*if2m).ifm_data.ifi_opackets, + old_packets_out: 0, + errors_in: (*if2m).ifm_data.ifi_ierrors, + old_errors_in: 0, + errors_out: (*if2m).ifm_data.ifi_oerrors, + old_errors_out: 0, updated: true, }); - interface.old_in = interface.current_in; - interface.current_in = ibytes; - interface.old_out = interface.current_out; - interface.current_out = obytes; + old_and_new!(interface, current_out, old_out, (*if2m).ifm_data.ifi_obytes); + old_and_new!(interface, current_in, old_in, (*if2m).ifm_data.ifi_ibytes); + old_and_new!(interface, packets_in, old_packets_in, (*if2m).ifm_data.ifi_ipackets); + old_and_new!(interface, packets_out, old_packets_out, (*if2m).ifm_data.ifi_opackets); + old_and_new!(interface, errors_in, old_errors_in, (*if2m).ifm_data.ifi_ierrors); + old_and_new!(interface, errors_out, old_errors_out, (*if2m).ifm_data.ifi_oerrors); interface.updated = true; } } @@ -120,10 +135,18 @@ impl NetworksExt for Networks { /// Contains network information. #[derive(PartialEq, Eq)] pub struct NetworkData { - old_in: u64, - old_out: u64, current_in: u64, + old_in: u64, current_out: u64, + old_out: u64, + packets_in: u64, + old_packets_in: u64, + packets_out: u64, + old_packets_out: u64, + errors_in: u64, + old_errors_in: u64, + errors_out: u64, + old_errors_out: u64, updated: bool, } @@ -132,15 +155,47 @@ impl NetworkExt for NetworkData { self.current_in - self.old_in } - fn get_outcome(&self) -> u64 { - self.current_out - self.old_out - } - fn get_total_income(&self) -> u64 { self.current_in } + fn get_outcome(&self) -> u64 { + self.current_out - self.old_out + } + fn get_total_outcome(&self) -> u64 { self.current_out } + + fn get_packets_income(&self) -> u64 { + self.packets_in - self.old_packets_in + } + + fn get_total_packets_income(&self) -> u64 { + self.packets_in + } + + fn get_packets_outcome(&self) -> u64 { + self.packets_out - self.old_packets_out + } + + fn get_total_packets_outcome(&self) -> u64 { + self.packets_out + } + + fn get_errors_income(&self) -> u64 { + self.errors_in - self.old_errors_in + } + + fn get_total_errors_income(&self) -> u64 { + self.errors_in + } + + fn get_errors_outcome(&self) -> u64 { + self.errors_out - self.old_errors_out + } + + fn get_total_errors_outcome(&self) -> u64 { + self.errors_out + } } From 004db8c0eaf21eda96584d4f8ef7c1c6f2cfa42b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 13:40:38 +0100 Subject: [PATCH 122/171] Extend linux network interface --- src/linux/network.rs | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/linux/network.rs b/src/linux/network.rs index 4068c7861..9f7378fa0 100644 --- a/src/linux/network.rs +++ b/src/linux/network.rs @@ -210,15 +210,47 @@ impl NetworkExt for NetworkData { self.rx_bytes as u64 - self.old_rx_bytes as u64 } + fn get_total_income(&self) -> u64 { + self.rx_bytes as u64 + } + fn get_outcome(&self) -> u64 { self.tx_bytes as u64 - self.old_tx_bytes as u64 } - fn get_total_income(&self) -> u64 { + fn get_total_outcome(&self) -> u64 { self.rx_bytes as u64 } - fn get_total_outcome(&self) -> u64 { - self.rx_bytes as u64 + fn get_packets_income(&self) -> u64 { + self.rx_packets as u64 - self.old_rx_packets as u64 + } + + fn get_total_packets_income(&self) -> u64 { + self.rx_packets as u64 + } + + fn get_packets_outcome(&self) -> u64 { + self.tx_packets as u64 - self.old_tx_packets as u64 + } + + fn get_total_packets_outcome(&self) -> u64 { + self.tx_packets as u64 + } + + fn get_errors_income(&self) -> u64 { + self.rx_errors as u64 - self.old_rx_errors as u64 + } + + fn get_total_errors_income(&self) -> u64 { + self.rx_errors as u64 + } + + fn get_errors_outcome(&self) -> u64 { + self.tx_errors as u64 - self.old_tx_errors as u64 + } + + fn get_total_errors_outcome(&self) -> u64 { + self.tx_errors as u64 } } From a0cb41b6bda06fd7c3464d81b1004905ab2fae91 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 13:47:18 +0100 Subject: [PATCH 123/171] Extend windows network interface --- src/windows/network.rs | 68 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/src/windows/network.rs b/src/windows/network.rs index a866d209a..38a2112a7 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -114,12 +114,24 @@ impl NetworksExt for Networks { .or_insert_with(|| NetworkData { id: ptr.InterfaceLuid, current_out: ptr.OutOctets, - old_out: ptr.OutOctets, + old_out: 0, current_in: ptr.InOctets, - old_in: ptr.InOctets, + old_in: 0, + packets_in: ptr.InUcastPkts + ptr.InNUcastPkts, + old_packets_in: 0, + packets_out: ptr.OutUcastPkts + ptr.OutNUcastPkts, + old_packets_out: 0, + errors_in: ptr.InErrors, + old_errors_in: 0, + errors_out: ptr.OutErrors, + old_errors_out: 0, }); old_and_new!(interface, current_out, old_out, ptr.OutOctets); old_and_new!(interface, current_in, old_in, ptr.InOctets); + old_and_new!(interface, packets_in, old_packets_in, ptr.InUcastPkts + ptr.InNUcastPkts); + old_and_new!(interface, packets_out, old_packets_out, ptr.OutUcastPkts + ptr.OutNUcastPkts); + old_and_new!(interface, errors_in, old_errors_in, ptr.InErrors); + old_and_new!(interface, errors_out, old_errors_out, ptr.OutErrors); } unsafe { ffi::FreeMibTable(table as _); @@ -139,6 +151,10 @@ impl NetworksExt for Networks { } old_and_new!(interface, current_out, old_out, entry.OutOctets); old_and_new!(interface, current_in, old_in, entry.InOctets); + old_and_new!(interface, packets_in, old_packets_in, entry.InUcastPkts + entry.InNUcastPkts); + old_and_new!(interface, packets_out, old_packets_out, entry.OutUcastPkts + entry.OutNUcastPkts); + old_and_new!(interface, errors_in, old_errors_in, entry.InErrors); + old_and_new!(interface, errors_out, old_errors_out, entry.OutErrors); } } } @@ -150,6 +166,14 @@ pub struct NetworkData { old_out: u64, current_in: u64, old_in: u64, + packets_in: u64, + old_packets_in: u64, + packets_out: u64, + old_packets_out: u64, + errors_in: u64, + old_errors_in: u64, + errors_out: u64, + old_errors_out: u64, } impl NetworkExt for NetworkData { @@ -157,15 +181,47 @@ impl NetworkExt for NetworkData { self.current_in - self.old_in } - fn get_outcome(&self) -> u64 { - self.current_out - self.old_out - } - fn get_total_income(&self) -> u64 { self.current_in } + fn get_outcome(&self) -> u64 { + self.current_out - self.old_out + } + fn get_total_outcome(&self) -> u64 { self.current_out } + + fn get_packets_income(&self) -> u64 { + self.packets_in - self.old_packets_in + } + + fn get_total_packets_income(&self) -> u64 { + self.packets_in + } + + fn get_packets_outcome(&self) -> u64 { + self.packets_out - self.old_packets_out + } + + fn get_total_packets_outcome(&self) -> u64 { + self.packets_out + } + + fn get_errors_income(&self) -> u64 { + self.errors_in - self.old_errors_in + } + + fn get_total_errors_income(&self) -> u64 { + self.errors_in + } + + fn get_errors_outcome(&self) -> u64 { + self.errors_out - self.old_errors_out + } + + fn get_total_errors_outcome(&self) -> u64 { + self.errors_out + } } From ea66e311cccc6758feceb852dc220b59a416b6e9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 13:48:22 +0100 Subject: [PATCH 124/171] Extend unknown network interface --- src/unknown/network.rs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/unknown/network.rs b/src/unknown/network.rs index ea3891df5..7163f2c81 100644 --- a/src/unknown/network.rs +++ b/src/unknown/network.rs @@ -49,15 +49,47 @@ impl NetworkExt for NetworkData { 0 } - fn get_outcome(&self) -> u64 { + fn get_total_income(&self) -> u64 { 0 } - fn get_total_income(&self) -> u64 { + fn get_outcome(&self) -> u64 { 0 } fn get_total_outcome(&self) -> u64 { 0 } + + fn get_packets_income(&self) -> u64 { + 0 + } + + fn get_total_packets_income(&self) -> u64 { + 0 + } + + fn get_packets_outcome(&self) -> u64 { + 0 + } + + fn get_total_packets_outcome(&self) -> u64 { + 0 + } + + fn get_errors_income(&self) -> u64 { + 0 + } + + fn get_total_errors_income(&self) -> u64 { + 0 + } + + fn get_errors_outcome(&self) -> u64 { + 0 + } + + fn get_total_errors_outcome(&self) -> u64 { + 0 + } } From a96b020f15d36de3eca5dca4b8fc7553fe1cc38d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 13:48:29 +0100 Subject: [PATCH 125/171] fmt --- benches/basic.rs | 2 +- src/mac/network.rs | 28 ++++++++++++++++++++++++---- src/system.rs | 5 ++++- src/unknown/mod.rs | 2 +- src/windows/network.rs | 28 ++++++++++++++++++++++++---- 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/benches/basic.rs b/benches/basic.rs index 5e6b63351..2d8b8791d 100644 --- a/benches/basic.rs +++ b/benches/basic.rs @@ -3,8 +3,8 @@ extern crate sysinfo; extern crate test; -use sysinfo::SystemExt; use sysinfo::get_current_pid; +use sysinfo::SystemExt; #[bench] fn bench_new(b: &mut test::Bencher) { diff --git a/src/mac/network.rs b/src/mac/network.rs index d006a1a69..b34c49d30 100644 --- a/src/mac/network.rs +++ b/src/mac/network.rs @@ -103,10 +103,30 @@ impl Networks { }); old_and_new!(interface, current_out, old_out, (*if2m).ifm_data.ifi_obytes); old_and_new!(interface, current_in, old_in, (*if2m).ifm_data.ifi_ibytes); - old_and_new!(interface, packets_in, old_packets_in, (*if2m).ifm_data.ifi_ipackets); - old_and_new!(interface, packets_out, old_packets_out, (*if2m).ifm_data.ifi_opackets); - old_and_new!(interface, errors_in, old_errors_in, (*if2m).ifm_data.ifi_ierrors); - old_and_new!(interface, errors_out, old_errors_out, (*if2m).ifm_data.ifi_oerrors); + old_and_new!( + interface, + packets_in, + old_packets_in, + (*if2m).ifm_data.ifi_ipackets + ); + old_and_new!( + interface, + packets_out, + old_packets_out, + (*if2m).ifm_data.ifi_opackets + ); + old_and_new!( + interface, + errors_in, + old_errors_in, + (*if2m).ifm_data.ifi_ierrors + ); + old_and_new!( + interface, + errors_out, + old_errors_out, + (*if2m).ifm_data.ifi_oerrors + ); interface.updated = true; } } diff --git a/src/system.rs b/src/system.rs index 121f5ac63..dd848ed27 100644 --- a/src/system.rs +++ b/src/system.rs @@ -25,7 +25,10 @@ mod tests { #[test] fn test_refresh_process() { let mut sys = System::new(); - assert!(sys.get_process_list().is_empty(), "no process should be listed!"); + assert!( + sys.get_process_list().is_empty(), + "no process should be listed!" + ); sys.refresh_processes(); assert!( sys.refresh_process(utils::get_current_pid().expect("failed to get current pid")), diff --git a/src/unknown/mod.rs b/src/unknown/mod.rs index bfb7215ff..ea2b88c65 100644 --- a/src/unknown/mod.rs +++ b/src/unknown/mod.rs @@ -13,7 +13,7 @@ pub mod system; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; -pub use self::network::{Networks, NetworkData}; +pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; diff --git a/src/windows/network.rs b/src/windows/network.rs index 38a2112a7..a9766a7cc 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -128,8 +128,18 @@ impl NetworksExt for Networks { }); old_and_new!(interface, current_out, old_out, ptr.OutOctets); old_and_new!(interface, current_in, old_in, ptr.InOctets); - old_and_new!(interface, packets_in, old_packets_in, ptr.InUcastPkts + ptr.InNUcastPkts); - old_and_new!(interface, packets_out, old_packets_out, ptr.OutUcastPkts + ptr.OutNUcastPkts); + old_and_new!( + interface, + packets_in, + old_packets_in, + ptr.InUcastPkts + ptr.InNUcastPkts + ); + old_and_new!( + interface, + packets_out, + old_packets_out, + ptr.OutUcastPkts + ptr.OutNUcastPkts + ); old_and_new!(interface, errors_in, old_errors_in, ptr.InErrors); old_and_new!(interface, errors_out, old_errors_out, ptr.OutErrors); } @@ -151,8 +161,18 @@ impl NetworksExt for Networks { } old_and_new!(interface, current_out, old_out, entry.OutOctets); old_and_new!(interface, current_in, old_in, entry.InOctets); - old_and_new!(interface, packets_in, old_packets_in, entry.InUcastPkts + entry.InNUcastPkts); - old_and_new!(interface, packets_out, old_packets_out, entry.OutUcastPkts + entry.OutNUcastPkts); + old_and_new!( + interface, + packets_in, + old_packets_in, + entry.InUcastPkts + entry.InNUcastPkts + ); + old_and_new!( + interface, + packets_out, + old_packets_out, + entry.OutUcastPkts + entry.OutNUcastPkts + ); old_and_new!(interface, errors_in, old_errors_in, entry.InErrors); old_and_new!(interface, errors_out, old_errors_out, entry.OutErrors); } From b7ec800a1570f5384c7cbbae953816237611bc51 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 16:39:16 +0100 Subject: [PATCH 126/171] Clippy fixes --- .travis.yml | 2 +- src/linux/component.rs | 6 +++--- src/linux/processor.rs | 4 ++-- src/linux/system.rs | 6 +++--- src/sysinfo.rs | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 851ba077c..30f911216 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,7 +55,7 @@ script: - rustc --version - sysctl -a | grep mem - if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then - (rustup component add clippy-preview && cargo clippy) || touch clippy_install_failed; + (rustup component add clippy && cargo clippy) || touch clippy_install_failed; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cargo build --features debug; diff --git a/src/linux/component.rs b/src/linux/component.rs index ce2b51701..8264ab478 100644 --- a/src/linux/component.rs +++ b/src/linux/component.rs @@ -71,7 +71,7 @@ fn append_files(components: &mut Vec, folder: &Path) { parts .next() .map(|s| format!("_{}", s)) - .unwrap_or_else(|| String::new()), + .unwrap_or_else(String::new), ); } } @@ -93,14 +93,14 @@ fn append_files(components: &mut Vec, folder: &Path) { _ => {} } } - if found_label.is_some() && found_input.is_some() { + if let (Some(_), Some(found_input)) = (found_label, found_input) { let mut p_label = folder.to_path_buf(); let mut p_input = folder.to_path_buf(); let mut p_crit = folder.to_path_buf(); let mut p_max = folder.to_path_buf(); p_label.push(&format!("temp{}_label", key)); - p_input.push(&format!("temp{}{}", key, val[found_input.unwrap()])); + p_input.push(&format!("temp{}{}", key, val[found_input])); p_max.push(&format!("temp{}_max", key)); p_crit.push(&format!("temp{}_crit", key)); if is_file(&p_input) { diff --git a/src/linux/processor.rs b/src/linux/processor.rs index 0ba11b81c..83048ca24 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -230,7 +230,7 @@ pub fn get_raw_times(p: &Processor) -> (u64, u64) { pub fn get_cpu_frequency() -> u64 { // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq let mut s = String::new(); - if let Err(_) = File::open("/proc/cpuinfo").and_then(|mut f| f.read_to_string(&mut s)) { + if File::open("/proc/cpuinfo").and_then(|mut f| f.read_to_string(&mut s)).is_err() { return 0; } @@ -251,7 +251,7 @@ pub fn get_cpu_frequency() -> u64 { /// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). pub fn get_vendor_id_and_brand() -> (String, String) { let mut s = String::new(); - if let Err(_) = File::open("/proc/cpuinfo").and_then(|mut f| f.read_to_string(&mut s)) { + if File::open("/proc/cpuinfo").and_then(|mut f| f.read_to_string(&mut s)).is_err() { return (String::new(), String::new()); } diff --git a/src/linux/system.rs b/src/linux/system.rs index 947b0a840..2933c56f6 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -377,7 +377,7 @@ impl SystemExt for System { fn get_load_average(&self) -> LoadAvg { let mut s = String::new(); - if let Err(_) = File::open("/proc/loadavg").and_then(|mut f| f.read_to_string(&mut s)) { + if File::open("/proc/loadavg").and_then(|mut f| f.read_to_string(&mut s)).is_err() { return LoadAvg::default(); } let loads = s @@ -599,7 +599,7 @@ fn check_nb_open_files(f: File) -> Option { } } // Something bad happened... - return None; + None } fn _get_process_data( @@ -826,6 +826,6 @@ fn get_uptime() -> u64 { fn get_secs_since_epoch() -> u64 { match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { Ok(n) => n.as_secs(), - Err(_) => panic!("SystemTime before UNIX EPOCH!"), + _ => panic!("SystemTime before UNIX EPOCH!"), } } diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 7945492fc..7e88f6915 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -121,7 +121,7 @@ pub fn set_open_files_limit(mut _new_limit: isize) -> bool { if _new_limit > max { _new_limit = max; } - return if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } { + if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } { // If files are already open, to be sure that the number won't be bigger when those // files are closed, we subtract the current number of opened files to the new limit. let diff = max - **x; @@ -129,11 +129,11 @@ pub fn set_open_files_limit(mut _new_limit: isize) -> bool { true } else { false - }; + } } #[cfg(any(not(unix), target_os = "macos"))] { - return false; + false } } From 144db8227b799daf8894c5959a7f64faead6869f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 23:26:32 +0100 Subject: [PATCH 127/171] clippy fixes on mac --- src/mac/disk.rs | 2 +- src/mac/processor.rs | 3 +-- src/mac/system.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mac/disk.rs b/src/mac/disk.rs index 00ba4c7d6..7e99b7f9c 100644 --- a/src/mac/disk.rs +++ b/src/mac/disk.rs @@ -114,7 +114,7 @@ macro_rules! unwrapper { } static DISK_TYPES: once_cell::sync::Lazy> = - once_cell::sync::Lazy::new(|| get_disk_types()); + once_cell::sync::Lazy::new(get_disk_types); fn get_disk_types() -> HashMap { let mut master_port: ffi::mach_port_t = 0; diff --git a/src/mac/processor.rs b/src/mac/processor.rs index 581f6ead4..78db8d08e 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -127,8 +127,7 @@ pub fn get_cpu_frequency() -> u64 { 0, ); } - speed /= 1000000; - speed + speed / 1_000_000 } fn get_sysctl_str(s: &[u8]) -> String { diff --git a/src/mac/system.rs b/src/mac/system.rs index 1d8fe0265..5695d9e43 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -158,7 +158,7 @@ impl SystemExt for System { ); for (id, v) in crate::mac::component::COMPONENTS_TEMPERATURE_IDS.iter() { - if let Some(c) = Component::new(id.to_string(), None, critical_temp, v, con) { + if let Some(c) = Component::new((*id).to_owned(), None, critical_temp, v, con) { self.temperatures.push(c); } } From 8acf8b35bf7dd3a19e2463f942a3c4557fc917fc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Feb 2020 23:28:52 +0100 Subject: [PATCH 128/171] Add clippy check on windows --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index de8d07e9a..c0b717e7d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,10 +11,12 @@ install: - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host "%ARCH%-pc-windows-gnu" --default-toolchain %RUST% -y - SET PATH=C:\Users\appveyor\.cargo\bin;C:\msys64\mingw%BITS%\bin;%PATH%;C:\msys64\usr\bin + - rustup component add clippy - rustc -Vv - cargo -Vv build_script: + - cargo clippy - cargo build - cargo test - cd examples From 7cdbef5b33681e7289e746a61d5f2105ec512eb3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 00:24:27 +0100 Subject: [PATCH 129/171] Fix clippy errors on windows --- src/windows/network.rs | 5 ++--- src/windows/process.rs | 2 +- src/windows/processor.rs | 6 +++--- src/windows/system.rs | 1 + 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/windows/network.rs b/src/windows/network.rs index a9766a7cc..574c0bb90 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -65,9 +65,8 @@ impl NetworksExt for Networks { let ptr = unsafe { (*table).Table.as_ptr() }; for i in 0..unsafe { *table }.NumEntries { let ptr = unsafe { &*ptr.offset(i as _) }; - if ptr.TransmitLinkSpeed == 0 && ptr.ReceiveLinkSpeed == 0 { - continue; - } else if ptr.MediaConnectState == ffi::MediaConnectStateDisconnected + if (ptr.TransmitLinkSpeed == 0 && ptr.ReceiveLinkSpeed == 0) + || ptr.MediaConnectState == ffi::MediaConnectStateDisconnected || ptr.PhysicalAddressLength == 0 { continue; diff --git a/src/windows/process.rs b/src/windows/process.rs index fbb0b02ab..f60bbb9c3 100644 --- a/src/windows/process.rs +++ b/src/windows/process.rs @@ -364,7 +364,7 @@ impl Debug for Process { writeln!(f, "name: {}", self.name); writeln!(f, "environment:"); for var in self.environ.iter() { - if var.len() > 0 { + if !var.is_empty() { writeln!(f, "\t{}", var); } } diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 01329be52..42d175849 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -114,10 +114,10 @@ unsafe fn init_load_avg() -> Mutex> { { PdhRemoveCounter(counter); PdhCloseQuery(query); - return Mutex::new(None); + Mutex::new(None) + } else { + Mutex::new(Some(LoadAvg::default())) } - - return Mutex::new(Some(LoadAvg::default())); } #[derive(Debug)] diff --git a/src/windows/system.rs b/src/windows/system.rs index 1e46a4d34..f6a76966c 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -180,6 +180,7 @@ impl SystemExt for System { } } + #[allow(clippy::cast_ptr_alignment)] fn refresh_processes(&mut self) { // Windows 10 notebook requires at least 512KiB of memory to make it in one go let mut buffer_size: usize = 512 * 1024; From 63460de296e79a96aeadb1a7d930c59d5331820d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 00:24:31 +0100 Subject: [PATCH 130/171] fmt --- src/linux/processor.rs | 10 ++++++++-- src/linux/system.rs | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/linux/processor.rs b/src/linux/processor.rs index 83048ca24..8e79ba8c2 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -230,7 +230,10 @@ pub fn get_raw_times(p: &Processor) -> (u64, u64) { pub fn get_cpu_frequency() -> u64 { // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq let mut s = String::new(); - if File::open("/proc/cpuinfo").and_then(|mut f| f.read_to_string(&mut s)).is_err() { + if File::open("/proc/cpuinfo") + .and_then(|mut f| f.read_to_string(&mut s)) + .is_err() + { return 0; } @@ -251,7 +254,10 @@ pub fn get_cpu_frequency() -> u64 { /// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). pub fn get_vendor_id_and_brand() -> (String, String) { let mut s = String::new(); - if File::open("/proc/cpuinfo").and_then(|mut f| f.read_to_string(&mut s)).is_err() { + if File::open("/proc/cpuinfo") + .and_then(|mut f| f.read_to_string(&mut s)) + .is_err() + { return (String::new(), String::new()); } diff --git a/src/linux/system.rs b/src/linux/system.rs index 2933c56f6..3f2fc86d0 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -377,7 +377,10 @@ impl SystemExt for System { fn get_load_average(&self) -> LoadAvg { let mut s = String::new(); - if File::open("/proc/loadavg").and_then(|mut f| f.read_to_string(&mut s)).is_err() { + if File::open("/proc/loadavg") + .and_then(|mut f| f.read_to_string(&mut s)) + .is_err() + { return LoadAvg::default(); } let loads = s From 06eba865dff1851214cb2d887c4e8ec0f2f339a6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 18:24:00 +0100 Subject: [PATCH 131/171] Add missing links inside documentation --- src/c_interface.rs | 64 +++++++++++++++++++++--------------------- src/common.rs | 6 ++-- src/linux/component.rs | 2 +- src/linux/disk.rs | 2 +- src/sysinfo.rs | 2 +- src/traits.rs | 15 ++++++---- 6 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/c_interface.rs b/src/c_interface.rs index f7765cc23..f6a254e03 100644 --- a/src/c_interface.rs +++ b/src/c_interface.rs @@ -9,16 +9,16 @@ use std::borrow::BorrowMut; use std::ffi::CString; use {NetworkExt, NetworksExt, Process, ProcessExt, ProcessorExt, System, SystemExt}; -/// Equivalent of `System` struct. +/// Equivalent of [`System`][crate::System] struct. pub type CSystem = *mut c_void; -/// Equivalent of `Process` struct. +/// Equivalent of [`Process`][crate::Process] struct. pub type CProcess = *const c_void; /// C string returned from `CString::into_raw`. pub type RString = *const c_char; -/// Callback used by `get_process_list`. +/// Callback used by [`get_process_list`][crate::System#method.get_process_list]. pub type ProcessLoop = extern "C" fn(pid: pid_t, process: CProcess, data: *mut c_void) -> bool; -/// Equivalent of `System::new()`. +/// Equivalent of [`System::new()`][crate::System#method.new]. #[no_mangle] pub extern "C" fn sysinfo_init() -> CSystem { let system = Box::new(System::new()); @@ -34,7 +34,7 @@ pub extern "C" fn sysinfo_destroy(system: CSystem) { } } -/// Equivalent of `System::refresh_system()`. +/// Equivalent of [`System::refresh_system()`][crate::System#method.refresh_system]. #[no_mangle] pub extern "C" fn sysinfo_refresh_system(system: CSystem) { assert!(!system.is_null()); @@ -46,7 +46,7 @@ pub extern "C" fn sysinfo_refresh_system(system: CSystem) { Box::into_raw(system); } -/// Equivalent of `System::refresh_memory()`. +/// Equivalent of [`System::refresh_memory()`][crate::System#method.refresh_memory]. #[no_mangle] pub extern "C" fn sysinfo_refresh_memory(system: CSystem) { assert!(!system.is_null()); @@ -58,7 +58,7 @@ pub extern "C" fn sysinfo_refresh_memory(system: CSystem) { Box::into_raw(system); } -/// Equivalent of `System::refresh_cpu()`. +/// Equivalent of [`System::refresh_cpu()`][crate::System#method.refresh_cpu]. #[no_mangle] pub extern "C" fn sysinfo_refresh_cpu(system: CSystem) { assert!(!system.is_null()); @@ -70,7 +70,7 @@ pub extern "C" fn sysinfo_refresh_cpu(system: CSystem) { Box::into_raw(system); } -/// Equivalent of `System::refresh_cpu()`. +/// Equivalent of [`System::refresh_temperatures()`][crate::System#method.refresh_temperatures]. #[no_mangle] pub extern "C" fn sysinfo_refresh_temperatures(system: CSystem) { assert!(!system.is_null()); @@ -82,7 +82,7 @@ pub extern "C" fn sysinfo_refresh_temperatures(system: CSystem) { Box::into_raw(system); } -/// Equivalent of `System::refresh_all()`. +/// Equivalent of [`System::refresh_all()`][crate::System#method.refresh_all]. #[no_mangle] pub extern "C" fn sysinfo_refresh_all(system: CSystem) { assert!(!system.is_null()); @@ -94,7 +94,7 @@ pub extern "C" fn sysinfo_refresh_all(system: CSystem) { Box::into_raw(system); } -/// Equivalent of `System::refresh_processes()`. +/// Equivalent of [`System::refresh_processes()`][crate::System#method.refresh_processes]. #[no_mangle] pub extern "C" fn sysinfo_refresh_processes(system: CSystem) { assert!(!system.is_null()); @@ -106,7 +106,7 @@ pub extern "C" fn sysinfo_refresh_processes(system: CSystem) { Box::into_raw(system); } -/// Equivalent of `System::refresh_process()`. +/// Equivalent of [`System::refresh_process()`][crate::System#method.refresh_process]. #[cfg(target_os = "linux")] #[no_mangle] pub extern "C" fn sysinfo_refresh_process(system: CSystem, pid: pid_t) { @@ -119,7 +119,7 @@ pub extern "C" fn sysinfo_refresh_process(system: CSystem, pid: pid_t) { Box::into_raw(system); } -/// Equivalent of `System::refresh_disks()`. +/// Equivalent of [`System::refresh_disks()`][crate::System#method.refresh_disks]. #[no_mangle] pub extern "C" fn sysinfo_refresh_disks(system: CSystem) { assert!(!system.is_null()); @@ -131,7 +131,7 @@ pub extern "C" fn sysinfo_refresh_disks(system: CSystem) { Box::into_raw(system); } -/// Equivalent of `System::refresh_disks_list()`. +/// Equivalent of [`System::refresh_disks_list()`][crate::System#method.refresh_disks_list]. #[no_mangle] pub extern "C" fn sysinfo_refresh_disks_list(system: CSystem) { assert!(!system.is_null()); @@ -143,7 +143,7 @@ pub extern "C" fn sysinfo_refresh_disks_list(system: CSystem) { Box::into_raw(system); } -/// Equivalent of `System::get_total_memory()`. +/// Equivalent of [`System::get_total_memory()`][crate::System#method.get_total_memory]. #[no_mangle] pub extern "C" fn sysinfo_get_total_memory(system: CSystem) -> size_t { assert!(!system.is_null()); @@ -153,7 +153,7 @@ pub extern "C" fn sysinfo_get_total_memory(system: CSystem) -> size_t { ret } -/// Equivalent of `System::get_free_memory()`. +/// Equivalent of [`System::get_free_memory()`][crate::System#method.get_free_memory]. #[no_mangle] pub extern "C" fn sysinfo_get_free_memory(system: CSystem) -> size_t { assert!(!system.is_null()); @@ -163,7 +163,7 @@ pub extern "C" fn sysinfo_get_free_memory(system: CSystem) -> size_t { ret } -/// Equivalent of `System::get_used_memory()`. +/// Equivalent of [`System::get_used_memory()`][crate::System#method.get_used_memory]. #[no_mangle] pub extern "C" fn sysinfo_get_used_memory(system: CSystem) -> size_t { assert!(!system.is_null()); @@ -173,7 +173,7 @@ pub extern "C" fn sysinfo_get_used_memory(system: CSystem) -> size_t { ret } -/// Equivalent of `System::get_total_swap()`. +/// Equivalent of [`System::get_total_swap()`][crate::System#method.get_total_swap]. #[no_mangle] pub extern "C" fn sysinfo_get_total_swap(system: CSystem) -> size_t { assert!(!system.is_null()); @@ -183,7 +183,7 @@ pub extern "C" fn sysinfo_get_total_swap(system: CSystem) -> size_t { ret } -/// Equivalent of `System::get_free_swap()`. +/// Equivalent of [`System::get_free_swap()`][crate::System#method.get_free_swap]. #[no_mangle] pub extern "C" fn sysinfo_get_free_swap(system: CSystem) -> size_t { assert!(!system.is_null()); @@ -193,7 +193,7 @@ pub extern "C" fn sysinfo_get_free_swap(system: CSystem) -> size_t { ret } -/// Equivalent of `System::get_used_swap()`. +/// Equivalent of [`System::get_used_swap()`][crate::System#method.get_used_swap]. #[no_mangle] pub extern "C" fn sysinfo_get_used_swap(system: CSystem) -> size_t { assert!(!system.is_null()); @@ -231,7 +231,7 @@ pub extern "C" fn sysinfo_get_networks_outcome(system: CSystem) -> size_t { ret } -/// Equivalent of `System::get_processors_usage()`. +/// Equivalent of [`System::get_processors_usage()`][crate::System#method.get_processors_usage]. /// /// * `length` will contain the number of cpu usage added into `procs`. /// * `procs` will be allocated if it's null and will contain of cpu usage. @@ -262,8 +262,8 @@ pub extern "C" fn sysinfo_get_processors_usage( Box::into_raw(system); } -/// Equivalent of `System::get_process_list()`. Returns an array ended by a null pointer. Must -/// be freed. +/// Equivalent of [`System::get_process_list()`][crate::System#method.get_process_list]. Returns an +/// array ended by a null pointer. Must be freed. /// /// # /!\ WARNING /!\ /// @@ -293,7 +293,7 @@ pub extern "C" fn sysinfo_get_processes( } } -/// Equivalent of `System::get_process()`. +/// Equivalent of [`System::get_process()`][crate::System#method.get_process]. /// /// # /!\ WARNING /!\ /// @@ -312,7 +312,7 @@ pub extern "C" fn sysinfo_get_process_by_pid(system: CSystem, pid: pid_t) -> CPr ret } -/// Equivalent of iterating over `Process::tasks()`. +/// Equivalent of iterating over [`Process::tasks()`][crate::Process#method.tasks]. /// /// # /!\ WARNING /!\ /// @@ -338,7 +338,7 @@ pub extern "C" fn sysinfo_process_get_tasks( } } -/// Equivalent of `Process::pid()`. +/// Equivalent of [`Process::pid()`][crate::Process#method.pid]. #[no_mangle] pub extern "C" fn sysinfo_process_get_pid(process: CProcess) -> pid_t { assert!(!process.is_null()); @@ -346,7 +346,7 @@ pub extern "C" fn sysinfo_process_get_pid(process: CProcess) -> pid_t { unsafe { (*process).pid() } } -/// Equivalent of `Process::parent()`. +/// Equivalent of [`Process::parent()`][crate::Process#method.parent]. /// /// In case there is no known parent, it returns `0`. #[no_mangle] @@ -356,7 +356,7 @@ pub extern "C" fn sysinfo_process_get_parent_pid(process: CProcess) -> pid_t { unsafe { (*process).parent().unwrap_or_else(|| 0) } } -/// Equivalent of `Process::cpu_usage()`. +/// Equivalent of [`Process::cpu_usage()`][crate::Process#method.cpu_usage]. #[no_mangle] pub extern "C" fn sysinfo_process_get_cpu_usage(process: CProcess) -> c_float { assert!(!process.is_null()); @@ -364,7 +364,7 @@ pub extern "C" fn sysinfo_process_get_cpu_usage(process: CProcess) -> c_float { unsafe { (*process).cpu_usage() } } -/// Equivalent of `Process::memory()`. +/// Equivalent of [`Process::memory()`][crate::Process#method.memory]. #[no_mangle] pub extern "C" fn sysinfo_process_get_memory(process: CProcess) -> size_t { assert!(!process.is_null()); @@ -372,7 +372,7 @@ pub extern "C" fn sysinfo_process_get_memory(process: CProcess) -> size_t { unsafe { (*process).memory() as usize } } -/// Equivalent of `Process::virtual_memory()`. +/// Equivalent of [`Process::virtual_memory()`][crate::Process#method.virtual_memory]. #[no_mangle] pub extern "C" fn sysinfo_process_get_virtual_memory(process: CProcess) -> size_t { assert!(!process.is_null()); @@ -380,7 +380,7 @@ pub extern "C" fn sysinfo_process_get_virtual_memory(process: CProcess) -> size_ unsafe { (*process).virtual_memory() as usize } } -/// Equivalent of `Process::exe()`. +/// Equivalent of [`Process::exe()`][crate::Process#method.exe]. #[no_mangle] pub extern "C" fn sysinfo_process_get_executable_path(process: CProcess) -> RString { assert!(!process.is_null()); @@ -395,7 +395,7 @@ pub extern "C" fn sysinfo_process_get_executable_path(process: CProcess) -> RStr } } -/// Equivalent of `Process::root()`. +/// Equivalent of [`Process::root()`][crate::Process#method.root]. #[no_mangle] pub extern "C" fn sysinfo_process_get_root_directory(process: CProcess) -> RString { assert!(!process.is_null()); @@ -410,7 +410,7 @@ pub extern "C" fn sysinfo_process_get_root_directory(process: CProcess) -> RStri } } -/// Equivalent of `Process::cwd()`. +/// Equivalent of [`Process::cwd()`][crate::Process#method.cwd]. #[no_mangle] pub extern "C" fn sysinfo_process_get_current_directory(process: CProcess) -> RString { assert!(!process.is_null()); diff --git a/src/common.rs b/src/common.rs index 5bdc9c3df..866edfe8d 100644 --- a/src/common.rs +++ b/src/common.rs @@ -8,9 +8,9 @@ use NetworkData; use Networks; use NetworksExt; -/// Trait to have a common fallback for the `Pid` type. +/// Trait to have a common fallback for the [`Pid`][crate::Pid] type. pub trait AsU32 { - /// Allows to convert `Pid` into `u32`. + /// Allows to convert [`Pid`][crate::Pid] into [`u32`]. fn as_u32(&self) -> u32; } @@ -114,6 +114,8 @@ assert_eq!(r.", stringify!($name), "(), false); /// assert_eq!(system.get_disks().len(), 0); /// assert!(system.get_process_list().len() > 0); /// ``` +/// +/// [`System`]: crate::System #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct RefreshKind { networks: bool, diff --git a/src/linux/component.rs b/src/linux/component.rs index 8264ab478..2f9a576aa 100644 --- a/src/linux/component.rs +++ b/src/linux/component.rs @@ -14,7 +14,7 @@ use std::path::{Path, PathBuf}; /// More information can be found at [kernel.org][k]. /// -/// k: https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface +/// [k]: https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface pub struct Component { temperature: f32, max: f32, diff --git a/src/linux/disk.rs b/src/linux/disk.rs index 9df169b16..6ca01d1fe 100644 --- a/src/linux/disk.rs +++ b/src/linux/disk.rs @@ -15,7 +15,7 @@ use std::mem; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; -/// Enum containing the different handled disks types. +/// Enum containing the different supported disks types. #[derive(Debug, PartialEq, Clone, Copy)] pub enum DiskType { /// HDD type. diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 7e88f6915..225261d65 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -14,7 +14,7 @@ //! ``` //! use sysinfo::{ProcessExt, SystemExt}; //! -//! let mut system = sysinfo::System::new(); +//! let mut system = sysinfo::System::new_all(); //! //! // First we update all information of our system struct. //! system.refresh_all(); diff --git a/src/traits.rs b/src/traits.rs index e8fccf481..b2e07d0cb 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; use std::ffi::OsStr; use std::path::Path; -/// Contains all the methods of the `Disk` struct. +/// Contains all the methods of the [`Disk`][crate::Disk] struct. /// /// ```no_run /// use sysinfo::{DiskExt, System, SystemExt}; @@ -103,7 +103,7 @@ pub trait DiskExt { fn update(&mut self) -> bool; } -/// Contains all the methods of the `Process` struct. +/// Contains all the methods of the [`Process`][crate::Process] struct. pub trait ProcessExt { /// Create a new process only containing the given information. /// @@ -288,7 +288,7 @@ pub trait ProcessExt { fn cpu_usage(&self) -> f32; } -/// Contains all the methods of the `Processor` struct. +/// Contains all the methods of the [`Processor`][crate::Processor] struct. pub trait ProcessorExt { /// Returns this processor's usage. /// @@ -354,11 +354,12 @@ pub trait ProcessorExt { fn get_frequency(&self) -> u64; } -/// Contains all the methods of the [`System`] type. +/// Contains all the methods of the [`System`][crate::System] type. pub trait SystemExt: Sized { /// Creates a new [`System`] instance with nothing loaded. Use the [`refresh_all`] method to /// update its internal information (or any of the `refresh_` method). /// + /// [`System`]: crate::System /// [`refresh_all`]: #method.refresh_all /// /// ```no_run @@ -372,7 +373,9 @@ pub trait SystemExt: Sized { /// Creates a new [`System`] instance with everything loaded. /// - /// It is an equivalent of `SystemExt::new_with_specifics(RefreshKind::everything())`. + /// It is an equivalent of [`SystemExt::new_with_specifics`]`(`[`RefreshKind::everything`]`())`. + /// + /// [`System`]: crate::System /// /// ```no_run /// use sysinfo::{System, SystemExt}; @@ -386,6 +389,8 @@ pub trait SystemExt: Sized { /// Creates a new [`System`] instance and refresh the data corresponding to the /// given [`RefreshKind`]. /// + /// [`System`]: crate::System + /// /// # Example /// /// ``` From b1be53867192a200ce42352a5508f9b86bc47f11 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 18:37:32 +0100 Subject: [PATCH 132/171] Move DiskType enum to common file --- src/common.rs | 41 +++++++++++++++++++++++++++++++++++++++++ src/linux/disk.rs | 22 +--------------------- src/linux/mod.rs | 2 +- src/mac/disk.rs | 22 +--------------------- src/mac/mod.rs | 2 +- src/sysinfo.rs | 4 ++-- src/traits.rs | 3 ++- src/unknown/disk.rs | 5 +---- src/unknown/mod.rs | 2 +- src/windows/disk.rs | 22 +--------------------- src/windows/mod.rs | 2 +- 11 files changed, 53 insertions(+), 74 deletions(-) diff --git a/src/common.rs b/src/common.rs index 866edfe8d..13b20510b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -202,6 +202,15 @@ impl RefreshKind { } /// Iterator over network interfaces. +/// +/// It is returned by [`Networks::iter`][crate::Networks#method.iter]. +/// +/// ```no_run +/// use sysinfo::{System, SystemExt, NetworksExt}; +/// +/// let system = System::new_all(); +/// let networks_iter = system.get_networks().iter(); +/// ``` pub struct NetworksIter<'a> { inner: std::collections::hash_map::Iter<'a, String, NetworkData>, } @@ -228,3 +237,35 @@ impl<'a> IntoIterator for &'a Networks { self.iter() } } + +/// Enum containing the different supported disks types. +/// +/// This type is returned by [`Disk::get_type`][crate::Disk#method.get_type]. +/// +/// ```no_run +/// use sysinfo::{System, SystemExt, DiskExt}; +/// +/// let system = System::new_all(); +/// for disk in system.get_disks() { +/// println!("{:?}: {:?}", disk.get_name(), disk.get_type()); +/// } +/// ``` +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum DiskType { + /// HDD type. + HDD, + /// SSD type. + SSD, + /// Unknown type. + Unknown(isize), +} + +impl From for DiskType { + fn from(t: isize) -> DiskType { + match t { + 0 => DiskType::HDD, + 1 => DiskType::SSD, + id => DiskType::Unknown(id), + } + } +} diff --git a/src/linux/disk.rs b/src/linux/disk.rs index 6ca01d1fe..cd261e99c 100644 --- a/src/linux/disk.rs +++ b/src/linux/disk.rs @@ -7,6 +7,7 @@ use super::system::get_all_data; use utils; use DiskExt; +use DiskType; use libc::statvfs; use std::ffi::{OsStr, OsString}; @@ -15,27 +16,6 @@ use std::mem; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; -/// Enum containing the different supported disks types. -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum DiskType { - /// HDD type. - HDD, - /// SSD type. - SSD, - /// Unknown type. - Unknown(isize), -} - -impl From for DiskType { - fn from(t: isize) -> DiskType { - match t { - 0 => DiskType::SSD, - 1 => DiskType::HDD, - id => DiskType::Unknown(id), - } - } -} - fn find_type_for_name(name: &OsStr) -> DiskType { /* turn "sda1" into "sda": */ let mut trimmed: &[u8] = name.as_bytes(); diff --git a/src/linux/mod.rs b/src/linux/mod.rs index ea2b88c65..9a228c465 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -12,7 +12,7 @@ pub mod processor; pub mod system; pub use self::component::Component; -pub use self::disk::{Disk, DiskType}; +pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; diff --git a/src/mac/disk.rs b/src/mac/disk.rs index 7e99b7f9c..dc90e2eef 100644 --- a/src/mac/disk.rs +++ b/src/mac/disk.rs @@ -6,6 +6,7 @@ use utils; use DiskExt; +use DiskType; use libc::{c_char, c_void, statfs}; use std::collections::HashMap; @@ -19,27 +20,6 @@ use std::path::{Path, PathBuf}; use std::ptr; use sys::ffi; -/// Enum containing the different handled disks types. -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum DiskType { - /// HDD type. - HDD, - /// SSD type. - SSD, - /// Unknown type. - Unknown(isize), -} - -impl From for DiskType { - fn from(t: isize) -> DiskType { - match t { - 0 => DiskType::HDD, - 1 => DiskType::SSD, - id => DiskType::Unknown(id), - } - } -} - /// Struct containing a disk information. pub struct Disk { type_: DiskType, diff --git a/src/mac/mod.rs b/src/mac/mod.rs index 8a2becbc9..e52da14f7 100644 --- a/src/mac/mod.rs +++ b/src/mac/mod.rs @@ -13,7 +13,7 @@ pub mod processor; pub mod system; pub use self::component::Component; -pub use self::disk::{Disk, DiskType}; +pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 225261d65..b2660d3b3 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -78,9 +78,9 @@ cfg_if! { } } -pub use common::{AsU32, NetworksIter, Pid, RefreshKind}; +pub use common::{AsU32, DiskType, NetworksIter, Pid, RefreshKind}; pub use sys::{ - Component, Disk, DiskType, NetworkData, Networks, Process, ProcessStatus, Processor, System, + Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System, }; pub use traits::{ ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, diff --git a/src/traits.rs b/src/traits.rs index b2e07d0cb..8a88f78da 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -4,7 +4,8 @@ // Copyright (c) 2017 Guillaume Gomez // -use sys::{Component, Disk, DiskType, Networks, Process, Processor}; +use sys::{Component, Disk, Networks, Process, Processor}; +use DiskType; use LoadAvg; use NetworksIter; use Pid; diff --git a/src/unknown/disk.rs b/src/unknown/disk.rs index c2810cd60..8fe2625f6 100644 --- a/src/unknown/disk.rs +++ b/src/unknown/disk.rs @@ -5,14 +5,11 @@ // use DiskExt; +use DiskType; use std::ffi::OsStr; use std::path::Path; -/// Enum containing the different handled disks types. -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum DiskType {} - /// Struct containing a disk information. pub struct Disk {} diff --git a/src/unknown/mod.rs b/src/unknown/mod.rs index ea2b88c65..9a228c465 100644 --- a/src/unknown/mod.rs +++ b/src/unknown/mod.rs @@ -12,7 +12,7 @@ pub mod processor; pub mod system; pub use self::component::Component; -pub use self::disk::{Disk, DiskType}; +pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; diff --git a/src/windows/disk.rs b/src/windows/disk.rs index 2e4cf3da2..081c7b685 100644 --- a/src/windows/disk.rs +++ b/src/windows/disk.rs @@ -10,31 +10,11 @@ use std::path::Path; use std::str; use DiskExt; +use DiskType; use winapi::um::fileapi::GetDiskFreeSpaceExW; use winapi::um::winnt::ULARGE_INTEGER; -/// Enum containing the different handled disks types. -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum DiskType { - /// HDD type. - HDD, - /// SSD type. - SSD, - /// Unknown type. - Unknown(isize), -} - -impl From for DiskType { - fn from(t: isize) -> DiskType { - match t { - 0 => DiskType::HDD, - 1 => DiskType::SSD, - id => DiskType::Unknown(id), - } - } -} - pub fn new_disk( name: &OsStr, mount_point: &[u16], diff --git a/src/windows/mod.rs b/src/windows/mod.rs index 633234aa9..e48042562 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -17,7 +17,7 @@ mod tools; mod ffi; pub use self::component::Component; -pub use self::disk::{Disk, DiskType}; +pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; From d35b4b1391c2a69f3ea96f2cf1150b4b29905251 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 21:46:57 +0100 Subject: [PATCH 133/171] Give more control over disks --- src/linux/disk.rs | 2 +- src/linux/system.rs | 14 ++++++-------- src/mac/disk.rs | 2 +- src/mac/system.rs | 41 +++++++++++++++++------------------------ src/traits.rs | 33 +++++++++++++++++++++++++++++---- src/unknown/disk.rs | 2 +- src/unknown/system.rs | 6 ++++-- src/windows/disk.rs | 2 +- src/windows/system.rs | 12 +++++------- 9 files changed, 65 insertions(+), 49 deletions(-) diff --git a/src/linux/disk.rs b/src/linux/disk.rs index cd261e99c..334b88329 100644 --- a/src/linux/disk.rs +++ b/src/linux/disk.rs @@ -114,7 +114,7 @@ impl DiskExt for Disk { self.available_space } - fn update(&mut self) -> bool { + fn refresh(&mut self) -> bool { unsafe { let mut stat: statvfs = mem::zeroed(); let mount_point_cpath = utils::to_cpath(&self.mount_point); diff --git a/src/linux/system.rs b/src/linux/system.rs index 3f2fc86d0..abab31ea5 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -13,7 +13,7 @@ use Disk; use LoadAvg; use Networks; use Pid; -use {DiskExt, ProcessExt, RefreshKind, SystemExt}; +use {ProcessExt, RefreshKind, SystemExt}; use libc::{self, gid_t, sysconf, uid_t, _SC_CLK_TCK, _SC_PAGESIZE}; use std::cell::UnsafeCell; @@ -304,12 +304,6 @@ impl SystemExt for System { found } - fn refresh_disks(&mut self) { - for disk in &mut self.disks { - disk.update(); - } - } - fn refresh_disks_list(&mut self) { self.disks = get_all_disks(); } @@ -368,7 +362,11 @@ impl SystemExt for System { } fn get_disks(&self) -> &[Disk] { - &self.disks[..] + &self.disks + } + + fn get_disks_mut(&mut self) -> &mut [Disk] { + &mut self.disks } fn get_uptime(&self) -> u64 { diff --git a/src/mac/disk.rs b/src/mac/disk.rs index dc90e2eef..48a11be80 100644 --- a/src/mac/disk.rs +++ b/src/mac/disk.rs @@ -70,7 +70,7 @@ impl DiskExt for Disk { self.available_space } - fn update(&mut self) -> bool { + fn refresh(&mut self) -> bool { unsafe { let mut stat: statfs = mem::zeroed(); let mount_point_cpath = utils::to_cpath(&self.mount_point); diff --git a/src/mac/system.rs b/src/mac/system.rs index 5695d9e43..a00233255 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -11,7 +11,7 @@ use sys::network::Networks; use sys::process::*; use sys::processor::*; -use {DiskExt, LoadAvg, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; +use {LoadAvg, Pid, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; use std::cell::UnsafeCell; use std::collections::HashMap; @@ -148,23 +148,18 @@ impl SystemExt for System { } } - fn refresh_temperatures(&mut self) { + fn refresh_components_list(&mut self) { if let Some(con) = self.connection { - if self.temperatures.is_empty() { - // getting CPU critical temperature - let critical_temp = crate::mac::component::get_temperature( - con, - &['T' as i8, 'C' as i8, '0' as i8, 'D' as i8, 0], - ); - - for (id, v) in crate::mac::component::COMPONENTS_TEMPERATURE_IDS.iter() { - if let Some(c) = Component::new((*id).to_owned(), None, critical_temp, v, con) { - self.temperatures.push(c); - } - } - } else { - for comp in &mut self.temperatures { - comp.update(con); + self.components.clear(); + // getting CPU critical temperature + let critical_temp = crate::mac::component::get_temperature( + con, + &['T' as i8, 'C' as i8, '0' as i8, 'D' as i8, 0], + ); + + for (id, v) in crate::mac::component::COMPONENTS_TEMPERATURE_IDS.iter() { + if let Some(c) = Component::new((*id).to_owned(), None, critical_temp, v, con) { + self.components.push(c); } } } @@ -317,12 +312,6 @@ impl SystemExt for System { } } - fn refresh_disks(&mut self) { - for disk in &mut self.disks { - disk.update(); - } - } - fn refresh_disks_list(&mut self) { self.disks = crate::mac::disk::get_disks(); } @@ -381,7 +370,11 @@ impl SystemExt for System { } fn get_disks(&self) -> &[Disk] { - &self.disks[..] + &self.disks + } + + fn get_disks_mut(&mut self) -> &mut [Disk] { + &mut self.disks } fn get_uptime(&self) -> u64 { diff --git a/src/traits.rs b/src/traits.rs index 8a88f78da..d963d8ab4 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -100,8 +100,16 @@ pub trait DiskExt { fn get_available_space(&self) -> u64; /// Update the disk' information. - #[doc(hidden)] - fn update(&mut self) -> bool; + /// + /// ```no_run + /// use sysinfo::{DiskExt, System, SystemExt}; + /// + /// let mut s = System::new_all(); + /// for disk in s.get_disks_mut() { + /// disk.refresh(); + /// } + /// ``` + fn refresh(&mut self) -> bool; } /// Contains all the methods of the [`Process`][crate::Process] struct. @@ -530,7 +538,11 @@ pub trait SystemExt: Sized { /// let mut s = System::new_all(); /// s.refresh_disks(); /// ``` - fn refresh_disks(&mut self); + fn refresh_disks(&mut self) { + for disk in self.get_disks_mut() { + disk.refresh(); + } + } /// The disk list will be emptied then completely recomputed. /// @@ -564,7 +576,8 @@ pub trait SystemExt: Sized { self.get_networks_mut().refresh(); } - /// The network list will be emptied then completely recomputed. + /// The network list will be updated: removing not existing anymore interfaces and adding new + /// ones. /// /// ```no_run /// use sysinfo::{System, SystemExt}; @@ -744,6 +757,18 @@ pub trait SystemExt: Sized { /// ``` fn get_disks(&self) -> &[Disk]; + /// Returns disks' list. + /// + /// ```no_run + /// use sysinfo::{DiskExt, System, SystemExt}; + /// + /// let mut s = System::new_all(); + /// for disk in s.get_disks_mut() { + /// disk.refresh(); + /// } + /// ``` + fn get_disks_mut(&mut self) -> &mut [Disk]; + /// Returns network interfaces. /// /// ```no_run diff --git a/src/unknown/disk.rs b/src/unknown/disk.rs index 8fe2625f6..b4285faef 100644 --- a/src/unknown/disk.rs +++ b/src/unknown/disk.rs @@ -38,7 +38,7 @@ impl DiskExt for Disk { 0 } - fn update(&mut self) -> bool { + fn refresh(&mut self) -> bool { true } } diff --git a/src/unknown/system.rs b/src/unknown/system.rs index 745e42af9..a4f85d2d2 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -41,8 +41,6 @@ impl SystemExt for System { false } - fn refresh_disks(&mut self) {} - fn refresh_disks_list(&mut self) {} fn refresh_network(&mut self) {} @@ -103,6 +101,10 @@ impl SystemExt for System { &[] } + fn get_disks_mut(&self) -> &mut [Disk] { + &mut [] + } + fn get_uptime(&self) -> u64 { 0 } diff --git a/src/windows/disk.rs b/src/windows/disk.rs index 081c7b685..cc13efd85 100644 --- a/src/windows/disk.rs +++ b/src/windows/disk.rs @@ -86,7 +86,7 @@ impl DiskExt for Disk { self.available_space } - fn update(&mut self) -> bool { + fn refresh(&mut self) -> bool { if self.total_space != 0 { unsafe { let mut tmp: ULARGE_INTEGER = ::std::mem::zeroed(); diff --git a/src/windows/system.rs b/src/windows/system.rs index f6a76966c..d20ed29ae 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -283,12 +283,6 @@ impl SystemExt for System { } } - fn refresh_disks(&mut self) { - self.disks.par_iter_mut().for_each(|disk| { - disk.update(); - }); - } - fn refresh_disks_list(&mut self) { self.disks = unsafe { get_disks() }; } @@ -334,7 +328,11 @@ impl SystemExt for System { } fn get_disks(&self) -> &[Disk] { - &self.disks[..] + &self.disks + } + + fn get_disks_mut(&self) -> &mut [Disk] { + &mut self.disks } fn get_networks(&self) -> &Networks { From 292fd031a229f4ed9f2fd40136e37b4e3c4af609 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 22:26:02 +0100 Subject: [PATCH 134/171] Update components API to give more controlto the users --- examples/src/simple.rs | 2 +- src/c_interface.rs | 6 +-- src/common.rs | 18 ++++++--- src/linux/component.rs | 31 ++++++++-------- src/linux/system.rs | 22 ++++++----- src/mac/component.rs | 26 +++++++------ src/mac/system.rs | 12 ++++-- src/sysinfo.rs | 2 +- src/traits.rs | 80 ++++++++++++++++++++++++++++++---------- src/unknown/system.rs | 8 +++- src/windows/component.rs | 38 +++++++++---------- src/windows/system.rs | 22 +++++++---- 12 files changed, 167 insertions(+), 100 deletions(-) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index c50e7d231..9bc94d496 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -240,7 +240,7 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { } } "temperature" => { - for component in sys.get_components_list() { + for component in sys.get_components() { writeln!(&mut io::stdout(), "{:?}", component); } } diff --git a/src/c_interface.rs b/src/c_interface.rs index f6a254e03..0d9c14826 100644 --- a/src/c_interface.rs +++ b/src/c_interface.rs @@ -70,14 +70,14 @@ pub extern "C" fn sysinfo_refresh_cpu(system: CSystem) { Box::into_raw(system); } -/// Equivalent of [`System::refresh_temperatures()`][crate::System#method.refresh_temperatures]. +/// Equivalent of [`System::refresh_components()`][crate::System#method.refresh_temperatures]. #[no_mangle] -pub extern "C" fn sysinfo_refresh_temperatures(system: CSystem) { +pub extern "C" fn sysinfo_refresh_components(system: CSystem) { assert!(!system.is_null()); let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; { let system: &mut System = system.borrow_mut(); - system.refresh_temperatures(); + system.refresh_components(); } Box::into_raw(system); } diff --git a/src/common.rs b/src/common.rs index 13b20510b..b7c32158d 100644 --- a/src/common.rs +++ b/src/common.rs @@ -125,7 +125,8 @@ pub struct RefreshKind { disks: bool, memory: bool, cpu: bool, - temperatures: bool, + components: bool, + components_list: bool, } impl RefreshKind { @@ -145,7 +146,8 @@ impl RefreshKind { /// assert_eq!(r.disks(), false); /// assert_eq!(r.memory(), false); /// assert_eq!(r.cpu(), false); - /// assert_eq!(r.temperatures(), false); + /// assert_eq!(r.components(), false); + /// assert_eq!(r.components_list(), false); /// ``` pub fn new() -> RefreshKind { RefreshKind { @@ -156,7 +158,8 @@ impl RefreshKind { disks_list: false, memory: false, cpu: false, - temperatures: false, + components: false, + components_list: false, } } @@ -176,7 +179,8 @@ impl RefreshKind { /// assert_eq!(r.disks(), true); /// assert_eq!(r.memory(), true); /// assert_eq!(r.cpu(), true); - /// assert_eq!(r.temperatures(), true); + /// assert_eq!(r.components(), true); + /// assert_eq!(r.components_list(), true); /// ``` pub fn everything() -> RefreshKind { RefreshKind { @@ -187,7 +191,8 @@ impl RefreshKind { disks_list: true, memory: true, cpu: true, - temperatures: true, + components: true, + components_list: true, } } @@ -198,7 +203,8 @@ impl RefreshKind { impl_get_set!(disks_list, with_disks_list, without_disks_list); impl_get_set!(memory, with_memory, without_memory); impl_get_set!(cpu, with_cpu, without_cpu); - impl_get_set!(temperatures, with_temperatures, without_temperatures); + impl_get_set!(components, with_components, without_components); + impl_get_set!(components_list, with_components_list, without_components_list); } /// Iterator over network interfaces. diff --git a/src/linux/component.rs b/src/linux/component.rs index 2f9a576aa..d203d59a4 100644 --- a/src/linux/component.rs +++ b/src/linux/component.rs @@ -126,7 +126,7 @@ fn append_files(components: &mut Vec, folder: &Path) { impl Component { /// Creates a new component with the given information. - pub fn new( + pub(crate) fn new( label: String, input_path: &Path, max: Option, @@ -139,23 +139,9 @@ impl Component { max: max.unwrap_or(0.0), critical, }; - c.update(); + c.refresh(); c } - - /// Updates the component. - pub fn update(&mut self) { - if let Some(content) = get_file_line(self.input_file.as_path(), 10) { - self.temperature = content - .replace("\n", "") - .parse::() - .unwrap_or(100_000f32) - / 1000f32; - if self.temperature > self.max { - self.max = self.temperature; - } - } - } } impl ComponentExt for Component { @@ -174,6 +160,19 @@ impl ComponentExt for Component { fn get_label(&self) -> &str { &self.label } + + fn refresh(&mut self) { + if let Some(content) = get_file_line(self.input_file.as_path(), 10) { + self.temperature = content + .replace("\n", "") + .parse::() + .unwrap_or(100_000f32) + / 1000f32; + if self.temperature > self.max { + self.max = self.temperature; + } + } + } } pub fn get_components() -> Vec { diff --git a/src/linux/system.rs b/src/linux/system.rs index abab31ea5..1dd0041ab 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -105,7 +105,7 @@ pub struct System { swap_free: u64, processors: Vec, page_size_kb: u64, - temperatures: Vec, + components: Vec, disks: Vec, networks: Networks, uptime: u64, @@ -220,7 +220,7 @@ impl SystemExt for System { swap_free: 0, processors: Vec::with_capacity(4), page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 }, - temperatures: component::get_components(), + components: Vec::new(), disks: Vec::with_capacity(2), networks: Networks::new(), uptime: get_uptime(), @@ -229,6 +229,10 @@ impl SystemExt for System { s } + fn refresh_components_list(&mut self) { + self.components = component::get_components(); + } + fn refresh_memory(&mut self) { self.uptime = get_uptime(); if let Ok(data) = get_all_data("/proc/meminfo", 16_385) { @@ -254,12 +258,6 @@ impl SystemExt for System { self.refresh_processors(None); } - fn refresh_temperatures(&mut self) { - for component in &mut self.temperatures { - component.update(); - } - } - fn refresh_processes(&mut self) { self.uptime = get_uptime(); if refresh_procs( @@ -357,8 +355,12 @@ impl SystemExt for System { self.swap_total - self.swap_free } - fn get_components_list(&self) -> &[Component] { - &self.temperatures[..] + fn get_components(&self) -> &[Component] { + &self.components + } + + fn get_components_mut(&mut self) -> &mut [Component] { + &mut self.components } fn get_disks(&self) -> &[Disk] { diff --git a/src/mac/component.rs b/src/mac/component.rs index 85c9ac326..52d953c3f 100644 --- a/src/mac/component.rs +++ b/src/mac/component.rs @@ -42,6 +42,7 @@ pub struct Component { critical: Option, label: String, ffi_part: ComponentFFI, + connection: ffi::io_connect_t, } impl Component { @@ -51,26 +52,18 @@ impl Component { max: Option, critical: Option, key: &[i8], - con: ffi::io_connect_t, + connection: ffi::io_connect_t, ) -> Option { - let ffi_part = ComponentFFI::new(key, con)?; - ffi_part.get_temperature(con).map(|temperature| Component { + let ffi_part = ComponentFFI::new(key, connection)?; + ffi_part.get_temperature(connection).map(|temperature| Component { temperature, label, max: max.unwrap_or(0.0), critical, ffi_part, + connection, }) } - - pub(crate) fn update(&mut self, con: ffi::io_connect_t) { - if let Some(temp) = self.ffi_part.get_temperature(con) { - self.temperature = temp; - if self.temperature > self.max { - self.max = self.temperature; - } - } - } } impl ComponentExt for Component { @@ -89,6 +82,15 @@ impl ComponentExt for Component { fn get_label(&self) -> &str { &self.label } + + fn refresh(&mut self) { + if let Some(temp) = self.ffi_part.get_temperature(self.connection) { + self.temperature = temp; + if self.temperature > self.max { + self.max = self.temperature; + } + } + } } unsafe fn perform_call( diff --git a/src/mac/system.rs b/src/mac/system.rs index a00233255..36a1792ce 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -31,7 +31,7 @@ pub struct System { swap_free: u64, processors: Vec, page_size_kb: u64, - temperatures: Vec, + components: Vec, connection: Option, disks: Vec, networks: Networks, @@ -79,7 +79,7 @@ impl SystemExt for System { swap_free: 0, processors: Vec::with_capacity(4), page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 >> 10 }, // divide by 1024 - temperatures: Vec::with_capacity(2), + components: Vec::with_capacity(2), connection: get_io_service_connection(), disks: Vec::with_capacity(1), networks: Networks::new(), @@ -365,8 +365,12 @@ impl SystemExt for System { self.swap_total - self.swap_free } - fn get_components_list(&self) -> &[Component] { - &self.temperatures[..] + fn get_components(&self) -> &[Component] { + &self.components + } + + fn get_components_mut(&mut self) -> &mut [Component] { + &mut self.components } fn get_disks(&self) -> &[Disk] { diff --git a/src/sysinfo.rs b/src/sysinfo.rs index b2660d3b3..ea426357e 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -25,7 +25,7 @@ //! } //! //! // Then let's print the temperature of the different components: -//! for component in system.get_components_list() { +//! for component in system.get_components() { //! println!("{:?}", component); //! } //! diff --git a/src/traits.rs b/src/traits.rs index d963d8ab4..3c2637c3f 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -365,8 +365,12 @@ pub trait ProcessorExt { /// Contains all the methods of the [`System`][crate::System] type. pub trait SystemExt: Sized { - /// Creates a new [`System`] instance with nothing loaded. Use the [`refresh_all`] method to - /// update its internal information (or any of the `refresh_` method). + /// Creates a new [`System`] instance with nothing loaded. If you want to load components, + /// network interfaces or the disks, you'll have to use the `refresh_*_list` methods. + /// [`SystemExt::refresh_networks_list`] for example. + /// + /// Use the [`refresh_all`] method to update its internal information (or any of the `refresh_` + /// method). /// /// [`System`]: crate::System /// [`refresh_all`]: #method.refresh_all @@ -438,13 +442,14 @@ pub trait SystemExt: Sized { if refreshes.cpu() { self.refresh_cpu(); } - if refreshes.temperatures() { - self.refresh_temperatures(); + if refreshes.components_list() { + self.refresh_components_list(); + } else if refreshes.components() { + self.refresh_components(); } if refreshes.networks_list() { self.refresh_networks_list(); - } - if refreshes.networks() { + } else if refreshes.networks() { self.refresh_networks(); } if refreshes.processes() { @@ -452,8 +457,7 @@ pub trait SystemExt: Sized { } if refreshes.disks_list() { self.refresh_disks_list(); - } - if refreshes.disks() { + } else if refreshes.disks() { self.refresh_disks(); } } @@ -461,11 +465,11 @@ pub trait SystemExt: Sized { /// Refresh system information (such as memory, swap, CPU usage and components' temperature). /// /// If you want some more specific refresh, you might be interested into looking at - /// [`refresh_memory`], [`refresh_cpu`] and [`refresh_temperatures`]. + /// [`refresh_memory`], [`refresh_cpu`] and [`refresh_components`]. /// /// [`refresh_memory`]: SystemExt::refresh_memory /// [`refresh_cpu`]: SystemExt::refresh_memory - /// [`refresh_temperatures`]: SystemExt::refresh_temperatures + /// [`refresh_components`]: SystemExt::refresh_components /// /// ```no_run /// use sysinfo::{System, SystemExt}; @@ -476,7 +480,7 @@ pub trait SystemExt: Sized { fn refresh_system(&mut self) { self.refresh_memory(); self.refresh_cpu(); - self.refresh_temperatures(); + self.refresh_components(); } /// Refresh RAM and SWAP usage. @@ -505,9 +509,23 @@ pub trait SystemExt: Sized { /// use sysinfo::{System, SystemExt}; /// /// let mut s = System::new_all(); - /// s.refresh_temperatures(); + /// s.refresh_components(); /// ``` - fn refresh_temperatures(&mut self); + fn refresh_components(&mut self) { + for component in self.get_components_mut() { + component.refresh(); + } + } + + /// Refresh components list. + /// + /// ```no_run + /// use sysinfo::{System, SystemExt}; + /// + /// let mut s = System::new(); + /// s.refresh_components_list(); + /// ``` + fn refresh_components_list(&mut self); /// Get all processes and update their information. /// @@ -739,11 +757,23 @@ pub trait SystemExt: Sized { /// use sysinfo::{ComponentExt, System, SystemExt}; /// /// let s = System::new_all(); - /// for component in s.get_components_list() { + /// for component in s.get_components() { /// println!("{}: {}°C", component.get_label(), component.get_temperature()); /// } /// ``` - fn get_components_list(&self) -> &[Component]; + fn get_components(&self) -> &[Component]; + + /// Returns components list. + /// + /// ```no_run + /// use sysinfo::{ComponentExt, System, SystemExt}; + /// + /// let mut s = System::new_all(); + /// for component in s.get_components_mut() { + /// component.refresh(); + /// } + /// ``` + fn get_components_mut(&mut self) -> &mut [Component]; /// Returns disks' list. /// @@ -1025,7 +1055,7 @@ pub trait ComponentExt { /// use sysinfo::{ComponentExt, System, SystemExt}; /// /// let s = System::new_all(); - /// for component in s.get_components_list() { + /// for component in s.get_components() { /// println!("{}°C", component.get_temperature()); /// } /// ``` @@ -1037,7 +1067,7 @@ pub trait ComponentExt { /// use sysinfo::{ComponentExt, System, SystemExt}; /// /// let s = System::new_all(); - /// for component in s.get_components_list() { + /// for component in s.get_components() { /// println!("{}°C", component.get_max()); /// } /// ``` @@ -1049,7 +1079,7 @@ pub trait ComponentExt { /// use sysinfo::{ComponentExt, System, SystemExt}; /// /// let s = System::new_all(); - /// for component in s.get_components_list() { + /// for component in s.get_components() { /// println!("{:?}°C", component.get_critical()); /// } /// ``` @@ -1061,9 +1091,21 @@ pub trait ComponentExt { /// use sysinfo::{ComponentExt, System, SystemExt}; /// /// let s = System::new_all(); - /// for component in s.get_components_list() { + /// for component in s.get_components() { /// println!("{}", component.get_label()); /// } /// ``` fn get_label(&self) -> &str; + + /// Refresh component. + /// + /// ```no_run + /// use sysinfo::{ComponentExt, System, SystemExt}; + /// + /// let mut s = System::new_all(); + /// for component in s.get_components_mut() { + /// component.refresh(); + /// } + /// ``` + fn refresh(&mut self); } diff --git a/src/unknown/system.rs b/src/unknown/system.rs index a4f85d2d2..f47cccc04 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -33,7 +33,7 @@ impl SystemExt for System { fn refresh_cpu(&mut self) {} - fn refresh_temperatures(&mut self) {} + fn refresh_components_list(&mut self) {} fn refresh_processes(&mut self) {} @@ -93,7 +93,11 @@ impl SystemExt for System { 0 } - fn get_components_list(&self) -> &[Component] { + fn get_components(&self) -> &[Component] { + &[] + } + + fn get_components_mut(&self) -> &[Component] { &[] } diff --git a/src/windows/component.rs b/src/windows/component.rs index b9d2c5dca..39c792b7c 100644 --- a/src/windows/component.rs +++ b/src/windows/component.rs @@ -60,8 +60,26 @@ impl Component { None => None, } } +} + +impl ComponentExt for Component { + fn get_temperature(&self) -> f32 { + self.temperature + } + + fn get_max(&self) -> f32 { + self.max + } + + fn get_critical(&self) -> Option { + self.critical + } + + fn get_label(&self) -> &str { + &self.label + } - pub(crate) fn refresh(&mut self) { + fn refresh(&mut self) { if self.connection.is_none() { self.connection = Connection::new() .and_then(|x| x.initialize_security()) @@ -85,24 +103,6 @@ impl Component { } } -impl ComponentExt for Component { - fn get_temperature(&self) -> f32 { - self.temperature - } - - fn get_max(&self) -> f32 { - self.max - } - - fn get_critical(&self) -> Option { - self.critical - } - - fn get_label(&self) -> &str { - &self.label - } -} - pub fn get_components() -> Vec { match Component::new() { Some(c) => vec![c], diff --git a/src/windows/system.rs b/src/windows/system.rs index d20ed29ae..92d85ade1 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -47,7 +47,7 @@ pub struct System { swap_total: u64, swap_free: u64, processors: Vec, - temperatures: Vec, + components: Vec, disks: Vec, query: Option, networks: Networks, @@ -70,7 +70,7 @@ impl SystemExt for System { swap_total: 0, swap_free: 0, processors: init_processors(), - temperatures: component::get_components(), + components: Vec::new(), disks: Vec::with_capacity(2), query: Query::new(), networks: Networks::new(), @@ -163,14 +163,18 @@ impl SystemExt for System { /// use sysinfo::{System, SystemExt}; /// /// let mut s = System::new(); - /// s.refresh_temperatures(); + /// s.refresh_components(); /// ``` - fn refresh_temperatures(&mut self) { - for component in &mut self.temperatures { + fn refresh_components(&mut self) { + for component in &mut self.components { component.refresh(); } } + fn refresh_components_list(&mut self) { + self.components = component::get_components(); + } + fn refresh_process(&mut self, pid: Pid) -> bool { if refresh_existing_process(self, pid, true) == false { self.process_list.remove(&pid); @@ -323,8 +327,12 @@ impl SystemExt for System { (self.swap_total - self.swap_free) >> 10 } - fn get_components_list(&self) -> &[Component] { - &self.temperatures[..] + fn get_components(&self) -> &[Component] { + &self.components + } + + fn get_components_mut(&mut self) -> &mut [Component] { + &mut self.components } fn get_disks(&self) -> &[Disk] { From 1735697c77f328899f5808805a26c947bf5aada1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 22:33:25 +0100 Subject: [PATCH 135/171] fix windows errors --- src/windows/disk.rs | 2 +- src/windows/system.rs | 4 ++-- src/windows/tools.rs | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/windows/disk.rs b/src/windows/disk.rs index cc13efd85..deaf8e9cd 100644 --- a/src/windows/disk.rs +++ b/src/windows/disk.rs @@ -31,7 +31,7 @@ pub fn new_disk( total_space: total_space, available_space: 0, }; - d.update(); + d.refresh(); d } diff --git a/src/windows/system.rs b/src/windows/system.rs index 92d85ade1..ce0de827b 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -12,7 +12,7 @@ use std::cell::UnsafeCell; use std::collections::HashMap; use std::mem::{size_of, zeroed}; -use DiskExt; +use ComponentExt; use LoadAvg; use Networks; use Pid; @@ -339,7 +339,7 @@ impl SystemExt for System { &self.disks } - fn get_disks_mut(&self) -> &mut [Disk] { + fn get_disks_mut(&mut self) -> &mut [Disk] { &mut self.disks } diff --git a/src/windows/tools.rs b/src/windows/tools.rs index 895183247..8a8ba94a7 100644 --- a/src/windows/tools.rs +++ b/src/windows/tools.rs @@ -6,7 +6,8 @@ use windows::processor::{self, CounterValue, Processor, Query}; -use sys::disk::{new_disk, Disk, DiskType}; +use DiskType; +use sys::disk::{new_disk, Disk}; use std::collections::HashMap; use std::ffi::OsStr; From 2c2d581e3958a5a589d34dd25d32dc10e589aa19 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 23:13:10 +0100 Subject: [PATCH 136/171] Update benchmarks --- benches/basic.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/benches/basic.rs b/benches/basic.rs index 2d8b8791d..970510f19 100644 --- a/benches/basic.rs +++ b/benches/basic.rs @@ -116,10 +116,19 @@ fn bench_refresh_cpu(b: &mut test::Bencher) { } #[bench] -fn bench_refresh_temperatures(b: &mut test::Bencher) { +fn bench_refresh_components(b: &mut test::Bencher) { let mut s = sysinfo::System::new_all(); b.iter(move || { - s.refresh_temperatures(); + s.refresh_components(); + }); +} + +#[bench] +fn bench_refresh_components_list(b: &mut test::Bencher) { + let mut s = sysinfo::System::new_all(); + + b.iter(move || { + s.refresh_components_list(); }); } From a40fa49e2783c81ab2da4187d7492ab6c63fc77f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 23:13:19 +0100 Subject: [PATCH 137/171] update linux benchmark results --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1fd07ef92..ac6948abc 100644 --- a/README.md +++ b/README.md @@ -94,19 +94,20 @@ Here are the current results:
```text -test bench_new ... bench: 375,774 ns/iter (+/- 7,119) -test bench_new_all ... bench: 10,308,642 ns/iter (+/- 422,803) -test bench_refresh_all ... bench: 2,824,911 ns/iter (+/- 169,153) -test bench_refresh_cpu ... bench: 13,630 ns/iter (+/- 702) -test bench_refresh_disks ... bench: 2,558 ns/iter (+/- 14) -test bench_refresh_disks_lists ... bench: 51,737 ns/iter (+/- 5,712) -test bench_refresh_memory ... bench: 12,006 ns/iter (+/- 277) -test bench_refresh_networks ... bench: 223,858 ns/iter (+/- 28,537) -test bench_refresh_networks_list ... bench: 232,934 ns/iter (+/- 34,344) -test bench_refresh_process ... bench: 78,925 ns/iter (+/- 12,421) -test bench_refresh_processes ... bench: 2,235,119 ns/iter (+/- 137,403) -test bench_refresh_system ... bench: 52,832 ns/iter (+/- 6,704) -test bench_refresh_temperatures ... bench: 25,079 ns/iter (+/- 2,258) +test bench_new ... bench: 3,741 ns/iter (+/- 252) +test bench_new_all ... bench: 10,491,084 ns/iter (+/- 450,925) +test bench_refresh_all ... bench: 2,787,974 ns/iter (+/- 235,649) +test bench_refresh_components ... bench: 24,270 ns/iter (+/- 1,127) +test bench_refresh_components_list ... bench: 370,693 ns/iter (+/- 51,925) +test bench_refresh_cpu ... bench: 13,367 ns/iter (+/- 1,858) +test bench_refresh_disks ... bench: 2,532 ns/iter (+/- 108) +test bench_refresh_disks_lists ... bench: 50,359 ns/iter (+/- 5,877) +test bench_refresh_memory ... bench: 11,713 ns/iter (+/- 1,006) +test bench_refresh_networks ... bench: 220,246 ns/iter (+/- 24,294) +test bench_refresh_networks_list ... bench: 229,648 ns/iter (+/- 82,050) +test bench_refresh_process ... bench: 77,375 ns/iter (+/- 10,657) +test bench_refresh_processes ... bench: 2,282,106 ns/iter (+/- 154,098) +test bench_refresh_system ... bench: 52,466 ns/iter (+/- 4,710) ```
From e83e62287afc2da9e14621fd043dbe2419bedd9e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 23:14:52 +0100 Subject: [PATCH 138/171] Check for dead links as well --- .travis.yml | 3 ++- appveyor.yml | 1 + src/sysinfo.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 30f911216..1978a0d98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -74,6 +74,7 @@ script: - if [[ -z "$EXTRA" ]]; then RUST_BACKTRACE=1 cargo test; fi + - cargo doc - cd examples - if [[ -z "$EXTRA" ]]; then RUST_BACKTRACE=1 cargo build; @@ -87,4 +88,4 @@ script: fi - if [[ -z "$EXTRA" ]]; then LD_LIBRARY_PATH=./target/debug ./simple; - fi + fi \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index c0b717e7d..be938e573 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,6 +19,7 @@ build_script: - cargo clippy - cargo build - cargo test + - cargo doc - cd examples - cargo build diff --git a/src/sysinfo.rs b/src/sysinfo.rs index ea426357e..218197151 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -45,6 +45,7 @@ #![crate_type = "lib"] #![crate_type = "rlib"] #![deny(missing_docs)] +#![deny(intra_doc_link_resolution_failure)] //#![deny(warnings)] #![allow(unknown_lints)] From e85b1843f17dfa8d6a4ef41c22730abd96245dd2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2020 23:19:46 +0100 Subject: [PATCH 139/171] Update benchmark results for macOS --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ac6948abc..5cb6c9047 100644 --- a/README.md +++ b/README.md @@ -137,19 +137,20 @@ test bench_refresh_temperatures ... bench: 1,231,260 ns/iter (+/- 111,274)
```text -test bench_new ... bench: 54,862 ns/iter (+/- 6,528) -test bench_new_all ... bench: 4,989,120 ns/iter (+/- 1,001,529) -test bench_refresh_all ... bench: 1,924,596 ns/iter (+/- 341,209) -test bench_refresh_cpu ... bench: 10,521 ns/iter (+/- 1,623) -test bench_refresh_disks ... bench: 945 ns/iter (+/- 95) -test bench_refresh_disks_lists ... bench: 29,315 ns/iter (+/- 3,076) -test bench_refresh_memory ... bench: 3,275 ns/iter (+/- 143) -test bench_refresh_networks ... bench: 200,670 ns/iter (+/- 28,674) -test bench_refresh_networks_list ... bench: 200,263 ns/iter (+/- 31,473) -test bench_refresh_process ... bench: 4,009 ns/iter (+/- 584) -test bench_refresh_processes ... bench: 790,834 ns/iter (+/- 61,236) -test bench_refresh_system ... bench: 335,144 ns/iter (+/- 35,713) -test bench_refresh_temperatures ... bench: 298,823 ns/iter (+/- 77,589) +test bench_new ... bench: 56,861 ns/iter (+/- 5,653) +test bench_new_all ... bench: 4,634,509 ns/iter (+/- 1,604,369) +test bench_refresh_all ... bench: 1,962,343 ns/iter (+/- 129,726) +test bench_refresh_components ... bench: 294,752 ns/iter (+/- 45,107) +test bench_refresh_components_list ... bench: 895,672 ns/iter (+/- 112,586) +test bench_refresh_cpu ... bench: 11,187 ns/iter (+/- 2,483) +test bench_refresh_disks ... bench: 975 ns/iter (+/- 50) +test bench_refresh_disks_lists ... bench: 25,955 ns/iter (+/- 3,159) +test bench_refresh_memory ... bench: 3,440 ns/iter (+/- 198) +test bench_refresh_networks ... bench: 211,552 ns/iter (+/- 16,686) +test bench_refresh_networks_list ... bench: 211,138 ns/iter (+/- 22,644) +test bench_refresh_process ... bench: 4,174 ns/iter (+/- 1,249) +test bench_refresh_processes ... bench: 803,559 ns/iter (+/- 42,974) +test bench_refresh_system ... bench: 365,762 ns/iter (+/- 55,893) ```
From b4fc323e9e122976987de47cfcc6262ca416cc67 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Thu, 6 Feb 2020 23:34:16 +0100 Subject: [PATCH 140/171] Update windows benchmark results --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 5cb6c9047..ed38223e9 100644 --- a/README.md +++ b/README.md @@ -116,19 +116,20 @@ test bench_refresh_system ... bench: 52,466 ns/iter (+/- 4,710)
```text -test bench_new ... bench: 14,738,570 ns/iter (+/- 586,107) -test bench_new_all ... bench: 27,132,490 ns/iter (+/- 1,292,307) -test bench_refresh_all ... bench: 3,075,022 ns/iter (+/- 110,711) -test bench_refresh_cpu ... bench: 392 ns/iter (+/- 30) -test bench_refresh_disks ... bench: 41,778 ns/iter (+/- 954) -test bench_refresh_disks_lists ... bench: 113,942 ns/iter (+/- 4,240) -test bench_refresh_memory ... bench: 578 ns/iter (+/- 41) -test bench_refresh_networks ... bench: 38,178 ns/iter (+/- 3,718) -test bench_refresh_networks_list ... bench: 668,390 ns/iter (+/- 30,642) -test bench_refresh_process ... bench: 745 ns/iter (+/- 62) -test bench_refresh_processes ... bench: 1,179,581 ns/iter (+/- 188,119) -test bench_refresh_system ... bench: 1,230,542 ns/iter (+/- 64,231) -test bench_refresh_temperatures ... bench: 1,231,260 ns/iter (+/- 111,274) +test bench_new ... bench: 7,688,460 ns/iter (+/- 1,230,010) +test bench_new_all ... bench: 24,098,860 ns/iter (+/- 5,260,950) +test bench_refresh_all ... bench: 3,096,107 ns/iter (+/- 94,257) +test bench_refresh_components ... bench: 1,205,378 ns/iter (+/- 40,071) +test bench_refresh_components_list ... bench: 3,181,602 ns/iter (+/- 102,533) +test bench_refresh_cpu ... bench: 395 ns/iter (+/- 18) +test bench_refresh_disks ... bench: 53,082 ns/iter (+/- 1,834) +test bench_refresh_disks_lists ... bench: 114,080 ns/iter (+/- 1,920) +test bench_refresh_memory ... bench: 596 ns/iter (+/- 48) +test bench_refresh_networks ... bench: 37,549 ns/iter (+/- 1,622) +test bench_refresh_networks_list ... bench: 667,180 ns/iter (+/- 59,859) +test bench_refresh_process ... bench: 755 ns/iter (+/- 47) +test bench_refresh_processes ... bench: 1,217,488 ns/iter (+/- 69,041) +test bench_refresh_system ... bench: 1,214,780 ns/iter (+/- 52,013) ```
From d2b41c1b9592fdb6026a03b3a4ce122f9ce7d3cf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 7 Feb 2020 13:52:40 +0100 Subject: [PATCH 141/171] Rename get_processor_list into get_processors --- README.md | 2 +- examples/src/simple.rs | 8 ++++---- src/c_interface.rs | 2 +- src/linux/system.rs | 2 +- src/mac/system.rs | 2 +- src/traits.rs | 14 +++++++------- src/unknown/system.rs | 2 +- src/windows/system.rs | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ed38223e9..528b0f44c 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ println!("total swap : {} KiB", sys.get_total_swap()); println!("used swap : {} KiB", sys.get_used_swap()); // Number of processors -println!("NB processors: {}", sys.get_processor_list().len()); +println!("NB processors: {}", sys.get_processors().len()); // To refresh all system information: sys.refresh_all(); diff --git a/examples/src/simple.rs b/examples/src/simple.rs index 9bc94d496..c847b46e3 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -143,7 +143,7 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { "procs" => { // Note: you should refresh a few times before using this, so that usage statistics // can be ascertained - let procs = sys.get_processor_list(); + let procs = sys.get_processors(); writeln!( &mut io::stdout(), @@ -189,7 +189,7 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { } } "frequency" => { - let procs = sys.get_processor_list(); + let procs = sys.get_processors(); // On windows, the first processor is the "all processors", so not interesting in here. writeln!( &mut io::stdout(), @@ -201,14 +201,14 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { writeln!( &mut io::stdout(), "vendor ID: {}", - sys.get_processor_list()[0].get_vendor_id() + sys.get_processors()[0].get_vendor_id() ); } "brand" => { writeln!( &mut io::stdout(), "brand: {}", - sys.get_processor_list()[0].get_brand() + sys.get_processors()[0].get_brand() ); } "load_avg" => { diff --git a/src/c_interface.rs b/src/c_interface.rs index 0d9c14826..6552e8a46 100644 --- a/src/c_interface.rs +++ b/src/c_interface.rs @@ -247,7 +247,7 @@ pub extern "C" fn sysinfo_get_processors_usage( } let system: Box = unsafe { Box::from_raw(system as *mut System) }; { - let processors = system.get_processor_list(); + let processors = system.get_processors(); unsafe { if (*procs).is_null() { (*procs) = libc::malloc(::std::mem::size_of::() * processors.len()) diff --git a/src/linux/system.rs b/src/linux/system.rs index 1dd0041ab..5fd54aa85 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -326,7 +326,7 @@ impl SystemExt for System { &mut self.networks } - fn get_processor_list(&self) -> &[Processor] { + fn get_processors(&self) -> &[Processor] { &self.processors[..] } diff --git a/src/mac/system.rs b/src/mac/system.rs index 36a1792ce..cd9f1658e 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -328,7 +328,7 @@ impl SystemExt for System { self.process_list.get(&pid) } - fn get_processor_list(&self) -> &[Processor] { + fn get_processors(&self) -> &[Processor] { &self.processors[..] } diff --git a/src/traits.rs b/src/traits.rs index 3c2637c3f..62d8bba1b 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -308,7 +308,7 @@ pub trait ProcessorExt { /// use sysinfo::{ProcessorExt, System, SystemExt}; /// /// let s = System::new(); - /// for processor in s.get_processor_list() { + /// for processor in s.get_processors() { /// println!("{}%", processor.get_cpu_usage()); /// } /// ``` @@ -320,7 +320,7 @@ pub trait ProcessorExt { /// use sysinfo::{ProcessorExt, System, SystemExt}; /// /// let s = System::new(); - /// for processor in s.get_processor_list() { + /// for processor in s.get_processors() { /// println!("{}", processor.get_name()); /// } /// ``` @@ -332,7 +332,7 @@ pub trait ProcessorExt { /// use sysinfo::{ProcessorExt, System, SystemExt}; /// /// let s = System::new(); - /// for processor in s.get_processor_list() { + /// for processor in s.get_processors() { /// println!("{}", processor.get_vendor_id()); /// } /// ``` @@ -344,7 +344,7 @@ pub trait ProcessorExt { /// use sysinfo::{ProcessorExt, System, SystemExt}; /// /// let s = System::new(); - /// for processor in s.get_processor_list() { + /// for processor in s.get_processors() { /// println!("{}", processor.get_brand()); /// } /// ``` @@ -356,7 +356,7 @@ pub trait ProcessorExt { /// use sysinfo::{ProcessorExt, System, SystemExt}; /// /// let s = System::new(); - /// for processor in s.get_processor_list() { + /// for processor in s.get_processors() { /// println!("{}", processor.get_frequency()); /// } /// ``` @@ -685,11 +685,11 @@ pub trait SystemExt: Sized { /// use sysinfo::{ProcessorExt, System, SystemExt}; /// /// let s = System::new_all(); - /// for processor in s.get_processor_list() { + /// for processor in s.get_processors() { /// println!("{}%", processor.get_cpu_usage()); /// } /// ``` - fn get_processor_list(&self) -> &[Processor]; + fn get_processors(&self) -> &[Processor]; /// Returns total RAM size in KiB. /// diff --git a/src/unknown/system.rs b/src/unknown/system.rs index f47cccc04..a3e3c8724 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -65,7 +65,7 @@ impl SystemExt for System { &mut self.networks } - fn get_processor_list(&self) -> &[Processor] { + fn get_processors(&self) -> &[Processor] { &[] } diff --git a/src/windows/system.rs b/src/windows/system.rs index ce0de827b..c00a8c359 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -299,7 +299,7 @@ impl SystemExt for System { self.process_list.get(&(pid as usize)) } - fn get_processor_list(&self) -> &[Processor] { + fn get_processors(&self) -> &[Processor] { &self.processors[..] } From 71e0477389e9a78b85c8d5e294718496ab2b7b79 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 7 Feb 2020 14:54:29 +0100 Subject: [PATCH 142/171] Update processor API --- examples/src/simple.rs | 4 +- src/common.rs | 6 +- src/linux/processor.rs | 6 +- src/linux/system.rs | 159 ++++++++++++++++++++++++--------------- src/mac/component.rs | 18 +++-- src/mac/processor.rs | 74 +++++++++++++++++- src/mac/system.rs | 95 ++++++----------------- src/sysinfo.rs | 4 +- src/traits.rs | 12 ++- src/unknown/processor.rs | 6 ++ src/unknown/system.rs | 6 ++ src/windows/system.rs | 24 ++++-- src/windows/tools.rs | 10 +-- tests/disk_list.rs | 2 +- 14 files changed, 261 insertions(+), 165 deletions(-) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index c847b46e3..2d469de56 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -189,12 +189,10 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { } } "frequency" => { - let procs = sys.get_processors(); - // On windows, the first processor is the "all processors", so not interesting in here. writeln!( &mut io::stdout(), "{} MHz", - procs[if procs.len() > 1 { 1 } else { 0 }].get_frequency() + sys.get_processors()[0].get_frequency() ); } "vendor_id" => { diff --git a/src/common.rs b/src/common.rs index b7c32158d..e59c7a7d3 100644 --- a/src/common.rs +++ b/src/common.rs @@ -204,7 +204,11 @@ impl RefreshKind { impl_get_set!(memory, with_memory, without_memory); impl_get_set!(cpu, with_cpu, without_cpu); impl_get_set!(components, with_components, without_components); - impl_get_set!(components_list, with_components_list, without_components_list); + impl_get_set!( + components_list, + with_components_list, + without_components_list + ); } /// Iterator over network interfaces. diff --git a/src/linux/processor.rs b/src/linux/processor.rs index 8e79ba8c2..daf2e836d 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -124,13 +124,13 @@ impl CpuValues { pub struct Processor { old_values: CpuValues, new_values: CpuValues, - name: String, + pub(crate) name: String, cpu_usage: f32, total_time: u64, old_total_time: u64, frequency: u64, - vendor_id: String, - brand: String, + pub(crate) vendor_id: String, + pub(crate) brand: String, } impl Processor { diff --git a/src/linux/system.rs b/src/linux/system.rs index 5fd54aa85..455faf060 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -103,6 +103,7 @@ pub struct System { mem_free: u64, swap_total: u64, swap_free: u64, + global_processor: Processor, processors: Vec, page_size_kb: u64, components: Vec, @@ -114,16 +115,15 @@ pub struct System { impl System { fn clear_procs(&mut self) { if !self.processors.is_empty() { - let (new, old) = get_raw_times(&self.processors[0]); + let (new, old) = get_raw_times(&self.global_processor); let total_time = (if old > new { 1 } else { new - old }) as f32; let mut to_delete = Vec::with_capacity(20); - let nb_processors = self.processors.len() as u64 - 1; for (pid, proc_) in &mut self.process_list.tasks { if !has_been_updated(proc_) { to_delete.push(*pid); } else { - compute_cpu_usage(proc_, nb_processors, total_time); + compute_cpu_usage(proc_, self.processors.len() as u64, total_time); } } for pid in to_delete { @@ -133,65 +133,46 @@ impl System { } fn refresh_processors(&mut self, limit: Option) { - fn get_callbacks( - first: bool, - ) -> Box, &mut Vec, &mut usize)> { - if first { - let frequency = get_cpu_frequency(); - let (vendor_id, brand) = get_vendor_id_and_brand(); - Box::new( - move |parts: &mut dyn Iterator, - processors: &mut Vec, - _| { - processors.push(Processor::new_with_values( - to_str!(parts.next().unwrap_or(&[])), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - frequency, - vendor_id.clone(), - brand.clone(), - )); - }, - ) - } else { - Box::new( - |parts: &mut dyn Iterator, - processors: &mut Vec, - i: &mut usize| { - parts.next(); // we don't want the name again - processors[*i].set( - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - parts.next().map(|v| to_u64(v)).unwrap_or(0), - ); - *i += 1; - }, - ) - } - } if let Ok(f) = File::open("/proc/stat") { let buf = BufReader::new(f); let mut i = 0; let first = self.processors.is_empty(); let mut it = buf.split(b'\n'); let mut count = 0; - let callback = get_callbacks(first); + let frequency = if first { get_cpu_frequency() } else { 0 }; + let (vendor_id, brand) = if first { + get_vendor_id_and_brand() + } else { + (String::new(), String::new()) + }; + if let Some(Ok(line)) = it.next() { + if &line[..3] != b"cpu" { + return; + } + count += 1; + let mut parts = line.split(|x| *x == b' ').filter(|s| !s.is_empty()); + if first { + self.global_processor.name = to_str!(parts.next().unwrap_or(&[])).to_owned(); + } + self.global_processor.set( + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + ); + if let Some(limit) = limit { + if count >= limit { + return; + } + } + } while let Some(Ok(line)) = it.next() { if &line[..3] != b"cpu" { break; @@ -199,13 +180,49 @@ impl System { count += 1; let mut parts = line.split(|x| *x == b' ').filter(|s| !s.is_empty()); - callback(&mut parts, &mut self.processors, &mut i); + if first { + self.processors.push(Processor::new_with_values( + to_str!(parts.next().unwrap_or(&[])), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + frequency, + vendor_id.clone(), + brand.clone(), + )); + } else { + parts.next(); // we don't want the name again + self.processors[i].set( + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + parts.next().map(|v| to_u64(v)).unwrap_or(0), + ); + i += 1; + } if let Some(limit) = limit { if count >= limit { break; } } } + if first { + self.global_processor.vendor_id = vendor_id; + self.global_processor.brand = brand; + } } } } @@ -218,6 +235,22 @@ impl SystemExt for System { mem_free: 0, swap_total: 0, swap_free: 0, + global_processor: Processor::new_with_values( + "", + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + String::new(), + String::new(), + ), processors: Vec::with_capacity(4), page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 }, components: Vec::new(), @@ -225,6 +258,9 @@ impl SystemExt for System { networks: Networks::new(), uptime: get_uptime(), }; + if !refreshes.cpu() { + s.refresh_processors(None); // We need the processors to be filled. + } s.refresh_specifics(refreshes); s } @@ -291,12 +327,11 @@ impl SystemExt for System { }; if found && !self.processors.is_empty() { self.refresh_processors(Some(1)); - let (new, old) = get_raw_times(&self.processors[0]); + let (new, old) = get_raw_times(&self.global_processor); let total_time = (if old > new { 1 } else { new - old }) as f32; - let nb_processors = self.processors.len() as u64 - 1; if let Some(p) = self.process_list.tasks.get_mut(&pid) { - compute_cpu_usage(p, nb_processors, total_time); + compute_cpu_usage(p, self.processors.len() as u64, total_time); } } found @@ -326,8 +361,12 @@ impl SystemExt for System { &mut self.networks } + fn get_global_processor_info(&self) -> &Processor { + &self.global_processor + } + fn get_processors(&self) -> &[Processor] { - &self.processors[..] + &self.processors } fn get_total_memory(&self) -> u64 { diff --git a/src/mac/component.rs b/src/mac/component.rs index 52d953c3f..56db664c7 100644 --- a/src/mac/component.rs +++ b/src/mac/component.rs @@ -55,14 +55,16 @@ impl Component { connection: ffi::io_connect_t, ) -> Option { let ffi_part = ComponentFFI::new(key, connection)?; - ffi_part.get_temperature(connection).map(|temperature| Component { - temperature, - label, - max: max.unwrap_or(0.0), - critical, - ffi_part, - connection, - }) + ffi_part + .get_temperature(connection) + .map(|temperature| Component { + temperature, + label, + max: max.unwrap_or(0.0), + critical, + ffi_part, + connection, + }) } } diff --git a/src/mac/processor.rs b/src/mac/processor.rs index 78db8d08e..d85d821d5 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -4,10 +4,12 @@ // Copyright (c) 2015 Guillaume Gomez // -use libc::c_char; +use libc::{c_char, c_void}; +use std::mem; use std::ops::Deref; use std::sync::Arc; use sys::ffi; +use sys::system::get_sys_value; use ProcessorExt; @@ -130,6 +132,76 @@ pub fn get_cpu_frequency() -> u64 { speed / 1_000_000 } +pub fn init_processors(port: ffi::mach_port_t) -> (Processor, Vec) { + let mut num_cpu = 0; + let mut processors = Vec::new(); + let mut pourcent = 0f32; + let mut mib = [0, 0]; + + let (vendor_id, brand) = get_vendor_id_and_brand(); + let frequency = get_cpu_frequency(); + + unsafe { + if !get_sys_value( + ffi::CTL_HW, + ffi::HW_NCPU, + mem::size_of::(), + &mut num_cpu as *mut usize as *mut c_void, + &mut mib, + ) { + num_cpu = 1; + } + + let mut num_cpu_u = 0u32; + let mut cpu_info: *mut i32 = ::std::ptr::null_mut(); + let mut num_cpu_info = 0u32; + + if ffi::host_processor_info( + port, + ffi::PROCESSOR_CPU_LOAD_INFO, + &mut num_cpu_u as *mut u32, + &mut cpu_info as *mut *mut i32, + &mut num_cpu_info as *mut u32, + ) == ffi::KERN_SUCCESS + { + let proc_data = Arc::new(ProcessorData::new(cpu_info, num_cpu_info)); + for i in 0..num_cpu { + let mut p = Processor::new( + format!("{}", i + 1), + Arc::clone(&proc_data), + frequency, + vendor_id.clone(), + brand.clone(), + ); + let in_use = *cpu_info.offset( + (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize, + ) + *cpu_info.offset( + (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_SYSTEM as isize, + ) + *cpu_info.offset( + (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_NICE as isize, + ); + let total = in_use + + *cpu_info.offset( + (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize, + ); + p.set_cpu_usage(in_use as f32 / total as f32); + pourcent += p.get_cpu_usage(); + processors.push(p); + } + } + } + let mut global_processor = Processor::new( + "0".to_owned(), + Arc::new(ProcessorData::new(::std::ptr::null_mut(), 0)), + frequency, + vendor_id, + brand, + ); + global_processor.set_cpu_usage(pourcent / processors.len() as f32); + + (global_processor, processors) +} + fn get_sysctl_str(s: &[u8]) -> String { let mut len = 0; diff --git a/src/mac/system.rs b/src/mac/system.rs index cd9f1658e..83910aca4 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -29,6 +29,7 @@ pub struct System { mem_free: u64, swap_total: u64, swap_free: u64, + global_processor: Processor, processors: Vec, page_size_kb: u64, components: Vec, @@ -67,24 +68,29 @@ impl System { self.process_list.remove(&pid); } } + } impl SystemExt for System { fn new_with_specifics(refreshes: RefreshKind) -> System { + let port = unsafe { ffi::mach_host_self() }; + let (global_processor, processors) = init_processors(port); + let mut s = System { process_list: HashMap::with_capacity(200), mem_total: 0, mem_free: 0, swap_total: 0, swap_free: 0, - processors: Vec::with_capacity(4), + global_processor, + processors, page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 >> 10 }, // divide by 1024 components: Vec::with_capacity(2), connection: get_io_service_connection(), disks: Vec::with_capacity(1), networks: Networks::new(), uptime: get_uptime(), - port: unsafe { ffi::mach_host_self() }, + port, }; s.refresh_specifics(refreshes); s @@ -168,68 +174,15 @@ impl SystemExt for System { fn refresh_cpu(&mut self) { self.uptime = get_uptime(); - let mut mib = [0, 0]; - unsafe { - // get processor values - let mut num_cpu_u = 0u32; - let mut cpu_info: *mut i32 = ::std::ptr::null_mut(); - let mut num_cpu_info = 0u32; - - if self.processors.is_empty() { - let mut num_cpu = 0; - let (vendor_id, brand) = get_vendor_id_and_brand(); - let frequency = get_cpu_frequency(); + // get processor values + let mut num_cpu_u = 0u32; + let mut cpu_info: *mut i32 = ::std::ptr::null_mut(); + let mut num_cpu_info = 0u32; - if !get_sys_value( - ffi::CTL_HW, - ffi::HW_NCPU, - mem::size_of::(), - &mut num_cpu as *mut usize as *mut c_void, - &mut mib, - ) { - num_cpu = 1; - } + let mut pourcent = 0f32; - self.processors.push(Processor::new( - "0".to_owned(), - Arc::new(ProcessorData::new(::std::ptr::null_mut(), 0)), - frequency, - vendor_id.clone(), - brand.clone(), - )); - if ffi::host_processor_info( - self.port, - ffi::PROCESSOR_CPU_LOAD_INFO, - &mut num_cpu_u as *mut u32, - &mut cpu_info as *mut *mut i32, - &mut num_cpu_info as *mut u32, - ) == ffi::KERN_SUCCESS - { - let proc_data = Arc::new(ProcessorData::new(cpu_info, num_cpu_info)); - for i in 0..num_cpu { - let mut p = Processor::new( - format!("{}", i + 1), - Arc::clone(&proc_data), - frequency, - vendor_id.clone(), - brand.clone(), - ); - let in_use = *cpu_info.offset( - (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize, - ) + *cpu_info.offset( - (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_SYSTEM as isize, - ) + *cpu_info.offset( - (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_NICE as isize, - ); - let total = in_use - + *cpu_info.offset( - (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize, - ); - p.set_cpu_usage(in_use as f32 / total as f32); - self.processors.push(p); - } - } - } else if ffi::host_processor_info( + unsafe { + if ffi::host_processor_info( self.port, ffi::PROCESSOR_CPU_LOAD_INFO, &mut num_cpu_u as *mut u32, @@ -237,9 +190,8 @@ impl SystemExt for System { &mut num_cpu_info as *mut u32, ) == ffi::KERN_SUCCESS { - let mut pourcent = 0f32; let proc_data = Arc::new(ProcessorData::new(cpu_info, num_cpu_info)); - for (i, proc_) in self.processors.iter_mut().skip(1).enumerate() { + for (i, proc_) in self.processors.iter_mut().enumerate() { let old_proc_data = &*proc_.get_data(); let in_use = (*cpu_info.offset( @@ -264,14 +216,9 @@ impl SystemExt for System { proc_.update(in_use as f32 / total as f32, Arc::clone(&proc_data)); pourcent += proc_.get_cpu_usage(); } - if self.processors.len() > 1 { - let len = self.processors.len() - 1; - if let Some(p) = self.processors.get_mut(0) { - p.set_cpu_usage(pourcent / len as f32); - } - } } } + self.global_processor.set_cpu_usage(pourcent / self.processors.len() as f32); } fn refresh_processes(&mut self) { @@ -328,8 +275,12 @@ impl SystemExt for System { self.process_list.get(&pid) } + fn get_global_processor_info(&self) -> &Processor { + &self.global_processor + } + fn get_processors(&self) -> &[Processor] { - &self.processors[..] + &self.processors } fn get_networks(&self) -> &Networks { @@ -483,7 +434,7 @@ fn get_arg_max() -> usize { } } -unsafe fn get_sys_value( +pub(crate) unsafe fn get_sys_value( high: u32, low: u32, mut len: usize, diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 218197151..e57eb2e0b 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -80,9 +80,7 @@ cfg_if! { } pub use common::{AsU32, DiskType, NetworksIter, Pid, RefreshKind}; -pub use sys::{ - Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System, -}; +pub use sys::{Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System}; pub use traits::{ ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, }; diff --git a/src/traits.rs b/src/traits.rs index 62d8bba1b..0df02e2f5 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -679,7 +679,17 @@ pub trait SystemExt: Sized { ret } - /// The first processor in the array is the "main" one (aka the addition of all the others). + /// Returns "global" processors information (aka the addition of all the processors). + /// + /// ```no_run + /// use sysinfo::{ProcessorExt, System, SystemExt}; + /// + /// let s = System::new_all(); + /// println!("{}%", s.get_global_processor_info().get_cpu_usage()); + /// ``` + fn get_global_processor_info(&self) -> &Processor; + + /// Returns the list of the processors. /// /// ```no_run /// use sysinfo::{ProcessorExt, System, SystemExt}; diff --git a/src/unknown/processor.rs b/src/unknown/processor.rs index dab8d5947..5fd8ecde4 100644 --- a/src/unknown/processor.rs +++ b/src/unknown/processor.rs @@ -12,6 +12,12 @@ use ProcessorExt; /// Dummy struct that represents a processor. pub struct Processor {} +impl Processor { + pub(crate) fn new() -> Processor { + Processor {} + } +} + impl ProcessorExt for Processor { fn get_cpu_usage(&self) -> f32 { 0.0 diff --git a/src/unknown/system.rs b/src/unknown/system.rs index a3e3c8724..a14468b46 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -19,6 +19,7 @@ use std::collections::HashMap; pub struct System { processes_list: HashMap, networks: Networks, + global_processor: Processor, } impl SystemExt for System { @@ -26,6 +27,7 @@ impl SystemExt for System { System { processes_list: Default::default(), networks: Networks::new(), + global_processor: Processor::new{}, } } @@ -65,6 +67,10 @@ impl SystemExt for System { &mut self.networks } + fn get_global_processor_info(&self) -> &Processor { + &self.global_processor + } + fn get_processors(&self) -> &[Processor] { &[] } diff --git a/src/windows/system.rs b/src/windows/system.rs index c00a8c359..3eb30b22a 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -46,6 +46,7 @@ pub struct System { mem_free: u64, swap_total: u64, swap_free: u64, + global_processor: Processor, processors: Vec, components: Vec, disks: Vec, @@ -63,13 +64,15 @@ unsafe impl Sync for Wrap {} impl SystemExt for System { #[allow(non_snake_case)] fn new_with_specifics(refreshes: RefreshKind) -> System { + let (processors, vendor_id, brand) = init_processors(); let mut s = System { process_list: HashMap::with_capacity(500), mem_total: 0, mem_free: 0, swap_total: 0, swap_free: 0, - processors: init_processors(), + global_processor: Processor::new_with_values("Total CPU", vendor_id, brand, 0), + processors, components: Vec::new(), disks: Vec::with_capacity(2), query: Query::new(), @@ -86,7 +89,7 @@ impl SystemExt for System { add_counter( format!("\\{}(_Total)\\{}", processor_trans, proc_time_trans), query, - get_key_used(&mut s.processors[0]), + get_key_used(&mut s.global_processor), "tot_0".to_owned(), CounterValue::Float(0.), ); @@ -95,12 +98,12 @@ impl SystemExt for System { add_counter( format!("\\{}(_Total)\\{}", processor_trans, idle_time_trans), query, - get_key_idle(&mut s.processors[0]), + get_key_idle(&mut s.global_processor), "tot_1".to_owned(), CounterValue::Float(0.), ); } - for (pos, proc_) in s.processors.iter_mut().skip(1).enumerate() { + for (pos, proc_) in s.processors.iter_mut().enumerate() { if let Some(ref proc_time_trans) = proc_time_trans { add_counter( format!("\\{}({})\\{}", processor_trans, pos, proc_time_trans), @@ -138,6 +141,13 @@ impl SystemExt for System { p.set_cpu_usage(1. - idle_time); } } + let mut idle_time = None; + if let &mut Some(ref key_idle) = get_key_idle(&mut self.global_processor) { + idle_time = Some(query.get(&key_idle.unique_id).expect("key disappeared")); + } + if let Some(idle_time) = idle_time { + self.global_processor.set_cpu_usage(1. - idle_time); + } } } @@ -299,8 +309,12 @@ impl SystemExt for System { self.process_list.get(&(pid as usize)) } + fn get_global_processor_info(&self) -> &Processor { + &self.global_processor + } + fn get_processors(&self) -> &[Processor] { - &self.processors[..] + &self.processors } fn get_total_memory(&self) -> u64 { diff --git a/src/windows/tools.rs b/src/windows/tools.rs index 8a8ba94a7..49ded9ee1 100644 --- a/src/windows/tools.rs +++ b/src/windows/tools.rs @@ -6,8 +6,8 @@ use windows::processor::{self, CounterValue, Processor, Query}; -use DiskType; use sys::disk::{new_disk, Disk}; +use DiskType; use std::collections::HashMap; use std::ffi::OsStr; @@ -45,7 +45,7 @@ impl KeyHandler { } } -pub fn init_processors() -> Vec { +pub fn init_processors() -> (Vec, String, String) { unsafe { let mut sys_info: SYSTEM_INFO = zeroed(); GetSystemInfo(&mut sys_info); @@ -60,11 +60,7 @@ pub fn init_processors() -> Vec { frequencies[nb as usize], )); } - ret.insert( - 0, - Processor::new_with_values("Total CPU", vendor_id, brand, 0), - ); - ret + (ret, vendor_id, brand) } } diff --git a/tests/disk_list.rs b/tests/disk_list.rs index d59e4f141..9b49dbfd5 100644 --- a/tests/disk_list.rs +++ b/tests/disk_list.rs @@ -12,5 +12,5 @@ fn test_disks() { let s = sysinfo::System::new(); println!("total memory: {}", s.get_total_memory()); - println!("total cpu cores: {}", s.get_processor_list().len()); + println!("total cpu cores: {}", s.get_processors().len()); } From ec2d72fb20bcc5645ca8096d74b63faa832c3c50 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 7 Feb 2020 16:51:49 +0100 Subject: [PATCH 143/171] Add test to ensure that processor list is always set when initializing System --- tests/processor.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/processor.rs diff --git a/tests/processor.rs b/tests/processor.rs new file mode 100644 index 000000000..39cafd696 --- /dev/null +++ b/tests/processor.rs @@ -0,0 +1,20 @@ +// +// Sysinfo +// +// Copyright (c) 2020 Guillaume Gomez +// + +// This test is used to ensure that the processors are loaded whatever the method +// used to initialize `System`. + +extern crate sysinfo; + +#[test] +fn test_processor() { + use sysinfo::SystemExt; + + let s = sysinfo::System::new(); + assert!(s.get_processors().len() > 0); + let s = sysinfo::System::new_all(); + assert!(s.get_processors().len() > 0); +} From aa55099f4eef49c10a9bc33e8cfb52884cfef2d8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 7 Feb 2020 16:53:41 +0100 Subject: [PATCH 144/171] Ensure that System::new doesn't generate Process list --- tests/process.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/process.rs b/tests/process.rs index caaf6dc07..869a1957a 100644 --- a/tests/process.rs +++ b/tests/process.rs @@ -13,6 +13,7 @@ fn test_process() { use sysinfo::SystemExt; let mut s = sysinfo::System::new(); + assert_eq!(s.get_process_list().len(), 0); s.refresh_processes(); assert!(s.get_process_list().len() != 0); #[cfg(not(windows))] From 08ce43f17605ef8a678fd0888d6973545087d6a2 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 8 Feb 2020 00:34:14 +0100 Subject: [PATCH 145/171] Fix cpu computation --- src/windows/processor.rs | 120 ++++++++++++--------------------------- src/windows/system.rs | 48 +++++----------- src/windows/tools.rs | 5 +- 3 files changed, 54 insertions(+), 119 deletions(-) diff --git a/src/windows/processor.rs b/src/windows/processor.rs index 42d175849..db81e1062 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; use std::mem; use std::ops::DerefMut; use std::ptr::null_mut; -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; use windows::tools::KeyHandler; use LoadAvg; @@ -20,7 +20,7 @@ use winapi::shared::minwindef::FALSE; use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::handleapi::CloseHandle; use winapi::um::pdh::{ - PdhAddCounterW, PdhAddEnglishCounterA, PdhCloseQuery, PdhCollectQueryDataEx, + PdhAddCounterW, PdhAddEnglishCounterA, PdhCloseQuery, PdhCollectQueryData, PdhCollectQueryDataEx, PdhGetFormattedCounterValue, PdhOpenQueryA, PdhRemoveCounter, PDH_FMT_COUNTERVALUE, PDH_FMT_DOUBLE, PDH_HCOUNTER, PDH_HQUERY, }; @@ -120,51 +120,10 @@ unsafe fn init_load_avg() -> Mutex> { } } -#[derive(Debug)] -pub enum CounterValue { - Float(f32), - Integer(u64), -} - -impl CounterValue { - pub fn get_f32(&self) -> f32 { - match *self { - CounterValue::Float(v) => v, - _ => panic!("not a float"), - } - } -} - -#[allow(dead_code)] -#[derive(Debug)] -struct Counter { - counter: PDH_HCOUNTER, - value: CounterValue, - getter: Vec, -} - -impl Counter { - fn new_f32(counter: PDH_HCOUNTER, value: f32, getter: Vec) -> Counter { - Counter { - counter: counter, - value: CounterValue::Float(value), - getter: getter, - } - } - - fn new_u64(counter: PDH_HCOUNTER, value: u64, getter: Vec) -> Counter { - Counter { - counter: counter, - value: CounterValue::Integer(value), - getter: getter, - } - } -} - struct InternalQuery { query: PDH_HQUERY, event: HANDLE, - data: Mutex>, + data: HashMap, } unsafe impl Send for InternalQuery {} @@ -173,10 +132,8 @@ unsafe impl Sync for InternalQuery {} impl Drop for InternalQuery { fn drop(&mut self) { unsafe { - if let Ok(ref data) = self.data.lock() { - for (_, counter) in data.iter() { - PdhRemoveCounter(counter.counter); - } + for (_, counter) in self.data.iter() { + PdhRemoveCounter(*counter); } if !self.event.is_null() { @@ -191,7 +148,7 @@ impl Drop for InternalQuery { } pub struct Query { - internal: Arc, + internal: InternalQuery, } impl Query { @@ -199,19 +156,12 @@ impl Query { let mut query = null_mut(); unsafe { if PdhOpenQueryA(null_mut(), 0, &mut query) == ERROR_SUCCESS as i32 { - let event = - CreateEventA(null_mut(), FALSE, FALSE, b"some_ev\0".as_ptr() as *const i8); - if event.is_null() { - PdhCloseQuery(query); - None - } else { - let q = Arc::new(InternalQuery { - query: query, - event: event, - data: Mutex::new(HashMap::new()), - }); - Some(Query { internal: q }) - } + let q = InternalQuery { + query, + event: null_mut(), + data: HashMap::new(), + }; + Some(Query { internal: q }) } else { None } @@ -219,34 +169,36 @@ impl Query { } pub fn get(&self, name: &String) -> Option { - if let Ok(data) = self.internal.data.lock() { - if let Some(ref counter) = data.get(name) { - return Some(counter.value.get_f32()); + if let Some(ref counter) = self.internal.data.get(name) { + unsafe { + let mut display_value: PDH_FMT_COUNTERVALUE = mem::MaybeUninit::uninit().assume_init(); + let counter: PDH_HCOUNTER = **counter; + + let ret = PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, null_mut(), &mut display_value) as u32; + return if ret == ERROR_SUCCESS as _ { + let data = *display_value.u.doubleValue(); + Some(data as f32) + } else { + Some(0.) + }; } } None } - pub fn add_counter(&mut self, name: &String, getter: Vec, value: CounterValue) -> bool { - if let Ok(data) = self.internal.data.lock() { - if data.contains_key(name) { - return false; - } + pub fn add_counter(&mut self, name: &String, getter: Vec) -> bool { + if self.internal.data.contains_key(name) { + return false; } unsafe { let mut counter: PDH_HCOUNTER = ::std::mem::zeroed(); let ret = PdhAddCounterW(self.internal.query, getter.as_ptr(), 0, &mut counter); - if ret == ERROR_SUCCESS as i32 { + if ret == ERROR_SUCCESS as _ { self.internal .data - .lock() - .expect("couldn't add counter...") .insert( name.clone(), - match value { - CounterValue::Float(v) => Counter::new_f32(counter, v, getter), - CounterValue::Integer(v) => Counter::new_u64(counter, v, getter), - }, + counter, ); } else { eprintln!("failed to add counter '{}': {:x}...", name, ret); @@ -255,13 +207,20 @@ impl Query { } true } + + pub fn refresh(&self) { + unsafe { + if PdhCollectQueryData(self.internal.query) != ERROR_SUCCESS as _ { + eprintln!("failed to refresh CPU data"); + } + } + } } /// Struct containing a processor information. pub struct Processor { name: String, cpu_usage: f32, - key_idle: Option, key_used: Option, vendor_id: String, brand: String, @@ -300,7 +259,6 @@ impl Processor { Processor { name: name.to_owned(), cpu_usage: 0f32, - key_idle: None, key_used: None, vendor_id, brand, @@ -411,10 +369,6 @@ pub fn get_vendor_id_and_brand(info: &SYSTEM_INFO) -> (String, String) { (get_vendor_id_not_great(info), String::new()) } -pub fn get_key_idle(p: &mut Processor) -> &mut Option { - &mut p.key_idle -} - pub fn get_key_used(p: &mut Processor) -> &mut Option { &mut p.key_used } diff --git a/src/windows/system.rs b/src/windows/system.rs index 3eb30b22a..84186dd89 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -23,7 +23,6 @@ use SystemExt; use windows::process::{ compute_cpu_usage, get_handle, get_system_computation_time, update_proc_info, Process, }; -use windows::processor::CounterValue; use windows::tools::*; use ntapi::ntexapi::{ @@ -91,16 +90,6 @@ impl SystemExt for System { query, get_key_used(&mut s.global_processor), "tot_0".to_owned(), - CounterValue::Float(0.), - ); - } - if let Some(ref idle_time_trans) = idle_time_trans { - add_counter( - format!("\\{}(_Total)\\{}", processor_trans, idle_time_trans), - query, - get_key_idle(&mut s.global_processor), - "tot_1".to_owned(), - CounterValue::Float(0.), ); } for (pos, proc_) in s.processors.iter_mut().enumerate() { @@ -110,19 +99,11 @@ impl SystemExt for System { query, get_key_used(proc_), format!("{}_0", pos), - CounterValue::Float(0.), - ); - } - if let Some(ref idle_time_trans) = idle_time_trans { - add_counter( - format!("\\{}({})\\{}", processor_trans, pos, idle_time_trans), - query, - get_key_idle(proc_), - format!("{}_1", pos), - CounterValue::Float(0.), ); } } + } else { + eprintln!("failed to get `Processor` translation"); } } s.refresh_specifics(refreshes); @@ -132,22 +113,23 @@ impl SystemExt for System { fn refresh_cpu(&mut self) { self.uptime = get_uptime(); if let Some(ref mut query) = self.query { + query.refresh(); + let mut used_time = None; + if let &mut Some(ref key_used) = get_key_used(&mut self.global_processor) { + used_time = Some(query.get(&key_used.unique_id).expect("global_key_idle disappeared")); + } + if let Some(used_time) = used_time { + self.global_processor.set_cpu_usage(used_time); + } for p in self.processors.iter_mut() { - let mut idle_time = None; - if let &mut Some(ref key_idle) = get_key_idle(p) { - idle_time = Some(query.get(&key_idle.unique_id).expect("key disappeared")); + let mut used_time = None; + if let &mut Some(ref key_used) = get_key_used(p) { + used_time = Some(query.get(&key_used.unique_id).expect("key_used disappeared")); } - if let Some(idle_time) = idle_time { - p.set_cpu_usage(1. - idle_time); + if let Some(used_time) = used_time { + p.set_cpu_usage(used_time); } } - let mut idle_time = None; - if let &mut Some(ref key_idle) = get_key_idle(&mut self.global_processor) { - idle_time = Some(query.get(&key_idle.unique_id).expect("key disappeared")); - } - if let Some(idle_time) = idle_time { - self.global_processor.set_cpu_usage(1. - idle_time); - } } } diff --git a/src/windows/tools.rs b/src/windows/tools.rs index 49ded9ee1..18565fda4 100644 --- a/src/windows/tools.rs +++ b/src/windows/tools.rs @@ -4,7 +4,7 @@ // Copyright (c) 2018 Guillaume Gomez // -use windows::processor::{self, CounterValue, Processor, Query}; +use windows::processor::{self, Processor, Query}; use sys::disk::{new_disk, Disk}; use DiskType; @@ -315,11 +315,10 @@ pub fn add_counter( query: &mut Query, keys: &mut Option, counter_name: String, - value: CounterValue, ) { let mut full = s.encode_utf16().collect::>(); full.push(0); - if query.add_counter(&counter_name, full.clone(), value) { + if query.add_counter(&counter_name, full.clone()) { *keys = Some(KeyHandler::new(counter_name, full)); } } From 756cdb557ce04dc589f922cddf12ee0a1e32b766 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 8 Feb 2020 00:34:32 +0100 Subject: [PATCH 146/171] get_cpu_usage now returns a value between 0 and 100 --- src/linux/processor.rs | 2 +- src/mac/processor.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linux/processor.rs b/src/linux/processor.rs index daf2e836d..6454fc82b 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -194,7 +194,7 @@ impl Processor { user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice, ); self.cpu_usage = min(self.new_values.work_time(), self.old_values.work_time()) - / min(self.new_values.total_time(), self.old_values.total_time()); + / min(self.new_values.total_time(), self.old_values.total_time()) * 100.; self.old_total_time = self.old_values.total_time(); self.total_time = self.new_values.total_time(); } diff --git a/src/mac/processor.rs b/src/mac/processor.rs index d85d821d5..feee6d515 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -184,7 +184,7 @@ pub fn init_processors(port: ffi::mach_port_t) -> (Processor, Vec) { + *cpu_info.offset( (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize, ); - p.set_cpu_usage(in_use as f32 / total as f32); + p.set_cpu_usage(in_use as f32 / total as f32 * 100.); pourcent += p.get_cpu_usage(); processors.push(p); } From 518abbee7048b6d75ac98c75b16c543d2bdbc27c Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Sat, 8 Feb 2020 00:38:46 +0100 Subject: [PATCH 147/171] fmt --- src/linux/processor.rs | 3 ++- src/mac/processor.rs | 18 ++++++++---------- src/mac/system.rs | 4 ++-- src/unknown/system.rs | 2 +- src/windows/processor.rs | 25 +++++++++++++------------ src/windows/system.rs | 12 ++++++++++-- 6 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/linux/processor.rs b/src/linux/processor.rs index 6454fc82b..df2027dc5 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -194,7 +194,8 @@ impl Processor { user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice, ); self.cpu_usage = min(self.new_values.work_time(), self.old_values.work_time()) - / min(self.new_values.total_time(), self.old_values.total_time()) * 100.; + / min(self.new_values.total_time(), self.old_values.total_time()) + * 100.; self.old_total_time = self.old_values.total_time(); self.total_time = self.new_values.total_time(); } diff --git a/src/mac/processor.rs b/src/mac/processor.rs index feee6d515..b325751b7 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -173,17 +173,15 @@ pub fn init_processors(port: ffi::mach_port_t) -> (Processor, Vec) { vendor_id.clone(), brand.clone(), ); - let in_use = *cpu_info.offset( - (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize, - ) + *cpu_info.offset( - (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_SYSTEM as isize, - ) + *cpu_info.offset( - (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_NICE as isize, - ); + let in_use = *cpu_info + .offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize) + + *cpu_info + .offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_SYSTEM as isize) + + *cpu_info + .offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_NICE as isize); let total = in_use - + *cpu_info.offset( - (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize, - ); + + *cpu_info + .offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize); p.set_cpu_usage(in_use as f32 / total as f32 * 100.); pourcent += p.get_cpu_usage(); processors.push(p); diff --git a/src/mac/system.rs b/src/mac/system.rs index 83910aca4..a7925ab82 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -68,7 +68,6 @@ impl System { self.process_list.remove(&pid); } } - } impl SystemExt for System { @@ -218,7 +217,8 @@ impl SystemExt for System { } } } - self.global_processor.set_cpu_usage(pourcent / self.processors.len() as f32); + self.global_processor + .set_cpu_usage(pourcent / self.processors.len() as f32); } fn refresh_processes(&mut self) { diff --git a/src/unknown/system.rs b/src/unknown/system.rs index a14468b46..9ceeb3d26 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -27,7 +27,7 @@ impl SystemExt for System { System { processes_list: Default::default(), networks: Networks::new(), - global_processor: Processor::new{}, + global_processor: Processor::new {}, } } diff --git a/src/windows/processor.rs b/src/windows/processor.rs index db81e1062..0833eb64d 100644 --- a/src/windows/processor.rs +++ b/src/windows/processor.rs @@ -20,9 +20,9 @@ use winapi::shared::minwindef::FALSE; use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::handleapi::CloseHandle; use winapi::um::pdh::{ - PdhAddCounterW, PdhAddEnglishCounterA, PdhCloseQuery, PdhCollectQueryData, PdhCollectQueryDataEx, - PdhGetFormattedCounterValue, PdhOpenQueryA, PdhRemoveCounter, PDH_FMT_COUNTERVALUE, - PDH_FMT_DOUBLE, PDH_HCOUNTER, PDH_HQUERY, + PdhAddCounterW, PdhAddEnglishCounterA, PdhCloseQuery, PdhCollectQueryData, + PdhCollectQueryDataEx, PdhGetFormattedCounterValue, PdhOpenQueryA, PdhRemoveCounter, + PDH_FMT_COUNTERVALUE, PDH_FMT_DOUBLE, PDH_HCOUNTER, PDH_HQUERY, }; use winapi::um::powerbase::CallNtPowerInformation; use winapi::um::synchapi::CreateEventA; @@ -171,10 +171,16 @@ impl Query { pub fn get(&self, name: &String) -> Option { if let Some(ref counter) = self.internal.data.get(name) { unsafe { - let mut display_value: PDH_FMT_COUNTERVALUE = mem::MaybeUninit::uninit().assume_init(); + let mut display_value: PDH_FMT_COUNTERVALUE = + mem::MaybeUninit::uninit().assume_init(); let counter: PDH_HCOUNTER = **counter; - let ret = PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, null_mut(), &mut display_value) as u32; + let ret = PdhGetFormattedCounterValue( + counter, + PDH_FMT_DOUBLE, + null_mut(), + &mut display_value, + ) as u32; return if ret == ERROR_SUCCESS as _ { let data = *display_value.u.doubleValue(); Some(data as f32) @@ -194,12 +200,7 @@ impl Query { let mut counter: PDH_HCOUNTER = ::std::mem::zeroed(); let ret = PdhAddCounterW(self.internal.query, getter.as_ptr(), 0, &mut counter); if ret == ERROR_SUCCESS as _ { - self.internal - .data - .insert( - name.clone(), - counter, - ); + self.internal.data.insert(name.clone(), counter); } else { eprintln!("failed to add counter '{}': {:x}...", name, ret); return false; @@ -209,7 +210,7 @@ impl Query { } pub fn refresh(&self) { - unsafe { + unsafe { if PdhCollectQueryData(self.internal.query) != ERROR_SUCCESS as _ { eprintln!("failed to refresh CPU data"); } diff --git a/src/windows/system.rs b/src/windows/system.rs index 84186dd89..2ef51d5b5 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -116,7 +116,11 @@ impl SystemExt for System { query.refresh(); let mut used_time = None; if let &mut Some(ref key_used) = get_key_used(&mut self.global_processor) { - used_time = Some(query.get(&key_used.unique_id).expect("global_key_idle disappeared")); + used_time = Some( + query + .get(&key_used.unique_id) + .expect("global_key_idle disappeared"), + ); } if let Some(used_time) = used_time { self.global_processor.set_cpu_usage(used_time); @@ -124,7 +128,11 @@ impl SystemExt for System { for p in self.processors.iter_mut() { let mut used_time = None; if let &mut Some(ref key_used) = get_key_used(p) { - used_time = Some(query.get(&key_used.unique_id).expect("key_used disappeared")); + used_time = Some( + query + .get(&key_used.unique_id) + .expect("key_used disappeared"), + ); } if let Some(used_time) = used_time { p.set_cpu_usage(used_time); From 702467240cd9ea968bf181c6a7ba0390772e4282 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Feb 2020 11:52:27 +0100 Subject: [PATCH 148/171] Fix CPU usage computation on mac --- src/mac/system.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mac/system.rs b/src/mac/system.rs index a7925ab82..9db0aa713 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -212,7 +212,7 @@ impl SystemExt for System { ) - *old_proc_data.cpu_info.offset( (ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize, )); - proc_.update(in_use as f32 / total as f32, Arc::clone(&proc_data)); + proc_.update(in_use as f32 / total as f32 * 100., Arc::clone(&proc_data)); pourcent += proc_.get_cpu_usage(); } } From 6931572652ac97283ed9ad3758db1719b5b8c244 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Feb 2020 12:10:56 +0100 Subject: [PATCH 149/171] remove warning --- src/windows/system.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows/system.rs b/src/windows/system.rs index 2ef51d5b5..739d8748d 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -82,7 +82,7 @@ impl SystemExt for System { if let Some(ref mut query) = s.query { let x = unsafe { load_symbols() }; if let Some(processor_trans) = get_translation(&"Processor".to_owned(), &x) { - let idle_time_trans = get_translation(&"% Idle Time".to_owned(), &x); + // let idle_time_trans = get_translation(&"% Idle Time".to_owned(), &x); let proc_time_trans = get_translation(&"% Processor Time".to_owned(), &x); if let Some(ref proc_time_trans) = proc_time_trans { add_counter( From e3b21da78491901ea22eb3be408824c9ef487503 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Feb 2020 12:11:14 +0100 Subject: [PATCH 150/171] Update example --- examples/src/simple.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index 2d469de56..a5074700f 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -79,7 +79,7 @@ fn print_help() { ); writeln!( &mut io::stdout(), - "procd : Displays processors state" + "processors : Displays processors state" ); writeln!( &mut io::stdout(), @@ -140,17 +140,15 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { nb += 1; } } - "procs" => { + "processors" => { // Note: you should refresh a few times before using this, so that usage statistics // can be ascertained - let procs = sys.get_processors(); - writeln!( &mut io::stdout(), "total process usage: {}%", - procs[0].get_cpu_usage() + sys.get_global_processor_info().get_cpu_usage() ); - for proc_ in procs.iter().skip(1) { + for proc_ in sys.get_processors() { writeln!(&mut io::stdout(), "{:?}", proc_); } } From 15893ee642e690c20e87c1264d57047d7668d6ae Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Feb 2020 12:13:06 +0100 Subject: [PATCH 151/171] Improve documentation --- src/traits.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 0df02e2f5..6fdce020d 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -365,9 +365,9 @@ pub trait ProcessorExt { /// Contains all the methods of the [`System`][crate::System] type. pub trait SystemExt: Sized { - /// Creates a new [`System`] instance with nothing loaded. If you want to load components, - /// network interfaces or the disks, you'll have to use the `refresh_*_list` methods. - /// [`SystemExt::refresh_networks_list`] for example. + /// Creates a new [`System`] instance with nothing loaded except the processors list. If you + /// want to load components, network interfaces or the disks, you'll have to use the + /// `refresh_*_list` methods. [`SystemExt::refresh_networks_list`] for example. /// /// Use the [`refresh_all`] method to update its internal information (or any of the `refresh_` /// method). @@ -684,7 +684,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{ProcessorExt, System, SystemExt}; /// - /// let s = System::new_all(); + /// let s = System::new(); /// println!("{}%", s.get_global_processor_info().get_cpu_usage()); /// ``` fn get_global_processor_info(&self) -> &Processor; @@ -694,7 +694,7 @@ pub trait SystemExt: Sized { /// ```no_run /// use sysinfo::{ProcessorExt, System, SystemExt}; /// - /// let s = System::new_all(); + /// let s = System::new(); /// for processor in s.get_processors() { /// println!("{}%", processor.get_cpu_usage()); /// } From b32e4f370d71dc7c0aa26c33bedd66db4df25cd2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Feb 2020 12:43:16 +0100 Subject: [PATCH 152/171] Rename get_process_list into get_processes --- examples/src/simple.rs | 2 +- src/c_interface.rs | 6 +++--- src/common.rs | 2 +- src/linux/system.rs | 2 +- src/mac/system.rs | 2 +- src/sysinfo.rs | 4 ++-- src/system.rs | 2 +- src/traits.rs | 8 ++++---- src/unknown/system.rs | 2 +- src/windows/system.rs | 2 +- tests/process.rs | 6 +++--- 11 files changed, 19 insertions(+), 19 deletions(-) diff --git a/examples/src/simple.rs b/examples/src/simple.rs index a5074700f..a28ce212e 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -176,7 +176,7 @@ fn interpret_input(input: &str, sys: &mut System) -> bool { } "quit" | "exit" => return true, "all" => { - for (pid, proc_) in sys.get_process_list() { + for (pid, proc_) in sys.get_processes() { writeln!( &mut io::stdout(), "{}:{} status={:?}", diff --git a/src/c_interface.rs b/src/c_interface.rs index 6552e8a46..78ac3d612 100644 --- a/src/c_interface.rs +++ b/src/c_interface.rs @@ -15,7 +15,7 @@ pub type CSystem = *mut c_void; pub type CProcess = *const c_void; /// C string returned from `CString::into_raw`. pub type RString = *const c_char; -/// Callback used by [`get_process_list`][crate::System#method.get_process_list]. +/// Callback used by [`get_processes`][crate::System#method.get_processes]. pub type ProcessLoop = extern "C" fn(pid: pid_t, process: CProcess, data: *mut c_void) -> bool; /// Equivalent of [`System::new()`][crate::System#method.new]. @@ -262,7 +262,7 @@ pub extern "C" fn sysinfo_get_processors_usage( Box::into_raw(system); } -/// Equivalent of [`System::get_process_list()`][crate::System#method.get_process_list]. Returns an +/// Equivalent of [`System::get_processes()`][crate::System#method.get_processes]. Returns an /// array ended by a null pointer. Must be freed. /// /// # /!\ WARNING /!\ @@ -278,7 +278,7 @@ pub extern "C" fn sysinfo_get_processes( if let Some(fn_pointer) = fn_pointer { let system: Box = unsafe { Box::from_raw(system as *mut System) }; let len = { - let entries = system.get_process_list(); + let entries = system.get_processes(); for (pid, process) in entries { if !fn_pointer(*pid, process as *const Process as CProcess, data) { break; diff --git a/src/common.rs b/src/common.rs index e59c7a7d3..32479dafc 100644 --- a/src/common.rs +++ b/src/common.rs @@ -112,7 +112,7 @@ assert_eq!(r.", stringify!($name), "(), false); /// let mut system = System::new_with_specifics(RefreshKind::everything().without_disks_list()); /// /// assert_eq!(system.get_disks().len(), 0); -/// assert!(system.get_process_list().len() > 0); +/// assert!(system.get_processes().len() > 0); /// ``` /// /// [`System`]: crate::System diff --git a/src/linux/system.rs b/src/linux/system.rs index 455faf060..392ba6091 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -345,7 +345,7 @@ impl SystemExt for System { // // Need to be moved into a "common" file to avoid duplication. - fn get_process_list(&self) -> &HashMap { + fn get_processes(&self) -> &HashMap { &self.process_list.tasks } diff --git a/src/mac/system.rs b/src/mac/system.rs index 9db0aa713..a5b855978 100644 --- a/src/mac/system.rs +++ b/src/mac/system.rs @@ -267,7 +267,7 @@ impl SystemExt for System { // // Need to be moved into a "common" file to avoid duplication. - fn get_process_list(&self) -> &HashMap { + fn get_processes(&self) -> &HashMap { &self.process_list } diff --git a/src/sysinfo.rs b/src/sysinfo.rs index e57eb2e0b..a5a280dc0 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -20,7 +20,7 @@ //! system.refresh_all(); //! //! // Now let's print every process' id and name: -//! for (pid, proc_) in system.get_process_list() { +//! for (pid, proc_) in system.get_processes() { //! println!("{}:{} => status: {:?}", pid, proc_.name(), proc_.status()); //! } //! @@ -230,7 +230,7 @@ mod test { s.refresh_all(); assert_eq!( - s.get_process_list() + s.get_processes() .iter() .all(|(_, proc_)| proc_.memory() == 0), false diff --git a/src/system.rs b/src/system.rs index dd848ed27..27f7682b4 100644 --- a/src/system.rs +++ b/src/system.rs @@ -26,7 +26,7 @@ mod tests { fn test_refresh_process() { let mut sys = System::new(); assert!( - sys.get_process_list().is_empty(), + sys.get_processes().is_empty(), "no process should be listed!" ); sys.refresh_processes(); diff --git a/src/traits.rs b/src/traits.rs index 6fdce020d..b1dfdd589 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -413,7 +413,7 @@ pub trait SystemExt: Sized { /// let mut system = System::new_with_specifics(RefreshKind::everything().without_disks_list()); /// /// assert_eq!(system.get_disks().len(), 0); - /// assert!(system.get_process_list().len() > 0); + /// assert!(system.get_processes().len() > 0); /// /// // If you want the disks list afterwards, just call the corresponding /// // "refresh_disks_list": @@ -641,11 +641,11 @@ pub trait SystemExt: Sized { /// use sysinfo::{ProcessExt, System, SystemExt}; /// /// let s = System::new_all(); - /// for (pid, process) in s.get_process_list() { + /// for (pid, process) in s.get_processes() { /// println!("{} {}", pid, process.name()); /// } /// ``` - fn get_process_list(&self) -> &HashMap; + fn get_processes(&self) -> &HashMap; /// Returns the process corresponding to the given pid or `None` if no such process exists. /// @@ -671,7 +671,7 @@ pub trait SystemExt: Sized { /// ``` fn get_process_by_name(&self, name: &str) -> Vec<&Process> { let mut ret = vec![]; - for val in self.get_process_list().values() { + for val in self.get_processes().values() { if val.name().contains(name) { ret.push(val); } diff --git a/src/unknown/system.rs b/src/unknown/system.rs index 9ceeb3d26..a14ca8799 100644 --- a/src/unknown/system.rs +++ b/src/unknown/system.rs @@ -51,7 +51,7 @@ impl SystemExt for System { // // Need to be moved into a "common" file to avoid duplication. - fn get_process_list(&self) -> &HashMap { + fn get_processes(&self) -> &HashMap { &self.processes_list } diff --git a/src/windows/system.rs b/src/windows/system.rs index 739d8748d..137a0cd8e 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -291,7 +291,7 @@ impl SystemExt for System { self.disks = unsafe { get_disks() }; } - fn get_process_list(&self) -> &HashMap { + fn get_processes(&self) -> &HashMap { &self.process_list } diff --git a/tests/process.rs b/tests/process.rs index 869a1957a..a9b4c2ecd 100644 --- a/tests/process.rs +++ b/tests/process.rs @@ -13,12 +13,12 @@ fn test_process() { use sysinfo::SystemExt; let mut s = sysinfo::System::new(); - assert_eq!(s.get_process_list().len(), 0); + assert_eq!(s.get_processes().len(), 0); s.refresh_processes(); - assert!(s.get_process_list().len() != 0); + assert!(s.get_processes().len() != 0); #[cfg(not(windows))] assert!(s - .get_process_list() + .get_processes() .values() .any(|p| p.exe().to_str().unwrap_or_else(|| "").len() != 0)); } From 6c4472d34eee8d2b094e43e79b548eac2f2feb70 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Feb 2020 15:56:20 +0100 Subject: [PATCH 153/171] Add tests for network --- tests/network.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/network.rs diff --git a/tests/network.rs b/tests/network.rs new file mode 100644 index 000000000..f5bccd25a --- /dev/null +++ b/tests/network.rs @@ -0,0 +1,20 @@ +// +// Sysinfo +// +// Copyright (c) 2020 Guillaume Gomez +// + +// This test is used to ensure that the processors are loaded whatever the method +// used to initialize `System`. + +extern crate sysinfo; + +#[test] +fn test_processor() { + use sysinfo::{NetworksExt, SystemExt}; + + let s = sysinfo::System::new(); + assert_eq!(s.get_networks().iter().count(), 0); + let s = sysinfo::System::new_all(); + assert!(s.get_networks().iter().count() > 0); +} From 3568540d0dd74aa415fda0f939bcc4f9b5d06ccb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Feb 2020 15:56:25 +0100 Subject: [PATCH 154/171] cleanup --- src/process.rs | 7 ------- src/sysinfo.rs | 1 - 2 files changed, 8 deletions(-) delete mode 100644 src/process.rs diff --git a/src/process.rs b/src/process.rs deleted file mode 100644 index 51e833d60..000000000 --- a/src/process.rs +++ /dev/null @@ -1,7 +0,0 @@ -// -// Sysinfo -// -// Copyright (c) 2015 Guillaume Gomez -// - -// Functions 'set_time' and 'has_been_updated' will need to get moved here. diff --git a/src/sysinfo.rs b/src/sysinfo.rs index a5a280dc0..bc5c82c05 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -93,7 +93,6 @@ pub use utils::get_current_pid; mod c_interface; mod common; mod component; -mod process; mod processor; mod system; mod traits; From 47592c6528edeac28a740136e77f06e7a431ce0d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Feb 2020 15:56:37 +0100 Subject: [PATCH 155/171] Upgrade crate version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 79a619271..41ddf47ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sysinfo" -version = "0.10.5" +version = "0.11.0" authors = ["Guillaume Gomez "] description = "Library to handle processes" From 0f9ed16e41f35d39a8801f5cee44471363e93d27 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Feb 2020 16:12:57 +0100 Subject: [PATCH 156/171] Improve crate's description --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 41ddf47ef..754fceb95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "sysinfo" version = "0.11.0" authors = ["Guillaume Gomez "] -description = "Library to handle processes" +description = "Library to get system information such as processes, processors, disks, components and networks" repository = "https://github.com/GuillaumeGomez/sysinfo" license = "MIT" readme = "README.md" From 3def3dbf5fa6e0f06fd46e1f5bedb90954f5a238 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Sun, 9 Feb 2020 22:07:39 -0500 Subject: [PATCH 157/171] Error with network TX on linux --- src/linux/network.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linux/network.rs b/src/linux/network.rs index 9f7378fa0..52328a32a 100644 --- a/src/linux/network.rs +++ b/src/linux/network.rs @@ -219,7 +219,7 @@ impl NetworkExt for NetworkData { } fn get_total_outcome(&self) -> u64 { - self.rx_bytes as u64 + self.tx_bytes as u64 } fn get_packets_income(&self) -> u64 { From d99e542af62046cd51124d72e00f943b59adddeb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 10 Feb 2020 10:18:13 +0100 Subject: [PATCH 158/171] Update crate version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 754fceb95..c7dff0f53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sysinfo" -version = "0.11.0" +version = "0.11.1" authors = ["Guillaume Gomez "] description = "Library to get system information such as processes, processors, disks, components and networks" From 87bab735143224c6c26142e4e090e2faf1a740ef Mon Sep 17 00:00:00 2001 From: Mohamed Belaouad Date: Mon, 10 Feb 2020 12:03:02 +0100 Subject: [PATCH 159/171] Document how to cross compile with proper Cargo configuration --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 528b0f44c..1a613f4ac 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,20 @@ It also compiles for Android but never been tested on it. ### Running on Raspberry -It'll be difficult to build on Raspberry. A good way-around is to be build on Linux before sending it to your Raspberry: +It'll be difficult to build on Raspberry. A good way-around is to be build on Linux before sending it to your Raspberry. + +First install the arm toolchain, for example on Ubuntu: `sudo apt-get install gcc-multilib-arm-linux-gnueabihf`. + +Then configure cargo to use the corresponding toolchain: + +```bash +cat << EOF > ~/.cargo/config +[target.armv7-unknown-linux-gnueabihf] +linker = "arm-linux-gnueabihf-gcc" +EOF +``` + +Finally, cross compile: ```bash rustup target add armv7-unknown-linux-gnueabihf From 7e6410bd718c4d3d974cd536603ee3e2c626ad60 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Mon, 10 Feb 2020 22:07:22 +0100 Subject: [PATCH 160/171] Enforce SystemExt::refresh_process working the same on windows --- src/traits.rs | 2 +- src/windows/process.rs | 203 ++++++++++++++++++++--------------------- src/windows/system.rs | 18 +++- 3 files changed, 114 insertions(+), 109 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index b1dfdd589..750ffee93 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -538,7 +538,7 @@ pub trait SystemExt: Sized { fn refresh_processes(&mut self); /// Refresh *only* the process corresponding to `pid`. Returns `false` if the process doesn't - /// exist or isn't listed. + /// exist. If it isn't listed yet, it'll be added. /// /// ```no_run /// use sysinfo::{System, SystemExt}; diff --git a/src/windows/process.rs b/src/windows/process.rs index f60bbb9c3..04aeaaf7d 100644 --- a/src/windows/process.rs +++ b/src/windows/process.rs @@ -5,9 +5,10 @@ // use std::fmt::{self, Debug, Formatter}; -use std::mem::{size_of, zeroed}; +use std::mem::{size_of, zeroed, MaybeUninit}; use std::ops::Deref; use std::path::{Path, PathBuf}; +use std::ptr::null_mut; use std::str; use libc::{c_uint, c_void, memcpy}; @@ -27,6 +28,7 @@ use winapi::um::winnt::{ HANDLE, /*, PWSTR*/ PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, PROCESS_VM_READ, ULARGE_INTEGER, /*THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION, THREAD_SUSPEND_RESUME,*/ }; +use ntapi::ntpsapi::{NtQueryInformationProcess, ProcessBasicInformation, PROCESS_BASIC_INFORMATION}; /// Enum describing the different status of a process. #[derive(Clone, Copy, Debug)] @@ -130,7 +132,7 @@ unsafe fn get_h_mod(process_handler: HANDLE, h_mod: &mut *mut c_void) -> bool { EnumProcessModulesEx( process_handler, h_mod as *mut *mut c_void as _, - ::std::mem::size_of::() as DWORD, + size_of::() as DWORD, &mut cb_needed, LIST_MODULES_ALL, ) != 0 @@ -157,6 +159,34 @@ unsafe fn get_exe(process_handler: HANDLE, h_mod: *mut c_void) -> PathBuf { } impl Process { + #[allow(clippy::uninit_assumed_init)] + pub(crate) fn new_from_pid(pid: Pid) -> Option { + let process_handler = unsafe { OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid as _) }; + if process_handler.is_null() { + return None; + + let mut info: PROCESS_BASIC_INFORMATION = unsafe { MaybeUninit::uninit().assume_init() }; + if unsafe { NtQueryInformationProcess( + process_handler, + ProcessBasicInformation, + &mut info as *mut _ as *mut _, + size_of::() as _, + null_mut(), + ) } != 0 { + unsafe { CloseHandle(process_handler) }; + return None; + } + Some(Process::new_with_handle( + pid, + if info.InheritedFromUniqueProcessId as usize != 0 { + Some(info.InheritedFromUniqueProcessId as usize) + } else { + None + }, + process_handler, + )) + } + pub(crate) fn new_full( pid: Pid, parent: Option, @@ -164,39 +194,37 @@ impl Process { virtual_memory: u64, name: String, ) -> Process { - if let Some(process_handler) = get_process_handler(pid) { - unsafe { - let mut h_mod = ::std::ptr::null_mut(); - get_h_mod(process_handler, &mut h_mod); - let environ = get_proc_env(process_handler, pid as u32, &name); - - let exe = get_exe(process_handler, h_mod); - let mut root = exe.clone(); - root.pop(); - Process { - handle: HandleWrapper(process_handler), - name, - pid, - parent, - cmd: get_cmd_line(pid), - environ, - exe, - cwd: PathBuf::new(), - root, - status: ProcessStatus::Run, - memory, - virtual_memory, - cpu_usage: 0., - old_cpu: 0, - old_sys_cpu: 0, - old_user_cpu: 0, - start_time: get_start_time(process_handler), - updated: true, - } + if let Some(handle) = get_process_handler(pid) { + let mut h_mod = null_mut(); + unsafe { get_h_mod(handle, &mut h_mod) }; + let environ = unsafe { get_proc_env(handle, pid as u32, &name) }; + + let exe = unsafe { get_exe(handle, h_mod) }; + let mut root = exe.clone(); + root.pop(); + Process { + handle: HandleWrapper(handle), + name, + pid, + parent, + cmd: get_cmd_line(pid), + environ, + exe, + cwd: PathBuf::new(), + root, + status: ProcessStatus::Run, + memory, + virtual_memory, + cpu_usage: 0., + old_cpu: 0, + old_sys_cpu: 0, + old_user_cpu: 0, + start_time: unsafe { get_start_time(handle) }, + updated: true, } } else { Process { - handle: HandleWrapper(::std::ptr::null_mut()), + handle: HandleWrapper(null_mut()), name, pid, parent, @@ -217,6 +245,43 @@ impl Process { } } } + + fn new_with_handle(pid: Pid, parent: Option, process_handler: HANDLE) -> Process { + let mut h_mod = null_mut(); + + unsafe { + let name = if get_h_mod(process_handler, &mut h_mod) { + get_process_name(process_handler, h_mod) + } else { + String::new() + }; + let environ = get_proc_env(process_handler, pid as u32, &name); + + let exe = get_exe(process_handler, h_mod); + let mut root = exe.clone(); + root.pop(); + Process { + handle: HandleWrapper(process_handler), + name, + pid, + parent, + cmd: get_cmd_line(pid), + environ, + exe, + cwd: PathBuf::new(), + root, + status: ProcessStatus::Run, + memory: 0, + virtual_memory: 0, + cpu_usage: 0., + old_cpu: 0, + old_sys_cpu: 0, + old_user_cpu: 0, + start_time: get_start_time(process_handler), + updated: true, + } + } + } } // TODO: it's possible to get environment variables like it's done in @@ -227,43 +292,10 @@ impl Process { impl ProcessExt for Process { fn new(pid: Pid, parent: Option, _: u64) -> Process { if let Some(process_handler) = get_process_handler(pid) { - let mut h_mod = ::std::ptr::null_mut(); - - unsafe { - let name = if get_h_mod(process_handler, &mut h_mod) { - get_process_name(process_handler, h_mod) - } else { - String::new() - }; - let environ = get_proc_env(process_handler, pid as u32, &name); - - let exe = get_exe(process_handler, h_mod); - let mut root = exe.clone(); - root.pop(); - Process { - handle: HandleWrapper(process_handler), - name, - pid, - parent, - cmd: get_cmd_line(pid), - environ, - exe, - cwd: PathBuf::new(), - root, - status: ProcessStatus::Run, - memory: 0, - virtual_memory: 0, - cpu_usage: 0., - old_cpu: 0, - old_sys_cpu: 0, - old_user_cpu: 0, - start_time: get_start_time(process_handler), - updated: true, - } - } + Process::new_with_handle(pid, parent, process_handler) } else { Process { - handle: HandleWrapper(::std::ptr::null_mut()), + handle: HandleWrapper(null_mut()), name: String::new(), pid, parent, @@ -396,41 +428,6 @@ unsafe fn get_start_time(handle: HANDLE) -> u64 { tmp / 10_000_000 - 11_644_473_600 } -/*pub unsafe fn get_parent_process_id(pid: Pid) -> Option { - use winapi::um::tlhelp32::{ - CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS, - }; - - let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - let mut entry: PROCESSENTRY32 = zeroed(); - entry.dwSize = size_of::() as u32; - let mut not_the_end = Process32First(snapshot, &mut entry); - while not_the_end != 0 { - if pid == entry.th32ProcessID as usize { - // TODO: if some day I have the motivation to add threads: - // ListProcessThreads(entry.th32ProcessID); - CloseHandle(snapshot); - return Some(entry.th32ParentProcessID as usize); - } - not_the_end = Process32Next(snapshot, &mut entry); - } - CloseHandle(snapshot); - None -}*/ - -/*fn run_wmi(args: &[&str]) -> Option { - use std::process::Command; - - if let Ok(out) = Command::new("wmic") - .args(args) - .output() { - if out.status.success() { - return Some(String::from_utf8_lossy(&out.stdout).into_owned()); - } - } - None -}*/ - fn get_cmd_line(_pid: Pid) -> Vec { /*let where_req = format!("ProcessId={}", pid); @@ -482,7 +479,7 @@ unsafe fn get_proc_env(_handle: HANDLE, _pid: u32, _name: &str) -> Vec { context.MxCsr as usize as *mut winapi::c_void, x.as_mut_ptr() as *mut winapi::c_void, x.len() as u64, - ::std::ptr::null_mut()) != 0 { + null_mut()) != 0 { for y in x { print!("{}", y as char); } diff --git a/src/windows/system.rs b/src/windows/system.rs index 137a0cd8e..031f97aef 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -176,11 +176,19 @@ impl SystemExt for System { } fn refresh_process(&mut self, pid: Pid) -> bool { - if refresh_existing_process(self, pid, true) == false { - self.process_list.remove(&pid); - false - } else { + if self.process_list.contains_key(&pid) { + if refresh_existing_process(self, pid, true) == false { + self.process_list.remove(&pid); + return false; + } true + } else if let Some(mut p) = Process::new_from_pid(pid) { + let system_time = get_system_computation_time(); + compute_cpu_usage(&mut p, self.processors.len() as u64, system_time); + self.process_list.insert(pid, p); + true + } else { + false } } @@ -389,7 +397,7 @@ fn refresh_existing_process(s: &mut System, pid: Pid, compute_cpu: bool) -> bool } } -fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: usize) -> String { +pub(crate) fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: usize) -> String { let name = &process.ImageName; if name.Buffer.is_null() { match process_id { From 924f34ddc02df0464cd744de86d485e61eba97a6 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Mon, 10 Feb 2020 22:07:48 +0100 Subject: [PATCH 161/171] Add tests to be sure that SystemExt::refresh_process adds the process if it isn't listed yet --- tests/process.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/process.rs b/tests/process.rs index a9b4c2ecd..8e01dde51 100644 --- a/tests/process.rs +++ b/tests/process.rs @@ -6,12 +6,12 @@ extern crate sysinfo; +#[cfg(not(windows))] +use sysinfo::ProcessExt; +use sysinfo::SystemExt; + #[test] fn test_process() { - #[cfg(not(windows))] - use sysinfo::ProcessExt; - use sysinfo::SystemExt; - let mut s = sysinfo::System::new(); assert_eq!(s.get_processes().len(), 0); s.refresh_processes(); @@ -22,3 +22,11 @@ fn test_process() { .values() .any(|p| p.exe().to_str().unwrap_or_else(|| "").len() != 0)); } + +#[test] +fn test_process_refresh() { + let mut s = sysinfo::System::new(); + assert_eq!(s.get_processes().len(), 0); + s.refresh_process(sysinfo::get_current_pid().expect("failed to get current pid")); + assert_eq!(s.get_process(sysinfo::get_current_pid().expect("failed to get current pid")).is_some(), true); +} From bf7b46b17103655d5c920de22e4407e28689da04 Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Mon, 10 Feb 2020 22:14:02 +0100 Subject: [PATCH 162/171] fmt --- src/windows/process.rs | 23 ++++++++++++++--------- tests/process.rs | 6 +++++- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/windows/process.rs b/src/windows/process.rs index 04aeaaf7d..a04ff3f39 100644 --- a/src/windows/process.rs +++ b/src/windows/process.rs @@ -16,6 +16,9 @@ use libc::{c_uint, c_void, memcpy}; use Pid; use ProcessExt; +use ntapi::ntpsapi::{ + NtQueryInformationProcess, ProcessBasicInformation, PROCESS_BASIC_INFORMATION, +}; use winapi::shared::minwindef::{DWORD, FALSE, FILETIME, MAX_PATH /*, TRUE, USHORT*/}; use winapi::um::handleapi::CloseHandle; use winapi::um::processthreadsapi::{GetProcessTimes, OpenProcess, TerminateProcess}; @@ -28,7 +31,6 @@ use winapi::um::winnt::{ HANDLE, /*, PWSTR*/ PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, PROCESS_VM_READ, ULARGE_INTEGER, /*THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION, THREAD_SUSPEND_RESUME,*/ }; -use ntapi::ntpsapi::{NtQueryInformationProcess, ProcessBasicInformation, PROCESS_BASIC_INFORMATION}; /// Enum describing the different status of a process. #[derive(Clone, Copy, Debug)] @@ -164,15 +166,18 @@ impl Process { let process_handler = unsafe { OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid as _) }; if process_handler.is_null() { return None; - + } let mut info: PROCESS_BASIC_INFORMATION = unsafe { MaybeUninit::uninit().assume_init() }; - if unsafe { NtQueryInformationProcess( - process_handler, - ProcessBasicInformation, - &mut info as *mut _ as *mut _, - size_of::() as _, - null_mut(), - ) } != 0 { + if unsafe { + NtQueryInformationProcess( + process_handler, + ProcessBasicInformation, + &mut info as *mut _ as *mut _, + size_of::() as _, + null_mut(), + ) + } != 0 + { unsafe { CloseHandle(process_handler) }; return None; } diff --git a/tests/process.rs b/tests/process.rs index 8e01dde51..fce70d2c9 100644 --- a/tests/process.rs +++ b/tests/process.rs @@ -28,5 +28,9 @@ fn test_process_refresh() { let mut s = sysinfo::System::new(); assert_eq!(s.get_processes().len(), 0); s.refresh_process(sysinfo::get_current_pid().expect("failed to get current pid")); - assert_eq!(s.get_process(sysinfo::get_current_pid().expect("failed to get current pid")).is_some(), true); + assert_eq!( + s.get_process(sysinfo::get_current_pid().expect("failed to get current pid")) + .is_some(), + true + ); } From 1c72997831bcc1159fca1fbe58ae140b8ea8ef4b Mon Sep 17 00:00:00 2001 From: GuillaumeGomez Date: Mon, 10 Feb 2020 23:21:01 +0100 Subject: [PATCH 163/171] Fix ProcessExt::kill on windows --- src/windows/process.rs | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/windows/process.rs b/src/windows/process.rs index a04ff3f39..95e122f0c 100644 --- a/src/windows/process.rs +++ b/src/windows/process.rs @@ -8,6 +8,7 @@ use std::fmt::{self, Debug, Formatter}; use std::mem::{size_of, zeroed, MaybeUninit}; use std::ops::Deref; use std::path::{Path, PathBuf}; +use std::process; use std::ptr::null_mut; use std::str; @@ -19,7 +20,7 @@ use ProcessExt; use ntapi::ntpsapi::{ NtQueryInformationProcess, ProcessBasicInformation, PROCESS_BASIC_INFORMATION, }; -use winapi::shared::minwindef::{DWORD, FALSE, FILETIME, MAX_PATH /*, TRUE, USHORT*/}; +use winapi::shared::minwindef::{DWORD, FALSE, FILETIME, MAX_PATH}; use winapi::um::handleapi::CloseHandle; use winapi::um::processthreadsapi::{GetProcessTimes, OpenProcess, TerminateProcess}; use winapi::um::psapi::{ @@ -27,10 +28,7 @@ use winapi::um::psapi::{ LIST_MODULES_ALL, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX, }; use winapi::um::sysinfoapi::GetSystemTimeAsFileTime; -use winapi::um::winnt::{ - HANDLE, /*, PWSTR*/ PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, PROCESS_VM_READ, - ULARGE_INTEGER, /*THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION, THREAD_SUSPEND_RESUME,*/ -}; +use winapi::um::winnt::{HANDLE, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ, ULARGE_INTEGER}; /// Enum describing the different status of a process. #[derive(Clone, Copy, Debug)] @@ -58,16 +56,10 @@ fn get_process_handler(pid: Pid) -> Option { if pid == 0 { return None; } - let options = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE; + let options = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; let process_handler = unsafe { OpenProcess(options, FALSE, pid as DWORD) }; if process_handler.is_null() { - let options = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; - let process_handler = unsafe { OpenProcess(options, FALSE, pid as DWORD) }; - if process_handler.is_null() { - None - } else { - Some(process_handler) - } + None } else { Some(process_handler) } @@ -323,11 +315,9 @@ impl ProcessExt for Process { } fn kill(&self, signal: ::Signal) -> bool { - if self.handle.is_null() { - false - } else { - unsafe { TerminateProcess(*self.handle, signal as c_uint) != 0 } - } + let mut kill = process::Command::new("taskkill.exe"); + kill.arg("/PID").arg(self.pid().to_string()).arg("/F"); + kill.output().is_err() } fn name(&self) -> &str { From 56ad26659099a16425ecd78530f0895bcad67f88 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 11 Feb 2020 13:41:23 +0100 Subject: [PATCH 164/171] Improve ProcessExt::kill code on windows --- src/windows/process.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/windows/process.rs b/src/windows/process.rs index 95e122f0c..84ecc89ae 100644 --- a/src/windows/process.rs +++ b/src/windows/process.rs @@ -317,7 +317,10 @@ impl ProcessExt for Process { fn kill(&self, signal: ::Signal) -> bool { let mut kill = process::Command::new("taskkill.exe"); kill.arg("/PID").arg(self.pid().to_string()).arg("/F"); - kill.output().is_err() + match kill.output() { + Ok(o) => o.status.success(), + Err(_) => false, + } } fn name(&self) -> &str { From f86c6143d232935f5461ee09eef51c5461409140 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 11 Feb 2020 14:10:25 +0100 Subject: [PATCH 165/171] Update crate version to 0.11.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c7dff0f53..918c59da7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sysinfo" -version = "0.11.1" +version = "0.11.2" authors = ["Guillaume Gomez "] description = "Library to get system information such as processes, processors, disks, components and networks" From 137790e0a1326bd6fd99fa82f7b1497b92ff1a59 Mon Sep 17 00:00:00 2001 From: Lonng Date: Tue, 3 Dec 2019 14:40:39 +0800 Subject: [PATCH 166/171] add functions get_cpu_frequency/get_avg_load Signed-off-by: Lonng --- src/linux/mod.rs | 2 +- src/linux/processor.rs | 22 ++++++++++++++++++++++ src/linux/system.rs | 3 +-- src/mac/mod.rs | 2 +- src/mac/processor.rs | 31 +++++++++++++++++++++++++++++++ src/sysinfo.rs | 12 +++++++++++- src/unknown/mod.rs | 2 +- src/unknown/processor.rs | 9 +++++++++ src/windows/mod.rs | 2 +- 9 files changed, 78 insertions(+), 7 deletions(-) diff --git a/src/linux/mod.rs b/src/linux/mod.rs index 9a228c465..cc8a01c9a 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::Processor; +pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; pub use self::system::System; diff --git a/src/linux/processor.rs b/src/linux/processor.rs index df2027dc5..55862dfe1 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -9,6 +9,7 @@ use std::fs::File; use std::io::Read; +use LoadAvg; use ProcessorExt; /// Struct containing values to compute a CPU usage. @@ -228,6 +229,7 @@ pub fn get_raw_times(p: &Processor) -> (u64, u64) { (p.new_values.total_time(), p.old_values.total_time()) } +/// get_cpu_frequency returns the CPU frequency in MHz pub fn get_cpu_frequency() -> u64 { // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq let mut s = String::new(); @@ -285,4 +287,24 @@ pub fn get_vendor_id_and_brand() -> (String, String) { } } (vendor_id.unwrap_or_default(), brand.unwrap_or_default()) + +} + +/// get_avg_load returns the system load average value. +pub fn get_avg_load() -> LoadAvg { + let mut s = String::new(); + if let Err(_) = File::open("/proc/loadavg").and_then(|mut f| f.read_to_string(&mut s)) { + return LoadAvg::default(); + } + let loads = s + .trim() + .split(' ') + .take(3) + .map(|val| val.parse::().unwrap()) + .collect::>(); + LoadAvg { + one: loads[0], + five: loads[1], + fifteen: loads[2], + } } diff --git a/src/linux/system.rs b/src/linux/system.rs index 392ba6091..4be3e7938 100644 --- a/src/linux/system.rs +++ b/src/linux/system.rs @@ -18,7 +18,6 @@ use {ProcessExt, RefreshKind, SystemExt}; use libc::{self, gid_t, sysconf, uid_t, _SC_CLK_TCK, _SC_PAGESIZE}; use std::cell::UnsafeCell; use std::collections::HashMap; -use std::error::Error; use std::fs::{self, read_link, File}; use std::io::{self, BufRead, BufReader, Read}; use std::path::{Path, PathBuf}; @@ -818,7 +817,7 @@ fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result { let size = file.read(&mut data)?; data.truncate(size); Ok(String::from_utf8(data) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.description()))?) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.to_string()))?) } pub fn get_all_data>(file_path: P, size: usize) -> io::Result { diff --git a/src/mac/mod.rs b/src/mac/mod.rs index e52da14f7..0dcf08fcf 100644 --- a/src/mac/mod.rs +++ b/src/mac/mod.rs @@ -16,5 +16,5 @@ pub use self::component::Component; pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::Processor; +pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; pub use self::system::System; diff --git a/src/mac/processor.rs b/src/mac/processor.rs index b325751b7..c28377ff1 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -11,6 +11,7 @@ use std::sync::Arc; use sys::ffi; use sys::system::get_sys_value; +use LoadAvg; use ProcessorExt; pub struct UnsafePtr(*mut T); @@ -241,3 +242,33 @@ pub fn get_vendor_id_and_brand() -> (String, String) { get_sysctl_str(b"machdep.cpu.vendor\0"), ) } + +/// get_cpu_frequency returns the CPU frequency in MHz +pub fn get_cpu_frequency() -> u64 { + let mut speed: u64 = 0; + let mut len = std::mem::size_of::(); + unsafe { + ffi::sysctlbyname( + "hw.cpufrequency".as_ptr() as *const c_char, + &mut speed, + &mut len, + std::ptr::null_mut(), + 0, + ); + } + speed /= 1000000; + speed +} + +/// get_avg_load returns the system load average value. +pub fn get_avg_load() -> LoadAvg { + let loads = vec![0f64; 3]; + unsafe { + ffi::getloadavg(loads.as_ptr() as *const f64, 3); + } + LoadAvg { + one: loads[0], + five: loads[1], + fifteen: loads[2], + } +} diff --git a/src/sysinfo.rs b/src/sysinfo.rs index bc5c82c05..9c1a09fee 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -80,7 +80,7 @@ cfg_if! { } pub use common::{AsU32, DiskType, NetworksIter, Pid, RefreshKind}; -pub use sys::{Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System}; +pub use sys::{get_avg_load, get_cpu_frequency, Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System}; pub use traits::{ ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, }; @@ -235,4 +235,14 @@ mod test { false ); } + + #[test] + fn test_get_cpu_frequency() { + println!("test get_cpu_frequency: {}", ::get_cpu_frequency()); + } + + #[test] + fn test_get_avg_load() { + println!("test get_avg_load: {:?}", ::get_avg_load()); + } } diff --git a/src/unknown/mod.rs b/src/unknown/mod.rs index 9a228c465..cc8a01c9a 100644 --- a/src/unknown/mod.rs +++ b/src/unknown/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::Processor; +pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; pub use self::system::System; diff --git a/src/unknown/processor.rs b/src/unknown/processor.rs index 5fd8ecde4..b1c9c66dc 100644 --- a/src/unknown/processor.rs +++ b/src/unknown/processor.rs @@ -39,3 +39,12 @@ impl ProcessorExt for Processor { "" } } + +pub fn get_cpu_frequency() -> u64 { + 0 +} + +/// get_avg_load returns the system load average value. +pub fn get_avg_load() -> LoadAvg { + LoadAvg::default() +} diff --git a/src/windows/mod.rs b/src/windows/mod.rs index e48042562..bc7616c7f 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -20,5 +20,5 @@ pub use self::component::Component; pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::Processor; +pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; pub use self::system::System; From faa68e663b253422c535e1423f4babc8ae8e7e30 Mon Sep 17 00:00:00 2001 From: Lonng Date: Tue, 3 Dec 2019 19:21:12 +0800 Subject: [PATCH 167/171] support retrieve system wide configuration list Signed-off-by: Lonng --- Cargo.toml | 1 + src/sysinfo.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 918c59da7..12b872e6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ cfg-if = "0.1" rayon = "^1.0" doc-comment = "0.3" once_cell = "1.0" +walkdir = "2.2.9" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "handleapi", "ifdef", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase", "powerbase", "netioapi"] } diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 9c1a09fee..73f7874de 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -89,6 +89,8 @@ pub use traits::{ pub use c_interface::*; pub use utils::get_current_pid; +use std::collections::HashMap; + #[cfg(feature = "c-interface")] mod c_interface; mod common; @@ -219,6 +221,35 @@ pub struct LoadAvg { pub fifteen: f64, } +/// Returns system wide configuration +/// +/// # Note +/// +/// Current only can be used in operating system mounted `procfs` +pub fn get_sysctl_list() -> HashMap { + const DIR: &str = "/proc/sys/"; + let mut result = HashMap::new(); + for entry in walkdir::WalkDir::new(DIR) { + let entry = match entry { + Ok(entry) => entry, + _ => continue, + }; + + let content = match std::fs::read_to_string(entry.path()) { + Ok(c) => c, + _ => continue, + }; + + let path = match entry.path().to_str() { + Some(p) => p, + _ => continue, + }; + let name = path.trim_start_matches(DIR).replace("/", "."); + result.insert(name, content.trim().to_string()); + } + result +} + #[cfg(test)] mod test { use super::*; From ecd97b0c4c310b7ed91fce669b0b633572c5ef8b Mon Sep 17 00:00:00 2001 From: Lonng Date: Wed, 4 Dec 2019 16:44:50 +0800 Subject: [PATCH 168/171] wrap num_cpus/pnet_datalink/cache_size crates Signed-off-by: Lonng --- Cargo.toml | 3 +++ src/sysinfo.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 12b872e6d..c4e1e1a99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,9 @@ rayon = "^1.0" doc-comment = "0.3" once_cell = "1.0" walkdir = "2.2.9" +pnet_datalink = "0.23.0" +num_cpus = "1.11.1" +cache-size = "0.4.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "handleapi", "ifdef", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase", "powerbase", "netioapi"] } diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 73f7874de..7b1abdc99 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -49,6 +49,8 @@ //#![deny(warnings)] #![allow(unknown_lints)] +extern crate num_cpus; + #[macro_use] extern crate cfg_if; #[cfg(not(any(target_os = "unknown", target_arch = "wasm32")))] @@ -79,11 +81,17 @@ cfg_if! { } } +pub extern crate cache_size; +pub extern crate pnet_datalink as datalink; + pub use common::{AsU32, DiskType, NetworksIter, Pid, RefreshKind}; pub use sys::{get_avg_load, get_cpu_frequency, Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System}; pub use traits::{ ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, }; +pub use io::IOLoad; +pub use net::NICLoad; +pub use num_cpus::{get as get_logical_cores, get_physical as get_physical_cores}; #[cfg(feature = "c-interface")] pub use c_interface::*; @@ -223,7 +231,7 @@ pub struct LoadAvg { /// Returns system wide configuration /// -/// # Note +/// # Notes /// /// Current only can be used in operating system mounted `procfs` pub fn get_sysctl_list() -> HashMap { @@ -276,4 +284,35 @@ mod test { fn test_get_avg_load() { println!("test get_avg_load: {:?}", ::get_avg_load()); } + + #[test] + fn test_nic_load() { + println!("test test_nic_load: {:?}", ::NICLoad::snapshot()); + } + + #[test] + fn test_io_load() { + println!("test test_io_load: {:?}", ::IOLoad::snapshot()); + } + + #[test] + fn test_get_cores() { + assert_ne!(::get_logical_cores(), 0, "expect none-zero logical core"); + assert_ne!(::get_physical_cores(), 0, "expect none-zero physical core"); + } + + #[test] + fn test_cache_size() { + let caches = vec![ + ("l1-cache-size", ::cache_size::l1_cache_size()), + ("l1-cache-line-size", ::cache_size::l1_cache_line_size()), + ("l2-cache-size", ::cache_size::l2_cache_size()), + ("l2-cache-line-size", ::cache_size::l2_cache_line_size()), + ("l3-cache-size", ::cache_size::l3_cache_size()), + ("l3-cache-line-size", ::cache_size::l3_cache_line_size()), + ]; + for c in caches { + assert_ne!(c.1.unwrap(), 0, "{} expect non-zero", c.0) + } + } } From 424a36c962c74fc9606f34533282f53e15866830 Mon Sep 17 00:00:00 2001 From: Lonng Date: Tue, 3 Dec 2019 16:09:39 +0800 Subject: [PATCH 169/171] support retrieve network statistics Signed-off-by: Lonng --- src/net.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/sysinfo.rs | 3 +++ 2 files changed, 75 insertions(+) create mode 100644 src/net.rs diff --git a/src/net.rs b/src/net.rs new file mode 100644 index 000000000..6abd84820 --- /dev/null +++ b/src/net.rs @@ -0,0 +1,72 @@ +use std::collections::HashMap; + +/// NICLoad represents the network interface card load informations +#[derive(Debug)] +pub struct NICLoad { + /// a total number of bytes received over interface. + pub rx_bytes: usize, + /// a total number of bytes transmitted over interface. + pub tx_bytes: usize, + /// a total number of packets received. + pub rx_packets: usize, + /// a total number of packets transmitted. + pub tx_packets: usize, + /// shows a total number of packets received with error. This includes + /// too-long-frames errors, ring-buffer overflow errors, CRC errors, + /// frame alignment errors, fifo overruns, and missed packets. + pub rx_errors: usize, + /// similar to `rx_errors` + pub tx_errors: usize, + /// Indicates the number of compressed packets received by this + /// network device. This value might only be relevant for interfaces + /// that support packet compression (e.g: PPP). + pub rx_compressed: usize, + /// Indicates the number of transmitted compressed packets. Note + /// this might only be relevant for devices that support + /// compression (e.g: PPP). + pub tx_compressed: usize, +} + +impl NICLoad { + /// Returns the current network interfaces card statistics + /// + /// # Notes + /// + /// Current don't support non-unix operating system + #[cfg(not(unix))] + pub fn current() -> HashMap { + HashMap::new() + } + + /// Returns the current network interfaces card statistics + #[cfg(unix)] + pub fn current() -> HashMap { + let mut result = HashMap::new(); + if let Ok(dir) = std::fs::read_dir("/sys/class/net/") { + for entry in dir { + if let Ok(entry) = entry { + let parent = entry.path().join("statistics"); + let read = |path: &str| -> usize { + std::fs::read_to_string(parent.join(path)) + .unwrap_or_default() + .trim() + .parse() + .unwrap_or_default() + }; + let load = NICLoad { + rx_bytes: read("rx_bytes"), + tx_bytes: read("tx_bytes"), + rx_packets: read("rx_packets"), + tx_packets: read("tx_packets"), + rx_errors: read("rx_errors"), + tx_errors: read("tx_errors"), + rx_compressed: read("rx_compressed"), + tx_compressed: read("tx_compressed"), + }; + result.insert(format!("{:?}", entry.file_name()), load); + } + } + } + result + } +} diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 7b1abdc99..78841ca61 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -103,6 +103,8 @@ use std::collections::HashMap; mod c_interface; mod common; mod component; +mod net; +mod process; mod processor; mod system; mod traits; @@ -288,6 +290,7 @@ mod test { #[test] fn test_nic_load() { println!("test test_nic_load: {:?}", ::NICLoad::snapshot()); + println!("test test_nic_load: {:?}", ::NICLoad::current()); } #[test] From eefc23a3b678e4712e78625c468322d1e2b57356 Mon Sep 17 00:00:00 2001 From: Lonng Date: Tue, 3 Dec 2019 17:02:14 +0800 Subject: [PATCH 170/171] support retrieve block device IO statistics Signed-off-by: Lonng --- src/io.rs | 93 ++++++++++++++++++++++++++++++++++++++++++ src/linux/processor.rs | 1 - src/net.rs | 4 +- src/sysinfo.rs | 14 ++++--- 4 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 src/io.rs diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 000000000..05bdc3356 --- /dev/null +++ b/src/io.rs @@ -0,0 +1,93 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +/// IOLoad represents current system block devices IO statistics +#[derive(Debug)] +pub struct IOLoad { + /// number of read I/Os processed + /// units: requests + pub read_io: f64, + /// number of read I/Os merged with in-queue I/O + /// units: requests + pub read_merges: f64, + /// number of sectors read + /// units: sectors + pub read_sectors: f64, + /// total wait time for read requests + /// units: milliseconds + pub read_ticks: f64, + /// number of write I/Os processed + /// units: requests + pub write_io: f64, + /// number of write I/Os merged with in-queue I/O + /// units: requests + pub write_merges: f64, + /// number of sectors written + /// units: sectors + pub write_sectors: f64, + /// total wait time for write requests + /// units: milliseconds + pub write_ticks: f64, + /// number of I/Os currently in flight + /// units: requests + pub in_flight: f64, + /// total time this block device has been active + /// units: milliseconds + pub io_ticks: f64, + /// total wait time for all requests + /// units: milliseconds + pub time_in_queue: f64, +} + +impl IOLoad { + /// Returns the current IO statistics + /// + /// # Notes + /// + /// Current don't support non-unix operating system + #[cfg(not(unix))] + pub fn snapshot() -> HashMap { + HashMap::new() + } + + /// Returns the current IO statistics + #[cfg(unix)] + pub fn snapshot() -> HashMap { + let mut result = HashMap::new(); + // https://www.kernel.org/doc/Documentation/block/stat.txt + if let Ok(dir) = std::fs::read_dir("/sys/block/") { + for entry in dir { + if let Ok(entry) = entry { + let stat = entry.path().join("stat"); + let mut s = String::new(); + if let Err(_) = File::open(stat).and_then(|mut f| f.read_to_string(&mut s)) { + continue; + }; + let parts = s + .split_whitespace() + .map(|w| w.parse().unwrap_or_default()) + .collect::>(); + if parts.len() != 11 { + continue; + } + let load = IOLoad { + read_io: parts[0], + read_merges: parts[1], + read_sectors: parts[2], + read_ticks: parts[3], + write_io: parts[4], + write_merges: parts[5], + write_sectors: parts[6], + write_ticks: parts[7], + in_flight: parts[8], + io_ticks: parts[9], + time_in_queue: parts[10], + }; + result.insert(format!("{:?}", entry.file_name()), load); + } + } + } + result + } +} diff --git a/src/linux/processor.rs b/src/linux/processor.rs index 55862dfe1..ae2eb25c7 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -287,7 +287,6 @@ pub fn get_vendor_id_and_brand() -> (String, String) { } } (vendor_id.unwrap_or_default(), brand.unwrap_or_default()) - } /// get_avg_load returns the system load average value. diff --git a/src/net.rs b/src/net.rs index 6abd84820..878c6648b 100644 --- a/src/net.rs +++ b/src/net.rs @@ -34,13 +34,13 @@ impl NICLoad { /// /// Current don't support non-unix operating system #[cfg(not(unix))] - pub fn current() -> HashMap { + pub fn snapshot() -> HashMap { HashMap::new() } /// Returns the current network interfaces card statistics #[cfg(unix)] - pub fn current() -> HashMap { + pub fn snapshot() -> HashMap { let mut result = HashMap::new(); if let Ok(dir) = std::fs::read_dir("/sys/class/net/") { for entry in dir { diff --git a/src/sysinfo.rs b/src/sysinfo.rs index 78841ca61..a9d961461 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -85,13 +85,16 @@ pub extern crate cache_size; pub extern crate pnet_datalink as datalink; pub use common::{AsU32, DiskType, NetworksIter, Pid, RefreshKind}; -pub use sys::{get_avg_load, get_cpu_frequency, Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System}; -pub use traits::{ - ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, -}; pub use io::IOLoad; pub use net::NICLoad; pub use num_cpus::{get as get_logical_cores, get_physical as get_physical_cores}; +pub use sys::{ + get_avg_load, get_cpu_frequency, Component, Disk, NetworkData, Networks, Process, + ProcessStatus, Processor, System, +}; +pub use traits::{ + ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, +}; #[cfg(feature = "c-interface")] pub use c_interface::*; @@ -103,8 +106,8 @@ use std::collections::HashMap; mod c_interface; mod common; mod component; +mod io; mod net; -mod process; mod processor; mod system; mod traits; @@ -290,7 +293,6 @@ mod test { #[test] fn test_nic_load() { println!("test test_nic_load: {:?}", ::NICLoad::snapshot()); - println!("test test_nic_load: {:?}", ::NICLoad::current()); } #[test] From 2e70ddd897e1d716fc63b5a11e5fa9953f6f6b8c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Sat, 15 Feb 2020 10:32:24 +0000 Subject: [PATCH 171/171] Remove unnecessary code Signed-off-by: Nick Cameron --- src/linux/mod.rs | 2 +- src/linux/processor.rs | 21 --------------------- src/mac/mod.rs | 2 +- src/mac/processor.rs | 32 +------------------------------- src/sysinfo.rs | 15 ++------------- src/unknown/mod.rs | 2 +- src/unknown/processor.rs | 9 --------- src/windows/mod.rs | 2 +- 8 files changed, 7 insertions(+), 78 deletions(-) diff --git a/src/linux/mod.rs b/src/linux/mod.rs index cc8a01c9a..9a228c465 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; +pub use self::processor::Processor; pub use self::system::System; diff --git a/src/linux/processor.rs b/src/linux/processor.rs index ae2eb25c7..df2027dc5 100644 --- a/src/linux/processor.rs +++ b/src/linux/processor.rs @@ -9,7 +9,6 @@ use std::fs::File; use std::io::Read; -use LoadAvg; use ProcessorExt; /// Struct containing values to compute a CPU usage. @@ -229,7 +228,6 @@ pub fn get_raw_times(p: &Processor) -> (u64, u64) { (p.new_values.total_time(), p.old_values.total_time()) } -/// get_cpu_frequency returns the CPU frequency in MHz pub fn get_cpu_frequency() -> u64 { // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq let mut s = String::new(); @@ -288,22 +286,3 @@ pub fn get_vendor_id_and_brand() -> (String, String) { } (vendor_id.unwrap_or_default(), brand.unwrap_or_default()) } - -/// get_avg_load returns the system load average value. -pub fn get_avg_load() -> LoadAvg { - let mut s = String::new(); - if let Err(_) = File::open("/proc/loadavg").and_then(|mut f| f.read_to_string(&mut s)) { - return LoadAvg::default(); - } - let loads = s - .trim() - .split(' ') - .take(3) - .map(|val| val.parse::().unwrap()) - .collect::>(); - LoadAvg { - one: loads[0], - five: loads[1], - fifteen: loads[2], - } -} diff --git a/src/mac/mod.rs b/src/mac/mod.rs index 0dcf08fcf..e52da14f7 100644 --- a/src/mac/mod.rs +++ b/src/mac/mod.rs @@ -16,5 +16,5 @@ pub use self::component::Component; pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; +pub use self::processor::Processor; pub use self::system::System; diff --git a/src/mac/processor.rs b/src/mac/processor.rs index c28377ff1..4b2c26888 100644 --- a/src/mac/processor.rs +++ b/src/mac/processor.rs @@ -118,7 +118,7 @@ impl ProcessorExt for Processor { } } -pub fn get_cpu_frequency() -> u64 { +fn get_cpu_frequency() -> u64 { let mut speed: u64 = 0; let mut len = std::mem::size_of::(); unsafe { @@ -242,33 +242,3 @@ pub fn get_vendor_id_and_brand() -> (String, String) { get_sysctl_str(b"machdep.cpu.vendor\0"), ) } - -/// get_cpu_frequency returns the CPU frequency in MHz -pub fn get_cpu_frequency() -> u64 { - let mut speed: u64 = 0; - let mut len = std::mem::size_of::(); - unsafe { - ffi::sysctlbyname( - "hw.cpufrequency".as_ptr() as *const c_char, - &mut speed, - &mut len, - std::ptr::null_mut(), - 0, - ); - } - speed /= 1000000; - speed -} - -/// get_avg_load returns the system load average value. -pub fn get_avg_load() -> LoadAvg { - let loads = vec![0f64; 3]; - unsafe { - ffi::getloadavg(loads.as_ptr() as *const f64, 3); - } - LoadAvg { - one: loads[0], - five: loads[1], - fifteen: loads[2], - } -} diff --git a/src/sysinfo.rs b/src/sysinfo.rs index a9d961461..5dfa5857a 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -87,9 +87,9 @@ pub extern crate pnet_datalink as datalink; pub use common::{AsU32, DiskType, NetworksIter, Pid, RefreshKind}; pub use io::IOLoad; pub use net::NICLoad; -pub use num_cpus::{get as get_logical_cores, get_physical as get_physical_cores}; +pub use num_cpus::get_physical as get_physical_cores; pub use sys::{ - get_avg_load, get_cpu_frequency, Component, Disk, NetworkData, Networks, Process, + Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System, }; pub use traits::{ @@ -280,16 +280,6 @@ mod test { ); } - #[test] - fn test_get_cpu_frequency() { - println!("test get_cpu_frequency: {}", ::get_cpu_frequency()); - } - - #[test] - fn test_get_avg_load() { - println!("test get_avg_load: {:?}", ::get_avg_load()); - } - #[test] fn test_nic_load() { println!("test test_nic_load: {:?}", ::NICLoad::snapshot()); @@ -302,7 +292,6 @@ mod test { #[test] fn test_get_cores() { - assert_ne!(::get_logical_cores(), 0, "expect none-zero logical core"); assert_ne!(::get_physical_cores(), 0, "expect none-zero physical core"); } diff --git a/src/unknown/mod.rs b/src/unknown/mod.rs index cc8a01c9a..9a228c465 100644 --- a/src/unknown/mod.rs +++ b/src/unknown/mod.rs @@ -15,5 +15,5 @@ pub use self::component::Component; pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; +pub use self::processor::Processor; pub use self::system::System; diff --git a/src/unknown/processor.rs b/src/unknown/processor.rs index b1c9c66dc..5fd8ecde4 100644 --- a/src/unknown/processor.rs +++ b/src/unknown/processor.rs @@ -39,12 +39,3 @@ impl ProcessorExt for Processor { "" } } - -pub fn get_cpu_frequency() -> u64 { - 0 -} - -/// get_avg_load returns the system load average value. -pub fn get_avg_load() -> LoadAvg { - LoadAvg::default() -} diff --git a/src/windows/mod.rs b/src/windows/mod.rs index bc7616c7f..e48042562 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -20,5 +20,5 @@ pub use self::component::Component; pub use self::disk::Disk; pub use self::network::{NetworkData, Networks}; pub use self::process::{Process, ProcessStatus}; -pub use self::processor::{get_avg_load, get_cpu_frequency, Processor}; +pub use self::processor::Processor; pub use self::system::System;