Thanks!
X
Paypal
Github sponshorship
Patreon

articles

New sysinfo release: processes disk usage

The new sysinfo version is here! As a reminder, sysinfo is a crate which provides system information. Let's check what's new!

Disk usage

As you may have guess from the title, this release brings the processes' disk usage. Example:

Runuse sysinfo::{ProcessExt, System, SystemExt};

let mut s = System::new();
s.refresh_processes();
for (pid, process) in s.get_processes() {
    let disk_usage = process.disk_usage();
    println!("[{}][{}]: {:?}", pid, process.name(), disk_usage);
}

ProcessExt::disk_usage returns a DiskUsage type which contains the following fields:

Little explanations here: both total_ fields are the total amount of bytes which has been read/written since the start of the process whereas the non-total_ fields are the difference since the last refresh.

As noted in the documentation though, on Windows, DiskUsage returns all the I/O, not just the disks. I'll provide explanations below.

Debugging

Another improvement for this release is the reworking of the debug feature. It was there but not really useful. I decided to fix this situation and replace the few:

Run#[cfg(feature = "debug")]
{
    println!("...");
}

I had around. The code is now a lot cleaner and the macro I'm using is pretty simple in itself. For the interested ones, you can take a look at it here.

This is pretty much all for this release. Time for some more technical information!

Performance

Surprisingly enough, the performances haven't change much... At first, I wanted to allow people to not choose when they wanted to refresh disk usage or not, implemented it, then ran the benchmarks. The difference was so small that I decided it wasn't worth it and reverted the changes.

Where I was the most surprised was about Linux: it forces me to open another file for ever process, which costs a lot. But maybe the access to /proc/[PID]/io isn't that expensive? I couldn't find specific information so I just let it be.

Implementation

This feature has spent a lot of time in an open pull request made by @bvaisvil. The big issue was the performance regression on Windows. Let's start there!

Windows

The initial implementation was using the winrt crate. This implementation was so slow that I could observe performance drop that would go up to 70 times (!!!) slower. It's unfortunately not because of the crate (otherwise it could be improved) but because of the WinRT library itself.

I then realized during tests that the functions I was relying on were not always available on the targets. Luckily, it's a runtime check. Unfortunately, the winrt crate doesn't provide yet a way to check that a function can be used before actually using it, resulting in a panic. After a few tries, I just decided to not go forward with it and to use the GetProcessIoCounters function instead. It has one big downside though: it returns ALL I/O, not just disk usage. So for now, Windows has an incomplete version for processes' disk usage. One thing I tell myself to feel better is that at least, the performance drop is now gone since GetProcessIoCounters is really fast.

I will try to add the network usage in a next version and will subtract this value from what GetProcessIoCounters returns to be able to get a value closer to reality for disk usage. It won't be the exact one yet since it also includes "drivers I/O" (couldn't find what that is), but closer to reality!

Linux

Not much to say here: I read the /proc/[PID]/io file, get both read_bytes and write_bytes fields and that's it.

MacOS

In here, I used the proc_pid_rusage function. Then I take the values from the ri_diskio_bytesread and ri_diskio_byteswritten fields. Nothing fancy here either.

process-viewer

As usual, I will update the process-viewer crate to add this extra information. More to come soon!

Conclusion

That's it for this small but super painful release! Thanks again to @bvaisvil for starting the work on this feature!

Posted on the 09/04/2020 at 12:00 by @GuillaumeGomez
Back to articles list