diff --git a/Cargo.lock b/Cargo.lock index 4d5a601..fae45d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1598,6 +1598,7 @@ dependencies = [ "pkg-config", "prettytable-rs", "sysinfo", + "uu_vmstat", "uucore", "windows-sys 0.59.0", ] diff --git a/src/uu/top/Cargo.toml b/src/uu/top/Cargo.toml index f02dd87..a1c5b14 100644 --- a/src/uu/top/Cargo.toml +++ b/src/uu/top/Cargo.toml @@ -20,12 +20,16 @@ prettytable-rs = { workspace = true } sysinfo = { workspace = true } chrono = { workspace = true } bytesize = { workspace = true } + +uu_vmstat = { path = "../vmstat" } + [target.'cfg(target_os="windows")'.dependencies] windows-sys = { workspace = true, features = [ "Win32_System_RemoteDesktop", "Win32_System_SystemInformation", ] } + [target.'cfg(target_os="linux")'.build-dependencies] pkg-config = "0.3.31" diff --git a/src/uu/top/src/header.rs b/src/uu/top/src/header.rs index 1785e20..66b1af4 100644 --- a/src/uu/top/src/header.rs +++ b/src/uu/top/src/header.rs @@ -135,49 +135,18 @@ fn task() -> String { #[cfg(target_os = "linux")] fn cpu() -> String { - let file = std::fs::File::open(std::path::Path::new("/proc/stat")).unwrap(); - let content = std::io::read_to_string(file).unwrap(); - let load = content - .lines() - .next() - .unwrap() - .strip_prefix("cpu") - .unwrap() - .split(' ') - .filter(|s| !s.is_empty()) - .collect::>(); - let user = load[0].parse::().unwrap(); - let nice = load[1].parse::().unwrap(); - let system = load[2].parse::().unwrap(); - let idle = load[3].parse::().unwrap_or_default(); // since 2.5.41 - let io_wait = load[4].parse::().unwrap_or_default(); // since 2.5.41 - let hardware_interrupt = load[5].parse::().unwrap_or_default(); // since 2.6.0 - let software_interrupt = load[6].parse::().unwrap_or_default(); // since 2.6.0 - let steal_time = load[7].parse::().unwrap_or_default(); // since 2.6.11 - // GNU do not show guest and guest_nice - let guest = load[8].parse::().unwrap_or_default(); // since 2.6.24 - let guest_nice = load[9].parse::().unwrap_or_default(); // since 2.6.33 - let total = user - + nice - + system - + idle - + io_wait - + hardware_interrupt - + software_interrupt - + steal_time - + guest - + guest_nice; + let cpu_load = uu_vmstat::CpuLoad::current(); format!( "%Cpu(s): {:.1} us, {:.1} sy, {:.1} ni, {:.1} id, {:.1} wa, {:.1} hi, {:.1} si, {:.1} st", - user / total * 100.0, - system / total * 100.0, - nice / total * 100.0, - idle / total * 100.0, - io_wait / total * 100.0, - hardware_interrupt / total * 100.0, - software_interrupt / total * 100.0, - steal_time / total * 100.0, + cpu_load.user, + cpu_load.system, + cpu_load.nice, + cpu_load.idle, + cpu_load.io_wait, + cpu_load.hardware_interrupt, + cpu_load.software_interrupt, + cpu_load.steal_time, ) } diff --git a/src/uu/vmstat/src/parser.rs b/src/uu/vmstat/src/parser.rs new file mode 100644 index 0000000..906fc11 --- /dev/null +++ b/src/uu/vmstat/src/parser.rs @@ -0,0 +1,78 @@ +#[cfg(target_os = "linux")] +pub fn parse_proc_file(path: &str) -> std::collections::HashMap { + let file = std::fs::File::open(std::path::Path::new(path)).unwrap(); + let content = std::io::read_to_string(file).unwrap(); + let mut map: std::collections::HashMap = std::collections::HashMap::new(); + + for line in content.lines() { + let parts = line.split_once(char::is_whitespace); + if let Some(parts) = parts { + map.insert(parts.0.to_string(), parts.1.trim_start().to_string()); + } + } + + map +} + +#[cfg(target_os = "linux")] +pub struct CpuLoad { + pub user: f64, + pub nice: f64, + pub system: f64, + pub idle: f64, + pub io_wait: f64, + pub hardware_interrupt: f64, + pub software_interrupt: f64, + pub steal_time: f64, + pub guest: f64, + pub guest_nice: f64, +} + +#[cfg(target_os = "linux")] +impl CpuLoad { + pub fn current() -> CpuLoad { + let file = std::fs::File::open(std::path::Path::new("/proc/stat")).unwrap(); // do not use `parse_proc_file` here because only one line is used + let content = std::io::read_to_string(file).unwrap(); + let load = content + .lines() + .next() + .unwrap() + .strip_prefix("cpu") + .unwrap() + .split(' ') + .filter(|s| !s.is_empty()) + .collect::>(); + let user = load[0].parse::().unwrap(); + let nice = load[1].parse::().unwrap(); + let system = load[2].parse::().unwrap(); + let idle = load[3].parse::().unwrap_or_default(); // since 2.5.41 + let io_wait = load[4].parse::().unwrap_or_default(); // since 2.5.41 + let hardware_interrupt = load[5].parse::().unwrap_or_default(); // since 2.6.0 + let software_interrupt = load[6].parse::().unwrap_or_default(); // since 2.6.0 + let steal_time = load[7].parse::().unwrap_or_default(); // since 2.6.11 + let guest = load[8].parse::().unwrap_or_default(); // since 2.6.24 + let guest_nice = load[9].parse::().unwrap_or_default(); // since 2.6.33 + let total = user + + nice + + system + + idle + + io_wait + + hardware_interrupt + + software_interrupt + + steal_time + + guest + + guest_nice; + Self { + user: user / total * 100.0, + system: system / total * 100.0, + nice: nice / total * 100.0, + idle: idle / total * 100.0, + io_wait: io_wait / total * 100.0, + hardware_interrupt: hardware_interrupt / total * 100.0, + software_interrupt: software_interrupt / total * 100.0, + steal_time: steal_time / total * 100.0, + guest: guest / total * 100.0, + guest_nice: guest_nice / total * 100.0, + } + } +} diff --git a/src/uu/vmstat/src/vmstat.rs b/src/uu/vmstat/src/vmstat.rs index c0b5156..1121457 100644 --- a/src/uu/vmstat/src/vmstat.rs +++ b/src/uu/vmstat/src/vmstat.rs @@ -3,11 +3,13 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +mod parser; + use clap::{crate_version, Command}; +#[allow(unused_imports)] +pub use parser::*; #[cfg(target_os = "linux")] use procfs::{Current, CurrentSI}; -#[cfg(target_os = "linux")] -use std::collections::HashMap; use uucore::error::UResult; use uucore::{format_usage, help_about, help_usage}; @@ -75,22 +77,6 @@ fn up_secs_proc() -> f64 { n_proc as f64 * up_secs() } -#[cfg(target_os = "linux")] -fn parse_proc_file(path: &str) -> HashMap { - let file = std::fs::File::open(std::path::Path::new(path)).unwrap(); - let content = std::io::read_to_string(file).unwrap(); - let mut map: HashMap = HashMap::new(); - - for line in content.lines() { - let parts = line.split_once(char::is_whitespace); - if let Some(parts) = parts { - map.insert(parts.0.to_string(), parts.1.trim_start().to_string()); - } - } - - map -} - #[cfg(target_os = "linux")] fn get_process_info() -> (String, String, String) { let stat = procfs::KernelStats::current().unwrap(); @@ -180,45 +166,14 @@ fn get_system_info() -> (String, String, String) { #[cfg(target_os = "linux")] fn get_cpu_info() -> (String, String, String) { - let stat = parse_proc_file("/proc/stat"); - let load = stat - .get("cpu") - .unwrap() - .split(' ') - .filter(|s| !s.is_empty()) - .collect::>(); - let user = load[0].parse::().unwrap(); - let nice = load[1].parse::().unwrap(); - let system = load[2].parse::().unwrap(); - let idle = load[3].parse::().unwrap_or_default(); // since 2.5.41 - let io_wait = load[4].parse::().unwrap_or_default(); // since 2.5.41 - let hardware_interrupt = load[5].parse::().unwrap_or_default(); // since 2.6.0 - let software_interrupt = load[6].parse::().unwrap_or_default(); // since 2.6.0 - let steal_time = load[7].parse::().unwrap_or_default(); // since 2.6.11 - // GNU do not show guest and guest_nice - let guest = load[8].parse::().unwrap_or_default(); // since 2.6.24 - let guest_nice = load[9].parse::().unwrap_or_default(); // since 2.6.33 - let total = user - + nice - + system - + idle - + io_wait - + hardware_interrupt - + software_interrupt - + steal_time - + guest - + guest_nice; + let cpu_load = CpuLoad::current(); ( "------cpu-----".into(), "us sy id wa st".into(), format!( "{:>2.0} {:>2.0} {:>2.0} {:>2.0} {:>2.0}", - user / total * 100.0, - system / total * 100.0, - idle / total * 100.0, - io_wait / total * 100.0, - steal_time / total * 100.0, + cpu_load.user, cpu_load.system, cpu_load.idle, cpu_load.io_wait, cpu_load.steal_time ), ) }