use crate::row::CommBuf;
use crate::system::{CpuTimes, SwapInfo};
pub fn cpu_times(v: &[i64; 5]) -> CpuTimes {
let n = |x: i64| -> u64 { x.max(0) as u64 };
CpuTimes {
user: n(v[0]),
nice: n(v[1]),
system: n(v[2]),
idle: n(v[4]),
iowait: 0,
irq: n(v[3]),
softirq: 0,
steal: 0,
guest: 0,
guest_nice: 0,
}
}
pub fn swap_from_pages(total: u64, used: u64, page_size: u64) -> SwapInfo {
let total = total.saturating_mul(page_size);
let used = used.saturating_mul(page_size).min(total);
SwapInfo {
total,
used,
free: total - used,
}
}
pub const MAXSLP: u32 = 20;
pub fn state_letter(stat: i8, interruptible: bool, slptime: u32) -> u8 {
match stat {
1 | 2 => b'R', 3 => {
if !interruptible {
b'D'
} else if slptime >= MAXSLP {
b'I'
} else {
b'S'
}
}
4 => b'T', 5 => b'Z', 6 => b'W', 7 => b'L', _ => b'?',
}
}
pub fn sched_policy(pri_class: u8) -> u8 {
match pri_class {
1 => 0,
2 => 1, 3 => 0, 4 => 5, _ => 0,
}
}
pub fn comm_buf(text: &str) -> CommBuf {
let mut out = CommBuf::new();
const MAX: usize = 64;
let end = if text.len() <= MAX {
text.len()
} else {
let mut i = MAX;
while i > 0 && !text.is_char_boundary(i) {
i -= 1;
}
i
};
if out.try_push_str(&text[..end]).is_err() {
out.clear();
for ch in text.chars() {
if out.try_push(ch).is_err() {
break;
}
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cpu_order_maps_cp_sys_to_system_and_cp_intr_to_irq() {
let t = cpu_times(&[3411, 0, 1158, 215, 165_658]);
assert_eq!(t.user, 3411);
assert_eq!(t.system, 1158);
assert_eq!(t.irq, 215);
assert_eq!(t.idle, 165_658);
assert_eq!(t.iowait, 0, "FreeBSD has no iowait counter");
assert_eq!(
t.total(),
t.user + t.nice + t.system + t.idle + t.iowait + t.irq + t.softirq
);
assert_eq!(t.total(), 3411 + 1158 + 165_658 + 215);
assert_eq!(t.busy(), t.total() - t.idle);
}
#[test]
fn a_negative_counter_is_clamped_not_wrapped() {
let t = cpu_times(&[-1, 0, 0, 0, 0]);
assert_eq!(t.user, 0);
assert_eq!(t.total(), 0);
}
#[test]
fn state_letters_match_ps() {
assert_eq!(state_letter(1, false, 0), b'R');
assert_eq!(state_letter(2, false, 0), b'R');
assert_eq!(state_letter(3, false, 0), b'D', "uninterruptible sleep");
assert_eq!(state_letter(3, true, 0), b'S', "interruptible sleep");
assert_eq!(state_letter(3, true, 19), b'S', "just under MAXSLP");
assert_eq!(state_letter(3, true, 20), b'I', "MAXSLP is inclusive");
assert_eq!(state_letter(4, false, 0), b'T');
assert_eq!(state_letter(5, false, 0), b'Z');
assert_eq!(state_letter(6, false, 0), b'W');
assert_eq!(state_letter(7, false, 0), b'L');
assert_eq!(state_letter(0, false, 0), b'?');
assert_eq!(state_letter(99, false, 0), b'?');
assert_eq!(state_letter(-1, false, 0), b'?');
}
#[test]
fn swap_pages_are_scaled_by_the_page_size() {
let s = swap_from_pages(65_536, 16_384, 4096);
assert_eq!(s.total, 256 * 1024 * 1024);
assert_eq!(s.used, 64 * 1024 * 1024);
assert_eq!(s.free, 192 * 1024 * 1024);
assert_eq!(s.total, s.used + s.free);
}
#[test]
fn used_swap_cannot_exceed_total() {
let s = swap_from_pages(100, 200, 4096);
assert_eq!(s.used, s.total);
assert_eq!(s.free, 0);
}
#[test]
fn scheduling_classes_map_to_the_shared_vocabulary() {
assert_eq!(sched_policy(1), 0);
assert_eq!(sched_policy(2), 1); assert_eq!(sched_policy(3), 0); assert_eq!(sched_policy(4), 5); assert_eq!(sched_policy(99), 0, "an unknown class is 'other'");
}
#[test]
fn comm_is_truncated_by_the_buffer_not_by_a_byte_slice() {
let long = "x".repeat(200);
let comm = comm_buf(&long);
assert_eq!(comm.len(), 64);
assert!(comm.as_str().is_char_boundary(comm.len()));
}
}