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

Add Process disk usage (bytes read/written) #248

Closed
wants to merge 12 commits into from
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ doc-comment = "0.3"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "objbase"] }
ntapi = "0.3"
winrt = { version = "0.6.0", features = ["windows-system"]}

[target.'cfg(not(any(target_os = "unknown", target_arch = "wasm32")))'.dependencies]
libc = "0.2"
Expand Down
12 changes: 12 additions & 0 deletions src/linux/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ pub struct Process {
/// Tasks run by this process.
pub tasks: HashMap<Pid, Process>,
pub(crate) stat_file: Option<File>,
pub(crate) read_bytes: u64,
pub(crate) written_bytes: u64
}

impl ProcessExt for Process {
Expand Down Expand Up @@ -155,6 +157,8 @@ impl ProcessExt for Process {
HashMap::new()
},
stat_file: None,
read_bytes: 0,
written_bytes: 0
}
}

Expand Down Expand Up @@ -215,6 +219,14 @@ impl ProcessExt for Process {
fn cpu_usage(&self) -> f32 {
self.cpu_usage
}

fn read_bytes(&self) -> u64{
self.read_bytes
}

fn written_bytes(&self) -> u64{
self.written_bytes
}
}

impl Drop for Process {
Expand Down
19 changes: 19 additions & 0 deletions src/linux/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ fn _get_process_data(
uptime,
now,
);
update_process_disk_activity(entry);
return Ok(None);
}

Expand Down Expand Up @@ -690,9 +691,27 @@ fn _get_process_data(
uptime,
now,
);
update_process_disk_activity(&mut p);
Ok(Some(p))
}

fn update_process_disk_activity(p: &mut Process){
let path = PathBuf::from(format!("/proc/{}/io", p.pid));
let data = match get_all_data(&path, 16_384){
Ok(d) => d,
Err(_) => return
};
let data: Vec<Vec<&str>> = data.split("\n").map(|l| l.split(": ").collect()).collect();
for d in data.iter(){
if d[0] == "read_bytes"{
p.read_bytes = d[1].parse::<u64>().unwrap_or(0);
}
else if d[0] == "write_bytes"{
p.written_bytes = d[1].parse::<u64>().unwrap_or(0);
}
}
}

