mirror of
https://github.com/ClementTsang/bottom.git
synced 2024-11-28 19:12:43 +03:00
More refactoring.
This commit is contained in:
parent
b7081dd0e4
commit
50d3be05dd
@ -8,6 +8,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.9"
|
||||
clap = "2.33.0"
|
||||
crossterm = "0.10.2"
|
||||
futures-preview = "0.3.0-alpha.18"
|
||||
fern = "0.5"
|
||||
|
4
TODO.md
4
TODO.md
@ -10,9 +10,11 @@
|
||||
|
||||
* Add custom error because it's really messy
|
||||
|
||||
* Scrolling event
|
||||
|
||||
* Keybindings
|
||||
|
||||
* FIX PROCESSES AHHHHHH
|
||||
~~* FIX PROCESSES AHHHHHH~~
|
||||
|
||||
* Refactor everything because it's a mess
|
||||
|
||||
|
@ -4,7 +4,7 @@ use sysinfo::{ProcessorExt, System, SystemExt};
|
||||
#[derive(Clone)]
|
||||
pub struct CPUData {
|
||||
pub cpu_name : Box<str>,
|
||||
pub cpu_usage : u32,
|
||||
pub cpu_usage : f64,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -20,7 +20,7 @@ pub fn get_cpu_data_list(sys : &System) -> Result<CPUPackage, heim::Error> {
|
||||
for cpu in cpu_data {
|
||||
cpu_vec.push(CPUData {
|
||||
cpu_name : Box::from(cpu.get_name()),
|
||||
cpu_usage : (cpu.get_cpu_usage() * 100_f32).ceil() as u32,
|
||||
cpu_usage : f64::from(cpu.get_cpu_usage()) * 100_f64,
|
||||
})
|
||||
}
|
||||
|
6
src/app/data_collection/mod.rs
Normal file
6
src/app/data_collection/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
pub mod cpu;
|
||||
pub mod disks;
|
||||
pub mod mem;
|
||||
pub mod network;
|
||||
pub mod processes;
|
||||
pub mod temperature;
|
@ -5,6 +5,8 @@ use sysinfo::{NetworkExt, System, SystemExt};
|
||||
pub struct NetworkData {
|
||||
pub rx : u64,
|
||||
pub tx : u64,
|
||||
pub total_rx : u64,
|
||||
pub total_tx : u64,
|
||||
pub instant : Instant,
|
||||
}
|
||||
|
||||
@ -13,6 +15,8 @@ pub fn get_network_data(sys : &System) -> Result<NetworkData, heim::Error> {
|
||||
Ok(NetworkData {
|
||||
rx : network_data.get_income(),
|
||||
tx : network_data.get_outcome(),
|
||||
total_rx : 0,
|
||||
total_tx : 0,
|
||||
instant : Instant::now(),
|
||||
})
|
||||
}
|
@ -52,10 +52,14 @@ fn vangelis_cpu_usage_calculation(prev_idle : &mut f64, prev_non_idle : &mut f64
|
||||
let total_delta : f64 = total - prev_total;
|
||||
let idle_delta : f64 = idle - *prev_idle;
|
||||
|
||||
debug!("Vangelis function: CPU PERCENT: {}", (total_delta - idle_delta) / total_delta * 100_f64);
|
||||
|
||||
*prev_idle = idle;
|
||||
*prev_non_idle = non_idle;
|
||||
|
||||
Ok(total_delta - idle_delta)
|
||||
let result = if total_delta - idle_delta != 0_f64 { total_delta - idle_delta } else { 1_f64 };
|
||||
|
||||
Ok(result) // This works, REALLY damn well. The percentage check is within like 2% of the sysinfo one.
|
||||
}
|
||||
|
||||
fn get_ordering<T : std::cmp::PartialOrd>(a_val : T, b_val : T, reverse_order : bool) -> std::cmp::Ordering {
|
||||
@ -96,16 +100,18 @@ fn get_process_cpu_stats(pid : u32) -> std::io::Result<f64> {
|
||||
|
||||
let stat_results = std::fs::read_to_string(path)?;
|
||||
let val = stat_results.split_whitespace().collect::<Vec<&str>>();
|
||||
let utime = val[13].parse::<f64>().unwrap_or(-1_f64);
|
||||
let stime = val[14].parse::<f64>().unwrap_or(-1_f64);
|
||||
let utime = val[13].parse::<f64>().unwrap_or(0_f64);
|
||||
let stime = val[14].parse::<f64>().unwrap_or(0_f64);
|
||||
|
||||
Ok(utime + stime)
|
||||
debug!("PID: {}, utime: {}, stime: {}", pid, utime, stime);
|
||||
|
||||
Ok(utime + stime) // This seems to match top...
|
||||
}
|
||||
|
||||
fn linux_cpu_usage(pid : u32, cpu_usage : f64, previous_pid_stats : &mut HashMap<String, f64>) -> std::io::Result<f64> {
|
||||
// Based heavily on https://stackoverflow.com/a/23376195 and https://stackoverflow.com/a/1424556
|
||||
let before_proc_val : f64 = if previous_pid_stats.contains_key(&pid.to_string()) {
|
||||
*previous_pid_stats.get(&pid.to_string()).unwrap_or(&-1_f64)
|
||||
*previous_pid_stats.get(&pid.to_string()).unwrap_or(&0_f64)
|
||||
}
|
||||
else {
|
||||
0_f64
|
@ -1,9 +1,5 @@
|
||||
pub mod cpu;
|
||||
pub mod disks;
|
||||
pub mod mem;
|
||||
pub mod network;
|
||||
pub mod processes;
|
||||
pub mod temperature;
|
||||
pub mod data_collection;
|
||||
use data_collection::{cpu, disks, mem, network, processes, temperature};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use sysinfo::{System, SystemExt};
|
||||
@ -46,7 +42,7 @@ pub struct DataState {
|
||||
pub data : Data,
|
||||
sys : System,
|
||||
stale_max_seconds : u64,
|
||||
prev_pid_stats : HashMap<String, f64>,
|
||||
prev_pid_stats : HashMap<String, f64>, // TODO: Purge list?
|
||||
prev_idle : f64,
|
||||
prev_non_idle : f64,
|
||||
}
|
121
src/main.rs
121
src/main.rs
@ -4,19 +4,20 @@ use std::{io, sync::mpsc, thread, time::Duration};
|
||||
use tui::{
|
||||
backend::CrosstermBackend,
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Style},
|
||||
style::{Color, Modifier, Style},
|
||||
widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Row, Table, Widget},
|
||||
Terminal,
|
||||
};
|
||||
|
||||
mod widgets;
|
||||
mod app;
|
||||
use app::data_collection;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
enum Event<I> {
|
||||
Input(I),
|
||||
Update(Box<widgets::Data>),
|
||||
Update(Box<app::Data>),
|
||||
}
|
||||
|
||||
const STALE_MAX_SECONDS : u64 = 60;
|
||||
@ -30,7 +31,7 @@ async fn main() -> Result<(), io::Error> {
|
||||
let tick_rate_in_milliseconds : u64 = 250;
|
||||
let update_rate_in_milliseconds : u64 = 1000; // TODO: Must set a check to prevent this from going into negatives!
|
||||
|
||||
let mut app = widgets::App::new("rustop");
|
||||
let mut app = app::App::new("rustop");
|
||||
|
||||
let log = init_logger();
|
||||
|
||||
@ -53,7 +54,7 @@ async fn main() -> Result<(), io::Error> {
|
||||
}
|
||||
|
||||
// Event loop
|
||||
let mut data_state = widgets::DataState::default();
|
||||
let mut data_state = app::DataState::default();
|
||||
data_state.init();
|
||||
data_state.set_stale_max_seconds(STALE_MAX_SECONDS);
|
||||
{
|
||||
@ -70,7 +71,10 @@ async fn main() -> Result<(), io::Error> {
|
||||
|
||||
terminal.clear()?;
|
||||
|
||||
let mut app_data = widgets::Data::default();
|
||||
let mut app_data = app::Data::default();
|
||||
let mut swap_data : Vec<(f64, f64)> = Vec::new();
|
||||
let mut mem_data : Vec<(f64, f64)> = Vec::new();
|
||||
|
||||
loop {
|
||||
if let Ok(recv) = rx.recv_timeout(Duration::from_millis(tick_rate_in_milliseconds)) {
|
||||
match recv {
|
||||
@ -87,16 +91,22 @@ async fn main() -> Result<(), io::Error> {
|
||||
}
|
||||
|
||||
if app.to_be_resorted {
|
||||
widgets::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse);
|
||||
data_collection::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse);
|
||||
app.to_be_resorted = false;
|
||||
}
|
||||
try_debug(&log, "Input event complete.");
|
||||
|
||||
// Only update processes
|
||||
}
|
||||
Event::Update(data) => {
|
||||
try_debug(&log, "Update event fired!");
|
||||
app_data = *data;
|
||||
widgets::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse);
|
||||
data_collection::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse);
|
||||
try_debug(&log, "Update event complete.");
|
||||
|
||||
// Convert all data into tui components
|
||||
mem_data = update_mem_data_points(&app_data);
|
||||
swap_data = update_swap_data_points(&app_data);
|
||||
}
|
||||
}
|
||||
if app.should_quit {
|
||||
@ -105,14 +115,33 @@ async fn main() -> Result<(), io::Error> {
|
||||
}
|
||||
|
||||
// Draw!
|
||||
draw_data(&mut terminal, &app_data)?;
|
||||
// TODO: We should change this btw! It should not redraw everything on every tick!
|
||||
draw_data(&mut terminal, &app_data, &mem_data, &swap_data)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data : &widgets::Data) -> Result<(), io::Error> {
|
||||
// Convert data into tui components
|
||||
fn update_temp_row(app_data : &app::Data) {
|
||||
}
|
||||
|
||||
fn update_process_row(app_data : &app::Data) {
|
||||
}
|
||||
|
||||
fn update_cpu_data_points(app_data : &app::Data) {
|
||||
}
|
||||
|
||||
fn update_mem_data_points(app_data : &app::Data) -> Vec<(f64, f64)> {
|
||||
convert_mem_data(&app_data.memory)
|
||||
}
|
||||
|
||||
fn update_swap_data_points(app_data : &app::Data) -> Vec<(f64, f64)> {
|
||||
convert_mem_data(&app_data.swap)
|
||||
}
|
||||
|
||||
fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data : &app::Data, mem_data : &[(f64, f64)], swap_data : &[(f64, f64)]) -> Result<(), io::Error> {
|
||||
const COLOUR_LIST : [Color; 6] = [Color::LightCyan, Color::LightMagenta, Color::LightRed, Color::LightGreen, Color::LightYellow, Color::LightBlue];
|
||||
|
||||
let temperature_rows = app_data.list_of_temperature.iter().map(|sensor| {
|
||||
Row::StyledData(
|
||||
vec![sensor.component_name.to_string(), sensor.temperature.to_string() + "C"].into_iter(), // TODO: Change this based on temperature type
|
||||
@ -134,6 +163,32 @@ fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data :
|
||||
)
|
||||
});
|
||||
|
||||
let mut dataset_vector : Vec<Dataset> = Vec::new();
|
||||
let mut data_vector : Vec<Vec<(f64, f64)>> = Vec::new();
|
||||
|
||||
if !app_data.list_of_cpu_packages.is_empty() {
|
||||
for cpu_num in 0..app_data.list_of_cpu_packages.last().unwrap().cpu_vec.len() {
|
||||
let mut this_cpu_data : Vec<(f64, f64)> = Vec::new();
|
||||
let current_time = std::time::Instant::now();
|
||||
|
||||
for cpu in &app_data.list_of_cpu_packages {
|
||||
this_cpu_data.push((STALE_MAX_SECONDS as f64 - current_time.duration_since(cpu.instant).as_secs_f64(), cpu.cpu_vec[cpu_num].cpu_usage));
|
||||
}
|
||||
|
||||
data_vector.push(this_cpu_data);
|
||||
}
|
||||
|
||||
for (i, data) in data_vector.iter().enumerate() {
|
||||
dataset_vector.push(
|
||||
Dataset::default()
|
||||
.name(&*(app_data.list_of_cpu_packages.last().unwrap().cpu_vec[i].cpu_name))
|
||||
.marker(Marker::Braille)
|
||||
.style(Style::default().fg(COLOUR_LIST[i % COLOUR_LIST.len()]))
|
||||
.data(&data),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let process_rows = app_data.list_of_processes.iter().map(|process| {
|
||||
Row::StyledData(
|
||||
vec![
|
||||
@ -200,24 +255,15 @@ fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data :
|
||||
|
||||
// CPU usage graph
|
||||
{
|
||||
debug!("Drawing CPU...");
|
||||
let x_axis : Axis<String> = Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 60.0]);
|
||||
let y_axis = Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 100.0]).labels(&["0.0", "50.0", "100.0"]);
|
||||
|
||||
Chart::default()
|
||||
.block(Block::default().title("CPU Usage").borders(Borders::ALL))
|
||||
.x_axis(x_axis)
|
||||
.y_axis(y_axis)
|
||||
.datasets(&[
|
||||
Dataset::default()
|
||||
.name("CPU0")
|
||||
.marker(Marker::Braille)
|
||||
.style(Style::default().fg(Color::Cyan))
|
||||
.data(&convert_cpu_data(0, &app_data.list_of_cpu_packages)),
|
||||
Dataset::default()
|
||||
.name("CPU1")
|
||||
.marker(Marker::Braille)
|
||||
.style(Style::default().fg(Color::LightMagenta))
|
||||
.data(&convert_cpu_data(1, &app_data.list_of_cpu_packages)),
|
||||
])
|
||||
.datasets(&dataset_vector)
|
||||
.render(&mut f, top_chunks[0]);
|
||||
}
|
||||
|
||||
@ -230,16 +276,8 @@ fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data :
|
||||
.x_axis(x_axis)
|
||||
.y_axis(y_axis)
|
||||
.datasets(&[
|
||||
Dataset::default()
|
||||
.name("MEM")
|
||||
.marker(Marker::Braille)
|
||||
.style(Style::default().fg(Color::Cyan))
|
||||
.data(&convert_mem_data(&app_data.memory)),
|
||||
Dataset::default()
|
||||
.name("SWAP")
|
||||
.marker(Marker::Braille)
|
||||
.style(Style::default().fg(Color::LightGreen))
|
||||
.data(&convert_mem_data(&app_data.swap)),
|
||||
Dataset::default().name("MEM").marker(Marker::Braille).style(Style::default().fg(Color::Cyan)).data(&mem_data),
|
||||
Dataset::default().name("SWAP").marker(Marker::Braille).style(Style::default().fg(Color::LightGreen)).data(&swap_data),
|
||||
])
|
||||
.render(&mut f, top_chunks[1]);
|
||||
}
|
||||
@ -278,22 +316,7 @@ fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data :
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Remove this count, this is for testing, lol
|
||||
fn convert_cpu_data(count : usize, cpu_data : &[widgets::cpu::CPUPackage]) -> Vec<(f64, f64)> {
|
||||
let mut result : Vec<(f64, f64)> = Vec::new();
|
||||
let current_time = std::time::Instant::now();
|
||||
|
||||
for data in cpu_data {
|
||||
result.push((
|
||||
STALE_MAX_SECONDS as f64 - current_time.duration_since(data.instant).as_secs() as f64,
|
||||
f64::from(data.cpu_vec[count + 1].cpu_usage),
|
||||
));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn convert_mem_data(mem_data : &[widgets::mem::MemData]) -> Vec<(f64, f64)> {
|
||||
fn convert_mem_data(mem_data : &[app::data_collection::mem::MemData]) -> Vec<(f64, f64)> {
|
||||
let mut result : Vec<(f64, f64)> = Vec::new();
|
||||
let current_time = std::time::Instant::now();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user