1
0
mirror of https://github.com/danog/ytop.git synced 2024-11-26 20:15:03 +01:00

Implement process sorting and grouping

This commit is contained in:
Caleb Bassi 2020-01-13 16:55:29 -08:00
parent 43b1ef7f68
commit 8b149e65ae
2 changed files with 58 additions and 7 deletions

View File

@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Changed
- Group processes by default
## 0.1.0 - 2020-01-13 ## 0.1.0 - 2020-01-13
Initial release! Initial release!

View File

@ -11,9 +11,16 @@ use crate::colorscheme::Colorscheme;
use crate::update::UpdatableWidget; use crate::update::UpdatableWidget;
use crate::widgets::block; use crate::widgets::block;
enum ProcSorting {
Cpu,
Mem,
Num,
Command,
}
#[derive(Clone)] #[derive(Clone)]
struct Proc { struct Proc {
pid: u32, num: u32,
name: String, name: String,
commandline: String, commandline: String,
cpu: f32, cpu: f32,
@ -25,9 +32,12 @@ pub struct ProcWidget<'a> {
update_interval: Ratio<u64>, update_interval: Ratio<u64>,
colorscheme: &'a Colorscheme, colorscheme: &'a Colorscheme,
grouping: bool,
selected_row: usize, selected_row: usize,
sorting: ProcSorting,
procs: Vec<Proc>, procs: Vec<Proc>,
grouped_procs: HashMap<String, Proc>,
processes: HashMap<u32, process::Process>, processes: HashMap<u32, process::Process>,
} }
@ -38,9 +48,12 @@ impl ProcWidget<'_> {
update_interval: Ratio::from_integer(1), update_interval: Ratio::from_integer(1),
colorscheme, colorscheme,
grouping: true,
selected_row: 0, selected_row: 0,
sorting: ProcSorting::Cpu,
procs: Vec::new(), procs: Vec::new(),
grouped_procs: HashMap::new(),
processes: HashMap::new(), processes: HashMap::new(),
} }
} }
@ -69,7 +82,7 @@ impl UpdatableWidget for ProcWidget<'_> {
let result = { let result = {
let name = process.name()?; let name = process.name()?;
Ok(Proc { Ok(Proc {
pid: process.pid(), num: process.pid(),
name: name.to_string(), name: name.to_string(),
commandline: process.cmdline()?.unwrap_or_else(|| format!("[{}]", name)), commandline: process.cmdline()?.unwrap_or_else(|| format!("[{}]", name)),
cpu: process.cpu_percent()?, cpu: process.cpu_percent()?,
@ -84,6 +97,21 @@ impl UpdatableWidget for ProcWidget<'_> {
.filter_map(|process: process::ProcessResult<Proc>| process.ok()) .filter_map(|process: process::ProcessResult<Proc>| process.ok())
.collect(); .collect();
self.grouped_procs = HashMap::new();
for proc in self.procs.iter() {
self.grouped_procs
.entry(proc.name.clone())
.and_modify(|e| {
e.num += 1;
e.cpu += proc.cpu;
e.mem += proc.mem;
})
.or_insert_with(|| Proc {
num: 1,
..proc.clone()
});
}
for id in to_remove { for id in to_remove {
self.processes.remove(&id); self.processes.remove(&id);
} }
@ -96,16 +124,35 @@ impl UpdatableWidget for ProcWidget<'_> {
impl Widget for ProcWidget<'_> { impl Widget for ProcWidget<'_> {
fn draw(&mut self, area: Rect, buf: &mut Buffer) { fn draw(&mut self, area: Rect, buf: &mut Buffer) {
let mut procs = self.procs.clone(); let mut procs = if self.grouping {
procs.sort_by(|a, b| a.cpu.partial_cmp(&b.cpu).unwrap()); self.grouped_procs.values().cloned().collect()
} else {
self.procs.clone()
};
procs.sort_by(|a, b| match &self.sorting {
ProcSorting::Cpu => a.cpu.partial_cmp(&b.cpu).unwrap(),
ProcSorting::Mem => a.mem.partial_cmp(&b.mem).unwrap(),
ProcSorting::Num => a.num.cmp(&b.num),
ProcSorting::Command => a.commandline.cmp(&b.commandline),
});
Table::new( Table::new(
["PID", "Command", "CPU%", "Mem%"].iter(), [
if self.grouping { "Count" } else { "PID" },
"Command",
"CPU%",
"Mem%",
]
.iter(),
procs.into_iter().map(|proc| { procs.into_iter().map(|proc| {
Row::StyledData( Row::StyledData(
vec![ vec![
proc.pid.to_string(), proc.num.to_string(),
proc.commandline, if self.grouping {
proc.name
} else {
proc.commandline
},
format!("{:2.1}", proc.cpu), format!("{:2.1}", proc.cpu),
format!("{:2.1}", proc.mem), format!("{:2.1}", proc.mem),
] ]