diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b256b84 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "system-monitoring-cli" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e6483bb --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "system-monitoring-cli" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7a19eb2 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,103 @@ +use std::fs::File; +use std::io::{self, BufRead, Error, ErrorKind, Result}; +use std::thread::sleep; +use std::time::Duration; + +#[derive(Debug)] +struct CpuTimes { + cpu: String, + user: u64, + nice: u64, + system: u64, + idle: u64, + iowait: u64, + irq: u64, + softirq: u64, + steal: u64, + guest: u64, + guest_nice: u64, +} + +fn read_cpu_times() -> Result> { + if let Ok(file) = File::open("/proc/stat") { + let reader = io::BufReader::new(file); + + let mut cpu_times: Vec = Vec::new(); + for line in reader.lines() { + let line = line?; + if line.starts_with("cpu") { + let times = parse_cputimes(line); + cpu_times.push(times); + } + } + return Ok(cpu_times); + } + Err(Error::new(ErrorKind::NotFound, "CPU data not found")) +} + +fn parse_cputimes(line: String) -> CpuTimes { + let parts: Vec<&str> = line.split_whitespace().collect(); + let times = CpuTimes { + cpu: parts[0].to_owned(), + user: parts[1].parse().unwrap(), + nice: parts[2].parse().unwrap(), + system: parts[3].parse().unwrap(), + idle: parts[4].parse().unwrap(), + iowait: parts[5].parse().unwrap(), + irq: parts[6].parse().unwrap(), + softirq: parts[7].parse().unwrap(), + steal: parts[8].parse().unwrap(), + guest: parts[9].parse().unwrap(), + guest_nice: parts[10].parse().unwrap(), + }; + times +} + +fn calculate_cpu_usage<'a>( + prev_times: &'a Vec, + curr_times: &'a Vec, +) -> Vec<(&'a str, f64)> { + let mut cpu_percentages: Vec<(&str, f64)> = Vec::new(); + + for i in 0..prev_times.len() { + let prev = &prev_times[i]; + let curr = &curr_times[i]; + + let prev_idle = prev.idle + prev.iowait; + let curr_idle = curr.idle + curr.iowait; + + let prev_non_idle = + prev.user + prev.nice + prev.system + prev.irq + prev.softirq + prev.steal; + let curr_non_idle = + curr.user + curr.nice + curr.system + curr.irq + curr.softirq + curr.steal; + + let prev_total = prev_idle + prev_non_idle; + let curr_total = curr_idle + curr_non_idle; + + let totald = curr_total - prev_total; + let idled = curr_idle - prev_idle; + + let cpu_percentage = (totald - idled) as f64 / totald as f64 * 100.0; + + cpu_percentages.push((&prev.cpu, cpu_percentage)); + } + + cpu_percentages +} + +fn main() { + loop { + // First snapshot + let prev = read_cpu_times().expect("Failed to read CPU times"); + // Wait for a second + sleep(Duration::new(1, 0)); + // Second snapshot + let curr = read_cpu_times().expect("Failed to read CPU times"); + + let cpu_usage = calculate_cpu_usage(&prev, &curr); + + for usage in cpu_usage { + println!("{} usage is {:.2}", usage.0 , usage.1); + } + } +}