fn copy_from_file(entry: &Path) -> Vec<String> {
match File::open(entry.to_str().unwrap_or("/")) {
Ok(mut f) => {
Expand Down
30 changes: 30 additions & 0 deletions src/mac/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ extern "C" {
// pub fn proc_name(pid: i32, buf: *mut i8, bufsize: u32) -> i32;
}

#[link(name = "proc", kind = "dylib")]
extern {
pub fn proc_pid_rusage(pid: c_int, flavor: c_int, buffer: *mut c_void) -> c_int;
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
macro_rules! cfg_if {
($(
Expand Down Expand Up @@ -342,6 +347,31 @@ pub struct xsw_usage {
pub xsu_encrypted: boolean_t,
}

//https://github.com/andrewdavidmackenzie/libproc-rs/blob/master/src/libproc/pid_rusage.rs
#[repr(C)]
#[derive(Debug, Default)]
pub struct RUsageInfoV2 {
pub ri_uuid : [u8; 16],
pub ri_user_time : u64,
pub ri_system_time : u64,
pub ri_pkg_idle_wkups : u64,
pub ri_interrupt_wkups : u64,
pub ri_pageins : u64,
pub ri_wired_size : u64,
pub ri_resident_size : u64,
pub ri_phys_footprint : u64,
pub ri_proc_start_abstime : u64,
pub ri_proc_exit_abstime : u64,
pub ri_child_user_time : u64,
pub ri_child_system_time : u64,
pub ri_child_pkg_idle_wkups : u64,
pub ri_child_interrupt_wkups: u64,
pub ri_child_pageins : u64,
pub ri_child_elapsed_abstime: u64,
pub ri_diskio_bytesread : u64,
pub ri_diskio_byteswritten : u64,
}

//pub const HOST_CPU_LOAD_INFO_COUNT: usize = 4;
//pub const HOST_CPU_LOAD_INFO: u32 = 3;
pub const KERN_SUCCESS: kern_return_t = 0;
Expand Down
36 changes: 35 additions & 1 deletion src/mac/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ pub struct Process {
///
/// This is very likely this one that you want instead of `process_status`.
pub status: Option<ThreadStatus>,
pub(crate) read_bytes: u64,
pub(crate) written_bytes: u64
}

impl Process {
Expand Down Expand Up @@ -179,6 +181,8 @@ impl Process {
gid: 0,
process_status: ProcessStatus::Unknown(0),
status: None,
read_bytes: 0,
written_bytes: 0
}
}

Expand Down Expand Up @@ -214,6 +218,8 @@ impl Process {
gid: 0,
process_status: ProcessStatus::Unknown(0),
status: None,
read_bytes: 0,
written_bytes: 0
}
}
}
Expand Down Expand Up @@ -242,6 +248,8 @@ impl ProcessExt for Process {
gid: 0,
process_status: ProcessStatus::Unknown(0),
status: None,
read_bytes: 0,
written_bytes: 0
}
}

Expand Down Expand Up @@ -300,6 +308,14 @@ impl ProcessExt for Process {
fn cpu_usage(&self) -> f32 {
self.cpu_usage
}

fn read_bytes(&self) -> u64{
self.read_bytes
}

fn written_bytes(&self) -> u64{
self.written_bytes
}
}

#[allow(unused_must_use)]
Expand Down Expand Up @@ -422,6 +438,7 @@ pub(crate) fn update_process(

p.memory = task_info.pti_resident_size >> 10; // divide by 1024
p.virtual_memory = task_info.pti_virtual_size >> 10; // divide by 1024
update_proc_disk_activity(p);
return Ok(None);
}

Expand Down Expand Up @@ -606,11 +623,28 @@ pub(crate) fn update_process(
p.uid = info.pbi_uid;
p.gid = info.pbi_gid;
p.process_status = ProcessStatus::from(info.pbi_status);

update_proc_disk_activity(&mut p);
Ok(Some(p))
}
}

fn update_proc_disk_activity(p: &mut Process){
let mut pidrusage = ffi::RUsageInfoV2::default();
let ptr = &mut pidrusage as *mut _ as *mut c_void;
let retval: i32;
unsafe{
retval = ffi::proc_pid_rusage(p.pid() as c_int, 2, ptr);
}

if retval < 0{
panic!("proc_pid_rusage failed: {:?}", retval);
}
else{
p.read_bytes = pidrusage.ri_diskio_bytesread;
p.written_bytes = pidrusage.ri_diskio_byteswritten;
}
}

pub(crate) fn get_proc_list() -> Option<Vec<Pid>> {
let count = unsafe { ffi::proc_listallpids(::std::ptr::null_mut(), 0) };
if count < 1 {
Expand Down
3 changes: 2 additions & 1 deletion src/sysinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
#![crate_name = "sysinfo"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![deny(missing_docs)]
#![warn(missing_docs)]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't change this one.

//#![deny(warnings)]
#![allow(unknown_lints)]

Expand All @@ -69,6 +69,7 @@ cfg_if! {
use windows as sys;
extern crate winapi;
extern crate ntapi;
extern crate winrt;
} else if #[cfg(unix)] {
mod linux;
use linux as sys;
Expand Down
6 changes: 6 additions & 0 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ pub trait ProcessExt {

/// Returns the total CPU usage.
fn cpu_usage(&self) -> f32;

/// Returns number of bytes read from disk
fn read_bytes(&self) -> u64;

/// Returns number of bytes written to disk
fn written_bytes(&self) -> u64;
}

/// Contains all the methods of the `Processor` struct.
Expand Down
55 changes: 55 additions & 0 deletions src/windows/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use winapi::um::winnt::{
HANDLE, /*, PWSTR*/ PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, PROCESS_VM_READ,
ULARGE_INTEGER, /*THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION, THREAD_SUSPEND_RESUME,*/
};
use winrt::*;
use winrt::windows::system::diagnostics::*;

/// Enum describing the different status of a process.
#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -104,6 +106,8 @@ pub struct Process {
start_time: u64,
cpu_usage: f32,
pub(crate) updated: bool,
pub(crate) read_bytes: u64,
pub(crate) written_bytes: u64
}

unsafe fn get_process_name(process_handler: HANDLE, h_mod: *mut c_void) -> String {
Expand Down Expand Up @@ -192,6 +196,8 @@ impl Process {
old_user_cpu: 0,
start_time: get_start_time(process_handler),
updated: true,
read_bytes: 0,
written_bytes: 0
}
}
} else {
Expand All @@ -214,6 +220,8 @@ impl Process {
old_user_cpu: 0,
start_time: 0,
updated: true,
read_bytes: 0,
written_bytes: 0
}
}
}
Expand Down Expand Up @@ -259,6 +267,8 @@ impl ProcessExt for Process {
old_user_cpu: 0,
start_time: get_start_time(process_handler),
updated: true,
read_bytes: 0,
written_bytes: 0
}
}
} else {
Expand All @@ -281,6 +291,8 @@ impl ProcessExt for Process {
old_user_cpu: 0,
start_time: 0,
updated: true,
read_bytes: 0,
written_bytes: 0
}
}
}
Expand Down Expand Up @@ -344,6 +356,14 @@ impl ProcessExt for Process {
fn cpu_usage(&self) -> f32 {
self.cpu_usage
}

fn read_bytes(&self) -> u64{
self.read_bytes
}

fn written_bytes(&self) -> u64{
self.written_bytes
}
}

