vmstat: impl delay, count, --one-heder, --no-first

This commit is contained in:
Bluemangoo
2025-04-05 15:02:02 +08:00
parent 116c9e8786
commit 1e63a38afb
6 changed files with 402 additions and 263 deletions
Generated
+2 -66
View File
@@ -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
View File
@@ -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"
+3 -4
View File
@@ -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
View File
@@ -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,
}
}
}
+196
View File
@@ -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
View File
@@ -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"),
])
}