Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Adds tree view #223

Merged
merged 21 commits into from
Sep 7, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Switch to using pid_t
  • Loading branch information
ClementTsang committed Sep 4, 2020
commit 7f7c8eefd457ac4430d27926ca31035d540ab908
7 changes: 4 additions & 3 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::{
canvas, constants,
utils::error::{BottomError, Result},
};
use libc::pid_t;

pub mod data_farmer;
pub mod data_harvester;
Expand Down Expand Up @@ -67,7 +68,7 @@ pub struct App {
pub dd_err: Option<String>,

#[builder(default, setter(skip))]
to_delete_process_list: Option<(String, Vec<u32>)>,
to_delete_process_list: Option<(String, Vec<pid_t>)>,

#[builder(default = false, setter(skip))]
pub is_frozen: bool,
Expand Down Expand Up @@ -885,7 +886,7 @@ impl App {
if proc_widget_state.scroll_state.current_scroll_position
< corresponding_filtered_process_list.len()
{
let current_process: (String, Vec<u32>);
let current_process: (String, Vec<pid_t>);
if self.is_grouped(self.current_widget.widget_id) {
if let Some(process) = &corresponding_filtered_process_list
.get(proc_widget_state.scroll_state.current_scroll_position)
Expand Down Expand Up @@ -1224,7 +1225,7 @@ impl App {
}
}

pub fn get_to_delete_processes(&self) -> Option<(String, Vec<u32>)> {
pub fn get_to_delete_processes(&self) -> Option<(String, Vec<pid_t>)> {
self.to_delete_process_list.clone()
}

Expand Down
3 changes: 2 additions & 1 deletion src/app/data_harvester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use battery::{Battery, Manager};
use crate::app::layout_manager::UsedWidgets;

use futures::join;
use libc::pid_t;

pub mod battery_harvester;
pub mod cpu;
Expand Down Expand Up @@ -72,7 +73,7 @@ pub struct DataCollector {
pub data: Data,
sys: System,
#[cfg(target_os = "linux")]
pid_mapping: HashMap<u32, processes::PrevProcDetails>,
pid_mapping: HashMap<pid_t, processes::PrevProcDetails>,
#[cfg(target_os = "linux")]
prev_idle: f64,
#[cfg(target_os = "linux")]
Expand Down
19 changes: 10 additions & 9 deletions src/app/data_harvester/processes.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use libc::pid_t;
use std::path::PathBuf;
use sysinfo::ProcessStatus;

Expand Down Expand Up @@ -59,8 +60,8 @@ impl Default for ProcessSorting {

#[derive(Debug, Clone, Default)]
pub struct ProcessHarvest {
pub pid: u32,
pub parent_pid: Option<u32>, // Remember, parent_pid 0 is root...
pub pid: pid_t,
pub parent_pid: Option<pid_t>, // Remember, parent_pid 0 is root...
pub cpu_usage_percent: f64,
pub mem_usage_percent: f64,
pub mem_usage_bytes: u64,
Expand Down Expand Up @@ -90,7 +91,7 @@ pub struct PrevProcDetails {
}

impl PrevProcDetails {
pub fn new(pid: u32) -> Self {
pub fn new(pid: pid_t) -> Self {
PrevProcDetails {
proc_io_path: PathBuf::from(format!("/proc/{}/io", pid)),
proc_exe_path: PathBuf::from(format!("/proc/{}/exe", pid)),
Expand Down Expand Up @@ -242,8 +243,8 @@ fn get_linux_cpu_usage(
#[allow(clippy::too_many_arguments)]
#[cfg(target_os = "linux")]
fn read_proc<S: core::hash::BuildHasher>(
pid: u32, cpu_usage: f64, cpu_fraction: f64,
pid_mapping: &mut HashMap<u32, PrevProcDetails, S>, use_current_cpu_total: bool,
pid: pid_t, cpu_usage: f64, cpu_fraction: f64,
pid_mapping: &mut HashMap<pid_t, PrevProcDetails, S>, use_current_cpu_total: bool,
time_difference_in_secs: u64, mem_total_kb: u64, page_file_kb: u64,
) -> error::Result<ProcessHarvest> {
let pid_stat = pid_mapping
Expand Down Expand Up @@ -283,7 +284,7 @@ fn read_proc<S: core::hash::BuildHasher>(
&mut pid_stat.cpu_time,
use_current_cpu_total,
)?;
let parent_pid = stat[1].parse::<u32>().ok();
let parent_pid = stat[1].parse::<pid_t>().ok();
let (_vsize, rss) = get_linux_process_vsize_rss(&stat);
let mem_usage_kb = rss * page_file_kb;
let mem_usage_percent = mem_usage_kb as f64 / mem_total_kb as f64 * 100.0;
Expand Down Expand Up @@ -340,14 +341,14 @@ fn read_proc<S: core::hash::BuildHasher>(
#[cfg(target_os = "linux")]
pub fn linux_get_processes_list(
prev_idle: &mut f64, prev_non_idle: &mut f64,
pid_mapping: &mut HashMap<u32, PrevProcDetails, RandomState>, use_current_cpu_total: bool,
pid_mapping: &mut HashMap<pid_t, PrevProcDetails, RandomState>, use_current_cpu_total: bool,
time_difference_in_secs: u64, mem_total_kb: u64, page_file_kb: u64,
) -> crate::utils::error::Result<Vec<ProcessHarvest>> {
if let Ok((cpu_usage, cpu_fraction)) = cpu_usage_calculation(prev_idle, prev_non_idle) {
let process_vector: Vec<ProcessHarvest> = std::fs::read_dir("/proc")?
.filter_map(|dir| {
if let Ok(dir) = dir {
let pid = dir.file_name().to_string_lossy().trim().parse::<u32>();
let pid = dir.file_name().to_string_lossy().trim().parse::<pid_t>();
if let Ok(pid) = pid {
// I skip checking if the path is also a directory, it's not needed I think?
if let Ok(process_object) = read_proc(
Expand Down Expand Up @@ -427,7 +428,7 @@ pub fn windows_macos_get_processes_list(
let disk_usage = process_val.disk_usage();

process_vector.push(ProcessHarvest {
pid: process_val.pid() as u32,
pid: process_val.pid(),
parent_pid: process_val.parent(),
name,
command,
Expand Down
3 changes: 2 additions & 1 deletion src/app/process_killer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use winapi::{

/// This file is meant to house (OS specific) implementations on how to kill processes.
use crate::utils::error::BottomError;
use libc::pid_t;

#[cfg(target_os = "windows")]
struct Process(HANDLE);
Expand All @@ -31,7 +32,7 @@ impl Process {
}

/// Kills a process, given a PID.
pub fn kill_process_given_pid(pid: u32) -> crate::utils::error::Result<()> {
pub fn kill_process_given_pid(pid: pid_t) -> crate::utils::error::Result<()> {
if cfg!(target_os = "linux") || cfg!(target_os = "macos") {
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
Expand Down
29 changes: 16 additions & 13 deletions src/data_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
app::{data_farmer, data_harvester, App, Filter},
utils::gen_util::*,
};
use libc::pid_t;

/// Point is of time, data
type Point = (f64, f64);
Expand Down Expand Up @@ -41,16 +42,16 @@ pub struct ConvertedNetworkData {
// TODO: [REFACTOR] Process data... stuff really needs a rewrite. Again.
#[derive(Clone, Default, Debug)]
pub struct ConvertedProcessData {
pub pid: u32,
pub ppid: Option<u32>,
pub pid: pid_t,
pub ppid: Option<pid_t>,
pub name: String,
pub command: String,
pub is_thread: Option<bool>,
pub cpu_percent_usage: f64,
pub mem_percent_usage: f64,
pub mem_usage_bytes: u64,
pub mem_usage_str: (f64, String),
pub group_pids: Vec<u32>,
pub group_pids: Vec<pid_t>,
pub read_per_sec: String,
pub write_per_sec: String,
pub total_read: String,
Expand Down Expand Up @@ -457,14 +458,16 @@ pub fn tree_process_data(
) -> Vec<ConvertedProcessData> {
// Let's first build up a (really terrible) parent -> child mapping...
// At the same time, let's make a mapping of PID -> process data!
let mut parent_child_mapping: HashMap<u32, Vec<u32>> = HashMap::default();
let mut pid_process_mapping: HashMap<u32, &ConvertedProcessData> = HashMap::default();
let mut parent_child_mapping: HashMap<pid_t, Vec<pid_t>> = HashMap::default();
let mut pid_process_mapping: HashMap<pid_t, &ConvertedProcessData> = HashMap::default();

single_process_data.iter().for_each(|process| {
parent_child_mapping
.entry(process.ppid.unwrap_or(0))
.or_insert_with(Vec::new)
.push(process.pid);
if let Some(ppid) = process.ppid {
parent_child_mapping
.entry(ppid)
.or_insert_with(Vec::new)
.push(process.pid);
}

// There should be no collisions...
if pid_process_mapping.contains_key(&process.pid) {
Expand All @@ -474,8 +477,8 @@ pub fn tree_process_data(
});

// Turn the parent-child mapping into a "list" via DFS...
let mut pids_to_explore: VecDeque<u32> = VecDeque::default();
let mut explored_pids: Vec<u32> = vec![0];
let mut pids_to_explore: VecDeque<pid_t> = VecDeque::default();
let mut explored_pids: Vec<pid_t> = vec![0];
if let Some(zero_pid) = parent_child_mapping.get(&0) {
pids_to_explore.extend(zero_pid);
} else {
Expand Down Expand Up @@ -508,11 +511,11 @@ pub fn group_process_data(
) -> Vec<ConvertedProcessData> {
#[derive(Clone, Default, Debug)]
struct SingleProcessData {
pub pid: u32,
pub pid: pid_t,
pub cpu_percent_usage: f64,
pub mem_percent_usage: f64,
pub mem_usage_bytes: u64,
pub group_pids: Vec<u32>,
pub group_pids: Vec<pid_t>,
pub read_per_sec: f64,
pub write_per_sec: f64,
pub total_read: f64,
Expand Down