impl Drop for Process {
Expand Down Expand Up @@ -538,6 +558,40 @@ pub(crate) fn get_system_computation_time() -> ULARGE_INTEGER {
}
}

pub(crate) fn get_disk_usage(p: &mut Process){
let diag_info = ProcessDiagnosticInfo::try_get_for_process_id(p.pid as u32).ok();
match diag_info{
Some(diag_info) => match diag_info{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't of this match cascade, you can add a new macro:

macro_rules! safe_unwrap {
    ($x:expr) => {
        match $x {
             Some(x) => x,
             None => return,
        }
    }

And you can use it like this:

let diag_info = safe_unwrap!(diag_info.get_disk_usage().ok());

Some(diag_info) => match diag_info.get_disk_usage().ok(){
Some(disk_usage) => match disk_usage{
Some(disk_usage) => match disk_usage.get_report().ok(){
Some(report) => match report{
Some(report) => {
let read_bytes = report.get_bytes_read_count().ok();
let write_bytes = report.get_bytes_written_count().ok();
match read_bytes{
Some(read_bytes) => p.read_bytes = read_bytes as u64,
None => {}
};
match write_bytes{
Some(write_bytes) => p.written_bytes = write_bytes as u64,
None => {}
};
},
None => {}
},
None => {}
},
None => {}
},
None => {}
},
None => {}
},
None => {}
};
}

pub(crate) fn compute_cpu_usage(p: &mut Process, nb_processors: u64, now: ULARGE_INTEGER) {
unsafe {
let mut sys: ULARGE_INTEGER = ::std::mem::zeroed();
Expand Down Expand Up @@ -580,6 +634,7 @@ pub fn get_handle(p: &Process) -> HANDLE {

pub fn update_proc_info(p: &mut Process) {
update_memory(p);
get_disk_usage(p);
}

pub fn update_memory(p: &mut Process) {
Expand Down
4 changes: 3 additions & 1 deletion src/windows/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use SystemExt;

use windows::network::{self, NetworkData};
use windows::process::{
compute_cpu_usage, get_handle, get_system_computation_time, update_proc_info, Process,
compute_cpu_usage, get_handle, get_system_computation_time, update_proc_info, Process, get_disk_usage
};
use windows::processor::CounterValue;
use windows::tools::*;
Expand Down Expand Up @@ -331,6 +331,7 @@ impl SystemExt for System {
proc_.memory = (pi.WorkingSetSize as u64) >> 10u64;
proc_.virtual_memory = (pi.VirtualSize as u64) >> 10u64;
compute_cpu_usage(proc_, nb_processors, system_time);
get_disk_usage(proc_);
proc_.updated = true;
return None;
}
Expand All @@ -346,6 +347,7 @@ impl SystemExt for System {
(pi.VirtualSize as u64) >> 10u64,
name,
);
get_disk_usage(&mut p);
compute_cpu_usage(&mut p, nb_processors, system_time);
Some(p)
})
Expand Down
Loading