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 support for diskstat info #71

Merged
merged 1 commit into from
Apr 17, 2020
Merged
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
38 changes: 38 additions & 0 deletions examples/diskinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use procfs::{diskstats, process::Process, DiskStat};
use std::collections::HashMap;
use std::iter::FromIterator;

fn main() {
let me = Process::myself().unwrap();
let mounts = me.mountinfo().unwrap();

// Get a list of all disks that we have IO stat info on
let disk_stats: HashMap<(i32, i32), DiskStat> = HashMap::from_iter(
diskstats()
.unwrap()
.into_iter()
.map(|i| ((i.major, i.minor), i)),
);

for mount in mounts {
// parse the majmin string (something like "0:3") into an (i32, i32) tuple
let (maj, min): (i32, i32) = {
let mut s = mount.majmin.split(':');
(
s.next().unwrap().parse().unwrap(),
s.next().unwrap().parse().unwrap(),
)
};

if let Some(stat) = disk_stats.get(&(maj, min)) {
println!("{} mounted on {}:", stat.name, mount.mount_point.display());
println!(" total reads: {} ({} ms)", stat.reads, stat.time_reading);
println!(" total writes: {} ({} ms)", stat.writes, stat.time_writing);
println!(
" total flushes: {} ({} ms)",
stat.flushes.unwrap_or(0),
stat.time_flushing.unwrap_or(0)
);
}
}
}
156 changes: 156 additions & 0 deletions src/diskstats.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
use crate::{FileWrapper, ProcResult};
use std::io::{BufRead, BufReader};

/// Disk IO stat information
///
/// To fully understand these fields, please see the [iostats.txt](https://www.kernel.org/doc/Documentation/iostats.txt)
/// kernel documentation
// Doc reference: https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats
// Doc reference: https://www.kernel.org/doc/Documentation/iostats.txt
#[derive(Debug)]
pub struct DiskStat {
/// The device major number
pub major: i32,

/// The device minor number
pub minor: i32,

/// Device name
pub name: String,

/// Reads completed successfully
///
/// This is the total number rof reads comopleted successfully
pub reads: usize,

/// Reads merged
///
/// The number of adjacent reads that have been merged for efficiency.
pub merged: usize,

/// Sectors read successfully
///
/// This is the total number of sectors read successfully.
pub sectors_read: usize,

/// Time spent reading (ms)
pub time_reading: usize,

/// writes completed
pub writes: usize,

/// writes merged
///
/// The number of adjacent writes that have been merged for efficiency.
pub writes_merged: usize,

/// Sectors written successfully
pub sectors_written: usize,

/// Time spent writing (ms)
pub time_writing: usize,

/// I/Os currently in progress
pub in_progress: usize,

/// Time spent doing I/Os (ms)
pub time_in_progress: usize,

/// Weighted time spent doing I/Os (ms)
pub weighted_time_in_progress: usize,

/// Discards completed successfully
///
/// (since kernel 4.18)
pub discards: Option<usize>,

/// Discards merged
pub discards_merged: Option<usize>,

/// Sectors discarded
pub sectors_discarded: Option<usize>,

/// Time spent discarding
pub time_discarding: Option<usize>,

/// Flush requests completed successfully
///
/// (since kernel 5.5)
pub flushes: Option<usize>,

/// Time spent flushing
pub time_flushing: Option<usize>,
}

/// Get disk IO stat info from /proc/diskstats
pub fn diskstats() -> ProcResult<Vec<DiskStat>> {
let file = FileWrapper::open("/proc/diskstats")?;
let reader = BufReader::new(file);
let mut v = Vec::new();

for line in reader.lines() {
let line = line?;
v.push(DiskStat::from_line(&line)?);
}
Ok(v)
}

impl DiskStat {
pub fn from_line(line: &str) -> ProcResult<DiskStat> {
let mut s = line.trim().split_whitespace();

let major = from_str!(i32, expect!(s.next()));
let minor = from_str!(i32, expect!(s.next()));
let name = expect!(s.next()).to_string();
let reads = from_str!(usize, expect!(s.next()));
let merged = from_str!(usize, expect!(s.next()));
let sectors_read = from_str!(usize, expect!(s.next()));
let time_reading = from_str!(usize, expect!(s.next()));
let writes = from_str!(usize, expect!(s.next()));
let writes_merged = from_str!(usize, expect!(s.next()));
let sectors_written = from_str!(usize, expect!(s.next()));
let time_writing = from_str!(usize, expect!(s.next()));
let in_progress = from_str!(usize, expect!(s.next()));
let time_in_progress = from_str!(usize, expect!(s.next()));
let weighted_time_in_progress = from_str!(usize, expect!(s.next()));
let discards = s.next().and_then(|s| usize::from_str_radix(s, 10).ok());
let discards_merged = s.next().and_then(|s| usize::from_str_radix(s, 10).ok());
let sectors_discarded = s.next().and_then(|s| usize::from_str_radix(s, 10).ok());
let time_discarding = s.next().and_then(|s| usize::from_str_radix(s, 10).ok());
let flushes = s.next().and_then(|s| usize::from_str_radix(s, 10).ok());
let time_flushing = s.next().and_then(|s| usize::from_str_radix(s, 10).ok());

Ok(DiskStat {
major,
minor,
name,
reads,
merged,
sectors_read,
time_reading,
writes,
writes_merged,
sectors_written,
time_writing,
in_progress,
time_in_progress,
weighted_time_in_progress,
discards,
discards_merged,
sectors_discarded,
time_discarding,
flushes,
time_flushing,
})
}
}

#[cfg(test)]
mod tests {
#[test]
fn diskstat() {
for disk in super::diskstats().unwrap() {
println!("{:?}", disk);
}
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,9 @@ pub use crate::sys::kernel::Version as KernelVersion;
mod pressure;
pub use crate::pressure::*;

mod diskstats;
pub use diskstats::*;

lazy_static! {
/// The number of clock ticks per second.
///
Expand Down
2 changes: 1 addition & 1 deletion support.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ This is an approximate list of all the files under the `/proc` mount, and an ind
* [ ] `/proc/crypto`
* [ ] `/proc/cpuinfo`
* [ ] `/proc/devices`
* [ ] `/proc/diskstats`
* [x] `/proc/diskstats`
* [ ] `/proc/dma`
* [ ] `/proc/driver`
* [ ] `/proc/execdomains`
Expand Down