mirror of
https://github.com/uutils/procps.git
synced 2026-06-10 16:14:00 -07:00
vmstat: impl delay, count, --one-heder, --no-first
This commit is contained in:
Generated
+2
-66
@@ -2,12 +2,6 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
@@ -269,15 +263,6 @@ version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.28.1"
|
||||
@@ -520,16 +505,6 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@@ -594,12 +569,6 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
@@ -762,15 +731,6 @@ version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.3"
|
||||
@@ -988,31 +948,6 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "procfs"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"flate2",
|
||||
"hex",
|
||||
"procfs-core",
|
||||
"rustix 0.38.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "procfs-core"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"hex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "procps"
|
||||
version = "0.0.1"
|
||||
@@ -1729,8 +1664,9 @@ dependencies = [
|
||||
name = "uu_vmstat"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bytesize",
|
||||
"clap",
|
||||
"procfs",
|
||||
"terminal_size",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
|
||||
+1
-1
@@ -56,12 +56,12 @@ nix = { version = "0.29", default-features = false, features = ["process"] }
|
||||
phf = "0.11.2"
|
||||
phf_codegen = "0.11.2"
|
||||
prettytable-rs = "0.10.0"
|
||||
procfs = "0.17.0"
|
||||
rand = { version = "0.9.0", features = ["small_rng"] }
|
||||
ratatui = "0.29.0"
|
||||
regex = "1.10.4"
|
||||
sysinfo = "0.34.0"
|
||||
tempfile = "3.10.1"
|
||||
terminal_size = "0.4.2"
|
||||
textwrap = { version = "0.16.1", features = ["terminal_size"] }
|
||||
thiserror = "2.0.4"
|
||||
uucore = "0.0.30"
|
||||
|
||||
@@ -12,11 +12,10 @@ keywords = ["acl", "uutils", "cross-platform", "cli", "utility"]
|
||||
categories = ["command-line-utilities"]
|
||||
|
||||
[dependencies]
|
||||
uucore = { workspace = true }
|
||||
bytesize = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os="linux")'.dependencies]
|
||||
procfs = { workspace = true }
|
||||
terminal_size = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[lib]
|
||||
path = "src/vmstat.rs"
|
||||
|
||||
+103
-13
@@ -4,21 +4,65 @@
|
||||
// file that was distributed with this source code.
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn parse_proc_file(path: &str) -> std::collections::HashMap<String, String> {
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn parse_proc_file(path: &str) -> HashMap<String, String> {
|
||||
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<String, String> = std::collections::HashMap::new();
|
||||
let mut map: HashMap<String, String> = 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.insert(
|
||||
parts.0.strip_suffix(":").unwrap_or(parts.0).to_string(),
|
||||
parts.1.trim_start().to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub struct ProcData {
|
||||
pub uptime: (f64, f64),
|
||||
pub stat: HashMap<String, String>,
|
||||
pub meminfo: HashMap<String, String>,
|
||||
pub vmstat: HashMap<String, String>,
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
impl Default for ProcData {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
impl ProcData {
|
||||
pub fn new() -> Self {
|
||||
let uptime = Self::get_uptime();
|
||||
let stat = parse_proc_file("/proc/stat");
|
||||
let meminfo = parse_proc_file("/proc/meminfo");
|
||||
let vmstat = parse_proc_file("/proc/vmstat");
|
||||
Self {
|
||||
uptime,
|
||||
stat,
|
||||
meminfo,
|
||||
vmstat,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_uptime() -> (f64, f64) {
|
||||
let file = std::fs::File::open(std::path::Path::new("/proc/uptime")).unwrap();
|
||||
let content = std::io::read_to_string(file).unwrap();
|
||||
let mut parts = content.split_whitespace();
|
||||
let uptime = parts.next().unwrap().parse::<f64>().unwrap();
|
||||
let idle_time = parts.next().unwrap().parse::<f64>().unwrap();
|
||||
(uptime, idle_time)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub struct CpuLoad {
|
||||
pub user: f64,
|
||||
@@ -35,18 +79,20 @@ pub struct CpuLoad {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl CpuLoad {
|
||||
pub fn current() -> CpuLoad {
|
||||
pub fn current() -> Self {
|
||||
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::<Vec<_>>();
|
||||
let load_str = content.lines().next().unwrap().strip_prefix("cpu").unwrap();
|
||||
Self::from_str(load_str)
|
||||
}
|
||||
|
||||
pub fn from_proc_map(proc_map: &HashMap<String, String>) -> Self {
|
||||
let load_str = proc_map.get("cpu").unwrap();
|
||||
Self::from_str(load_str)
|
||||
}
|
||||
|
||||
fn from_str(s: &str) -> Self {
|
||||
let load = s.split(' ').filter(|s| !s.is_empty()).collect::<Vec<_>>();
|
||||
let user = load[0].parse::<f64>().unwrap();
|
||||
let nice = load[1].parse::<f64>().unwrap();
|
||||
let system = load[2].parse::<f64>().unwrap();
|
||||
@@ -81,3 +127,47 @@ impl CpuLoad {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub struct Meminfo {
|
||||
pub mem_total: bytesize::ByteSize,
|
||||
pub mem_free: bytesize::ByteSize,
|
||||
pub mem_available: bytesize::ByteSize,
|
||||
pub buffers: bytesize::ByteSize,
|
||||
pub cached: bytesize::ByteSize,
|
||||
pub swap_cached: bytesize::ByteSize,
|
||||
pub swap_total: bytesize::ByteSize,
|
||||
pub swap_free: bytesize::ByteSize,
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
impl Meminfo {
|
||||
pub fn current() -> Self {
|
||||
let meminfo = parse_proc_file("/proc/meminfo");
|
||||
Self::from_proc_map(&meminfo)
|
||||
}
|
||||
|
||||
pub fn from_proc_map(proc_map: &HashMap<String, String>) -> Self {
|
||||
use std::str::FromStr;
|
||||
|
||||
let mem_total = bytesize::ByteSize::from_str(proc_map.get("MemTotal").unwrap()).unwrap();
|
||||
let mem_free = bytesize::ByteSize::from_str(proc_map.get("MemFree").unwrap()).unwrap();
|
||||
let mem_available =
|
||||
bytesize::ByteSize::from_str(proc_map.get("MemAvailable").unwrap()).unwrap();
|
||||
let buffers = bytesize::ByteSize::from_str(proc_map.get("Buffers").unwrap()).unwrap();
|
||||
let cached = bytesize::ByteSize::from_str(proc_map.get("Cached").unwrap()).unwrap();
|
||||
let swap_cached =
|
||||
bytesize::ByteSize::from_str(proc_map.get("SwapCached").unwrap()).unwrap();
|
||||
let swap_total = bytesize::ByteSize::from_str(proc_map.get("SwapTotal").unwrap()).unwrap();
|
||||
let swap_free = bytesize::ByteSize::from_str(proc_map.get("SwapFree").unwrap()).unwrap();
|
||||
Self {
|
||||
mem_total,
|
||||
mem_free,
|
||||
mem_available,
|
||||
buffers,
|
||||
cached,
|
||||
swap_cached,
|
||||
swap_total,
|
||||
swap_free,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
// This file is part of the uutils procps package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::{CpuLoad, Meminfo, ProcData};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub type Picker = (
|
||||
(String, String),
|
||||
Box<dyn Fn(&ProcData, Option<&ProcData>, &mut Vec<String>, &mut usize)>,
|
||||
);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn get_pickers() -> Vec<Picker> {
|
||||
vec![
|
||||
concat_helper(("procs".into(), " r b".into()), get_process_info),
|
||||
concat_helper(
|
||||
(
|
||||
"-----------memory----------".into(),
|
||||
" swpd free buff cache".into(),
|
||||
),
|
||||
get_memory_info,
|
||||
),
|
||||
concat_helper(("---swap--".into(), " si so".into()), get_swap_info),
|
||||
concat_helper(("-----io----".into(), " bi bo".into()), get_io_info),
|
||||
concat_helper(("-system--".into(), " in cs".into()), get_system_info),
|
||||
concat_helper(
|
||||
("-------cpu-------".into(), "us sy id wa st gu".into()),
|
||||
get_cpu_info,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn concat_helper(
|
||||
title: (String, String),
|
||||
func: impl Fn(&ProcData, Option<&ProcData>) -> Vec<(usize, String)> + 'static,
|
||||
) -> Picker {
|
||||
(
|
||||
title,
|
||||
Box::from(
|
||||
move |proc_data: &ProcData,
|
||||
proc_data_before: Option<&ProcData>,
|
||||
data: &mut Vec<String>,
|
||||
data_len_excess: &mut usize| {
|
||||
let output = func(proc_data, proc_data_before);
|
||||
output.iter().for_each(|(len, value)| {
|
||||
let len = if *data_len_excess > *len {
|
||||
0
|
||||
} else {
|
||||
len - *data_len_excess
|
||||
};
|
||||
let formatted_value = format!("{:>width$}", value, width = len);
|
||||
*data_len_excess = formatted_value.len() - len;
|
||||
data.push(formatted_value);
|
||||
});
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
macro_rules! diff {
|
||||
($now:expr, $before:expr, $($property:tt)*) => {
|
||||
if let Some(before) = &$before {
|
||||
$now.$($property)* - before.$($property)*
|
||||
} else {
|
||||
$now.$($property)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_process_info(
|
||||
proc_data: &ProcData,
|
||||
_proc_data_before: Option<&ProcData>,
|
||||
) -> Vec<(usize, String)> {
|
||||
let runnable = proc_data.stat.get("procs_running").unwrap();
|
||||
let blocked = proc_data.stat.get("procs_blocked").unwrap();
|
||||
|
||||
vec![(2, runnable.to_string()), (2, blocked.to_string())]
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_memory_info(
|
||||
proc_data: &ProcData,
|
||||
_proc_data_before: Option<&ProcData>,
|
||||
) -> Vec<(usize, String)> {
|
||||
use bytesize::*;
|
||||
|
||||
let memory_info = Meminfo::from_proc_map(&proc_data.meminfo);
|
||||
|
||||
let swap_used = (memory_info.swap_total - memory_info.swap_free).as_u64() / KB;
|
||||
let free = memory_info.mem_free.as_u64() / KB;
|
||||
let buffer = memory_info.buffers.as_u64() / KB;
|
||||
let cache = memory_info.cached.as_u64() / KB;
|
||||
|
||||
vec![
|
||||
(6, format!("{}", swap_used)),
|
||||
(6, format!("{}", free)),
|
||||
(6, format!("{}", buffer)),
|
||||
(6, format!("{}", cache)),
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_swap_info(
|
||||
proc_data: &ProcData,
|
||||
proc_data_before: Option<&ProcData>,
|
||||
) -> Vec<(usize, String)> {
|
||||
let period = diff!(proc_data, proc_data_before, uptime.0);
|
||||
let swap_in = diff!(
|
||||
proc_data,
|
||||
proc_data_before,
|
||||
vmstat.get("pswpin").unwrap().parse::<u64>().unwrap()
|
||||
);
|
||||
let swap_out = diff!(
|
||||
proc_data,
|
||||
proc_data_before,
|
||||
vmstat.get("pswpout").unwrap().parse::<u64>().unwrap()
|
||||
);
|
||||
|
||||
vec![
|
||||
(4, format!("{:.0}", swap_in as f64 / period)),
|
||||
(4, format!("{:.0}", swap_out as f64 / period)),
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_io_info(proc_data: &ProcData, proc_data_before: Option<&ProcData>) -> Vec<(usize, String)> {
|
||||
let period = diff!(proc_data, proc_data_before, uptime.0);
|
||||
let read_bytes = diff!(
|
||||
proc_data,
|
||||
proc_data_before,
|
||||
vmstat.get("pgpgin").unwrap().parse::<u64>().unwrap()
|
||||
);
|
||||
let write_bytes = diff!(
|
||||
proc_data,
|
||||
proc_data_before,
|
||||
vmstat.get("pgpgout").unwrap().parse::<u64>().unwrap()
|
||||
);
|
||||
|
||||
vec![
|
||||
(5, format!("{:.0}", read_bytes as f64 / period)),
|
||||
(5, format!("{:.0}", write_bytes as f64 / period)),
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_system_info(
|
||||
proc_data: &ProcData,
|
||||
proc_data_before: Option<&ProcData>,
|
||||
) -> Vec<(usize, String)> {
|
||||
let period = diff!(proc_data, proc_data_before, uptime.0);
|
||||
|
||||
let interrupts = diff!(
|
||||
proc_data,
|
||||
proc_data_before,
|
||||
stat.get("intr")
|
||||
.unwrap()
|
||||
.split_whitespace()
|
||||
.next()
|
||||
.unwrap()
|
||||
.parse::<i64>()
|
||||
.unwrap()
|
||||
);
|
||||
let context_switches = diff!(
|
||||
proc_data,
|
||||
proc_data_before,
|
||||
stat.get("ctxt").unwrap().parse::<i64>().unwrap()
|
||||
);
|
||||
|
||||
vec![
|
||||
(4, format!("{:.0}", interrupts as f64 / period)),
|
||||
(4, format!("{:.0}", context_switches as f64 / period)),
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_cpu_info(
|
||||
proc_data: &ProcData,
|
||||
_proc_data_before: Option<&ProcData>,
|
||||
) -> Vec<(usize, String)> {
|
||||
let cpu_load = CpuLoad::from_proc_map(&proc_data.stat);
|
||||
|
||||
vec![
|
||||
(2, format!("{:.0}", cpu_load.user)),
|
||||
(2, format!("{:.0}", cpu_load.system)),
|
||||
(2, format!("{:.0}", cpu_load.idle)),
|
||||
(2, format!("{:.0}", cpu_load.io_wait)),
|
||||
(2, format!("{:.0}", cpu_load.steal_time)),
|
||||
(2, format!("{:.0}", cpu_load.guest)),
|
||||
]
|
||||
}
|
||||
+97
-179
@@ -4,13 +4,15 @@
|
||||
// file that was distributed with this source code.
|
||||
|
||||
mod parser;
|
||||
mod picker;
|
||||
|
||||
use clap::{crate_version, Command};
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::picker::{get_pickers, Picker};
|
||||
use clap::{arg, crate_version, Command};
|
||||
#[allow(unused_imports)]
|
||||
pub use parser::*;
|
||||
#[cfg(target_os = "linux")]
|
||||
use procfs::{Current, CurrentSI};
|
||||
use uucore::error::UResult;
|
||||
#[allow(unused_imports)]
|
||||
use uucore::error::{UResult, USimpleError};
|
||||
use uucore::{format_usage, help_about, help_usage};
|
||||
|
||||
const ABOUT: &str = help_about!("vmstat.md");
|
||||
@@ -18,173 +20,91 @@ const USAGE: &str = help_usage!("vmstat.md");
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let _matches = uu_app().try_get_matches_from(args)?;
|
||||
|
||||
let mut section: Vec<String> = vec![];
|
||||
let mut title: Vec<String> = vec![];
|
||||
let mut data: Vec<String> = vec![];
|
||||
let mut data_len_excess = 0;
|
||||
|
||||
#[allow(unused)]
|
||||
let matches = uu_app().try_get_matches_from(args)?;
|
||||
#[cfg(target_os = "linux")]
|
||||
let func = [
|
||||
concat_helper(get_process_info),
|
||||
concat_helper(get_memory_info),
|
||||
concat_helper(get_swap_info),
|
||||
concat_helper(get_io_info),
|
||||
concat_helper(get_system_info),
|
||||
concat_helper(get_cpu_info),
|
||||
];
|
||||
{
|
||||
let one_header = matches.get_flag("one-header");
|
||||
let no_first = matches.get_flag("no-first");
|
||||
let delay = matches.get_one::<String>("delay");
|
||||
let mut delay = if let Some(delay) = delay {
|
||||
let delay = delay.parse::<i64>().unwrap();
|
||||
if delay <= 0 {
|
||||
return Err(USimpleError::new(-1, "delay must be greater than 0"));
|
||||
}
|
||||
delay
|
||||
} else {
|
||||
-1
|
||||
};
|
||||
let count = matches.get_one::<String>("count");
|
||||
let mut count = if let Some(count) = count {
|
||||
let mut count = count.parse::<i64>().unwrap();
|
||||
if count < 0 {
|
||||
return Err(USimpleError::new(-1, "count must be greater than 0"));
|
||||
}
|
||||
if count == 0 {
|
||||
count = 1;
|
||||
}
|
||||
count
|
||||
} else {
|
||||
-1
|
||||
};
|
||||
if count < 0 && delay < 0 {
|
||||
count = 1;
|
||||
if no_first {
|
||||
delay = 1;
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let func: [ConcatFunc; 0] = [];
|
||||
let pickers = get_pickers();
|
||||
let mut proc_data = ProcData::new();
|
||||
|
||||
func.iter()
|
||||
.for_each(|f| f(&mut section, &mut title, &mut data, &mut data_len_excess));
|
||||
let mut line_count = 0;
|
||||
print_header(&pickers);
|
||||
if !no_first {
|
||||
print_data(&pickers, &proc_data, None);
|
||||
line_count += 1;
|
||||
}
|
||||
|
||||
println!("{}", section.join(" "));
|
||||
println!("{}", title.join(" "));
|
||||
println!("{}", data.join(" "));
|
||||
let term_height = terminal_size::terminal_size()
|
||||
.map(|size| size.1 .0)
|
||||
.unwrap_or(0);
|
||||
|
||||
while count < 0 || line_count < count {
|
||||
std::thread::sleep(std::time::Duration::from_secs(delay as u64));
|
||||
let proc_data_now = ProcData::new();
|
||||
if !one_header && term_height > 0 && ((line_count + 3) % term_height as i64 == 0) {
|
||||
print_header(&pickers);
|
||||
}
|
||||
print_data(&pickers, &proc_data_now, Some(&proc_data));
|
||||
line_count += 1;
|
||||
proc_data = proc_data_now;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
type ConcatFunc = Box<dyn Fn(&mut Vec<String>, &mut Vec<String>, &mut Vec<String>, &mut usize)>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn concat_helper(
|
||||
func: impl Fn() -> (String, String, Vec<(usize, String)>) + 'static,
|
||||
) -> ConcatFunc {
|
||||
Box::from(
|
||||
move |section: &mut Vec<String>,
|
||||
title: &mut Vec<String>,
|
||||
data: &mut Vec<String>,
|
||||
data_len_excess: &mut usize| {
|
||||
let output = func();
|
||||
section.push(output.0);
|
||||
title.push(output.1);
|
||||
output.2.iter().for_each(|(len, value)| {
|
||||
let len = len - *data_len_excess;
|
||||
let formatted_value = format!("{:>width$}", value, width = len);
|
||||
*data_len_excess = formatted_value.len() - len;
|
||||
data.push(formatted_value);
|
||||
});
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn up_secs() -> f64 {
|
||||
let file = std::fs::File::open(std::path::Path::new("/proc/uptime")).unwrap();
|
||||
let content = std::io::read_to_string(file).unwrap();
|
||||
let mut parts = content.split_whitespace();
|
||||
parts.next().unwrap().parse::<f64>().unwrap()
|
||||
fn print_header(pickers: &[Picker]) {
|
||||
let mut section: Vec<&str> = vec![];
|
||||
let mut title: Vec<&str> = vec![];
|
||||
|
||||
pickers.iter().for_each(|p| {
|
||||
section.push(p.0 .0.as_str());
|
||||
title.push(p.0 .1.as_str());
|
||||
});
|
||||
println!("{}", section.join(" "));
|
||||
println!("{}", title.join(" "));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_process_info() -> (String, String, Vec<(usize, String)>) {
|
||||
let stat = procfs::KernelStats::current().unwrap();
|
||||
let runnable = stat.procs_running.unwrap_or_default();
|
||||
let blocked = stat.procs_blocked.unwrap_or_default();
|
||||
(
|
||||
"procs".into(),
|
||||
" r b".into(),
|
||||
vec![(2, format!("{}", runnable)), (2, format!("{}", blocked))],
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_memory_info() -> (String, String, Vec<(usize, String)>) {
|
||||
let memory_info = procfs::Meminfo::current().unwrap();
|
||||
let swap_used = (memory_info.swap_total - memory_info.swap_free) / 1024;
|
||||
let free = memory_info.mem_free / 1024;
|
||||
let buffer = memory_info.buffers / 1024;
|
||||
let cache = memory_info.cached / 1024;
|
||||
|
||||
(
|
||||
"-----------memory----------".into(),
|
||||
" swpd free buff cache".into(),
|
||||
vec![
|
||||
(6, format!("{}", swap_used)),
|
||||
(6, format!("{}", free)),
|
||||
(6, format!("{}", buffer)),
|
||||
(6, format!("{}", cache)),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_swap_info() -> (String, String, Vec<(usize, String)>) {
|
||||
let uptime = up_secs();
|
||||
let vmstat = procfs::vmstat().unwrap();
|
||||
let swap_in = vmstat.get("pswpin").unwrap();
|
||||
let swap_out = vmstat.get("pswpout").unwrap();
|
||||
(
|
||||
"---swap--".into(),
|
||||
" si so".into(),
|
||||
vec![
|
||||
(4, format!("{:.0}", *swap_in as f64 / uptime)),
|
||||
(4, format!("{:.0}", *swap_out as f64 / uptime)),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_io_info() -> (String, String, Vec<(usize, String)>) {
|
||||
let uptime = up_secs();
|
||||
let vmstat = procfs::vmstat().unwrap();
|
||||
let read_bytes = vmstat.get("pgpgin").unwrap();
|
||||
let write_bytes = vmstat.get("pgpgout").unwrap();
|
||||
(
|
||||
"-----io----".into(),
|
||||
" bi bo".into(),
|
||||
vec![
|
||||
(5, format!("{:.0}", *read_bytes as f64 / uptime)),
|
||||
(5, format!("{:.0}", *write_bytes as f64 / uptime)),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_system_info() -> (String, String, Vec<(usize, String)>) {
|
||||
let uptime = up_secs();
|
||||
let stat = parse_proc_file("/proc/stat");
|
||||
|
||||
let interrupts = stat
|
||||
.get("intr")
|
||||
.unwrap()
|
||||
.split_whitespace()
|
||||
.next()
|
||||
.unwrap()
|
||||
.parse::<i64>()
|
||||
.unwrap();
|
||||
let context_switches = stat.get("ctxt").unwrap().parse::<i64>().unwrap();
|
||||
|
||||
(
|
||||
"-system--".into(),
|
||||
" in cs".into(),
|
||||
vec![
|
||||
(4, format!("{:.0}", interrupts as f64 / uptime)),
|
||||
(4, format!("{:.0}", context_switches as f64 / uptime)),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_cpu_info() -> (String, String, Vec<(usize, String)>) {
|
||||
let cpu_load = CpuLoad::current();
|
||||
|
||||
(
|
||||
"-------cpu-------".into(),
|
||||
"us sy id wa st gu".into(),
|
||||
vec![
|
||||
(2, format!("{:.0}", cpu_load.user)),
|
||||
(2, format!("{:.0}", cpu_load.system)),
|
||||
(2, format!("{:.0}", cpu_load.idle)),
|
||||
(2, format!("{:.0}", cpu_load.io_wait)),
|
||||
(2, format!("{:.0}", cpu_load.steal_time)),
|
||||
(2, format!("{:.0}", cpu_load.guest)),
|
||||
],
|
||||
)
|
||||
fn print_data(pickers: &[Picker], proc_data: &ProcData, proc_data_before: Option<&ProcData>) {
|
||||
let mut data: Vec<String> = vec![];
|
||||
let mut data_len_excess = 0;
|
||||
pickers.iter().for_each(|f| {
|
||||
f.1(proc_data, proc_data_before, &mut data, &mut data_len_excess);
|
||||
});
|
||||
println!("{}", data.join(" "));
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
@@ -194,22 +114,20 @@ pub fn uu_app() -> Command {
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.infer_long_args(true)
|
||||
// .args([
|
||||
// arg!(<delay> "The delay between updates in seconds").required(false),
|
||||
// arg!(<count> "Number of updates").required(false),
|
||||
// arg!(-a --active "Display active and inactive memory"),
|
||||
// arg!(-f --forks "switch displays the number of forks since boot"),
|
||||
// arg!(-m --slabs "Display slabinfo"),
|
||||
// arg!(-n --one-header "Display the header only once rather than periodically"),
|
||||
// arg!(-s --stats "Displays a table of various event counters and memory statistics"),
|
||||
// arg!(-d --disk "Report disk statistics"),
|
||||
// arg!(-D --disk-sum "Report some summary statistics about disk activity"),
|
||||
// arg!(-p --partition <device> "Detailed statistics about partition"),
|
||||
// arg!(-S --unit <character> "Switches outputs between 1000 (k), 1024 (K), 1000000 (m), or 1048576 (M) bytes"),
|
||||
// arg!(-t --timestamp "Append timestamp to each line"),
|
||||
// arg!(-w --wide "Wide output mode"),
|
||||
// arg!(-y --no-first "Omits first report with statistics since system boot"),
|
||||
// arg!(-V --version "Display version information and exit"),
|
||||
// arg!(-h --help "Display help and exit"),
|
||||
// ])
|
||||
.args([
|
||||
arg!(<delay> "The delay between updates in seconds").required(false),
|
||||
arg!(<count> "Number of updates").required(false),
|
||||
// arg!(-a --active "Display active and inactive memory"),
|
||||
// arg!(-f --forks "switch displays the number of forks since boot"),
|
||||
// arg!(-m --slabs "Display slabinfo"),
|
||||
arg!(-n --"one-header" "Display the header only once rather than periodically"),
|
||||
// arg!(-s --stats "Displays a table of various event counters and memory statistics"),
|
||||
// arg!(-d --disk "Report disk statistics"),
|
||||
// arg!(-D --"disk-sum" "Report some summary statistics about disk activity"),
|
||||
// arg!(-p --partition <device> "Detailed statistics about partition"),
|
||||
// arg!(-S --unit <character> "Switches outputs between 1000 (k), 1024 (K), 1000000 (m), or 1048576 (M) bytes"),
|
||||
// arg!(-t --timestamp "Append timestamp to each line"),
|
||||
// arg!(-w --wide "Wide output mode"),
|
||||
arg!(-y --"no-first" "Omits first report with statistics since system boot"),
|
||||
])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user