Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ or if you want per-process swap usage:
zmem -p
```

You can also sort per-process output by a different memory column:

```bash
zmem -p --sort-by uss
```

Available values for `--sort-by` are `swap` (default), `uss`, `pss`, and `rss`.

![zmem](assets/zmem.png)

## Contributing
Expand Down
8 changes: 6 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use clap::Parser;

use memory::MemoryStats;
use process::Processes;
use process::{Processes, SortColumn};

mod memory;
mod process;
Expand All @@ -21,6 +21,10 @@ struct Args {
/// (default: true)
#[clap(short, long, default_value = "true")]
summary: bool,
/// Sort per-process output by memory column
/// (default: swap)
#[clap(long, value_enum, default_value_t = SortColumn::Swap)]
sort_by: SortColumn,
}

#[tokio::main]
Expand All @@ -37,7 +41,7 @@ async fn main() {

if args.per_process {
let mut processes = Processes::new();
if let Err(e) = processes.update().await {
if let Err(e) = processes.update(args.sort_by).await {
println!("error updating processes: {}", e);
}

Expand Down
45 changes: 42 additions & 3 deletions src/process.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
use colored::Colorize;
use clap::ValueEnum;
use std::fs;
use tokio::task;

use crate::memory::ProcessMemoryStats;
use crate::utils::{format_size, get_cmd};
use crate::AnyError;

#[derive(Copy, Clone, Debug, ValueEnum)]
pub enum SortColumn {
Swap,
Uss,
Pss,
Rss,
}

pub struct Process {
pid: u32,
command: String,
Expand Down Expand Up @@ -64,7 +73,7 @@ impl Processes {
/// let mut processes = Processes::new();
/// processes.update()?;
/// ```
pub async fn update(&mut self) -> Result<(), AnyError> {
pub async fn update(&mut self, sort_by: SortColumn) -> Result<(), AnyError> {
let processes = fs::read_dir("/proc")?
.filter_map(|entry| {
let entry = entry.ok()?;
Expand All @@ -76,12 +85,13 @@ impl Processes {

// Wait for all the processes to finish
let processes = futures::future::try_join_all(processes).await?;
// Sort the processes by swap usage
// Sort the processes by selected memory column
self.processes = processes
.into_iter()
.filter_map(Result::ok)
.collect();
self.processes.sort_by_key(|p| p.memory.swap);
self.processes
.sort_by_key(|p| process_sort_key(&p.memory, sort_by));
Ok(())
}

Expand All @@ -100,3 +110,32 @@ impl Processes {
}
}
}

fn process_sort_key(memory: &ProcessMemoryStats, sort_by: SortColumn) -> u64 {
match sort_by {
SortColumn::Swap => memory.swap,
SortColumn::Uss => memory.uss,
SortColumn::Pss => memory.pss,
SortColumn::Rss => memory.rss,
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn process_sort_key_uses_requested_column() {
let memory = ProcessMemoryStats {
swap: 1,
uss: 2,
pss: 3,
rss: 4,
};

assert_eq!(process_sort_key(&memory, SortColumn::Swap), 1);
assert_eq!(process_sort_key(&memory, SortColumn::Uss), 2);
assert_eq!(process_sort_key(&memory, SortColumn::Pss), 3);
assert_eq!(process_sort_key(&memory, SortColumn::Rss), 4);
}
}