articles

New sysinfo release: time to extend APIs

Little reminder first: sysinfo is crate to get system information, such as processes, processors, disks, components and networks. Now let's go! :)

Time for a new sysinfo release! In this version, multiple things were added, such as the load average and processor information (frequency and vendor ID). The API has also been reworked to give you more control. Let's check it in details!

Load average

You can now get the load average. To do so:

Runuse sysinfo::{System, SystemExt};

let s = System::new();
let load_avg = s.get_load_average();
println!(
    "one minute: {}%, five minutes: {}%, fifteen minutes: {}%",
    load_avg.one,
    load_avg.five,
    load_avg.fifteen,
);

More processor information (and change in CPU usage returned number)

Before that, we could only get the name and the CPU usage. You can now get its vendor id, its brand and its frequency.

In addition to these new functionalities, I changed how the CPU usage was returned. Before that, it was a number before 0 and 1. Now, it's between 0 and 100. It makes much more sense since I always about it as a percentage. It's now more obvious.

Rework of the network API

The network API has been reworked: you now have access to interfaces directly instead of just a global information. Before, you could do:

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

let mut s = System::new();
s.refresh_network();
println!(
    "total income/outcome: {}/{} B",
    s.get_network().get_income(),
    s.get_network().get_outcome(),
);

Now, to get the same results, you'll have to iterate through the network interfaces:

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

let mut s = System::new_all();
s.refresh_networks();
let mut income = 0;
let mut outcome = 0;
for (interface_name, data) in s.get_networks() {
    income += data.get_income();
    outcome += data.get_outcome();
}
println!(
    "total income/outcome: {}/{} B",
    income,
    outcome,
);

But now, you can have more control over which interface you want to monitor.

A little note about this: on Windows, only the hardware network interfaces are included. I voluntarily dismissed the software interfaces because there was a lot of them and it's mostly inner (and useless?) Windows stuff.

Extension of network API

With this release comes new information for each network interface. Before, sysinfo only provided income and outcome bytes, now it also provides:

And as an example:

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

let mut s = System::new_all();
s.refresh_networks();
for (interface_name, data) in s.get_networks() {
    println!("== [{}] ==", interface_name);
    println!("income (new/total):          {}/{} B",
        data.get_income(), data.get_total_income());
    println!("outcome (new/total):         {}/{} B",
        data.get_outcome(), data.get_total_outcome());
    println!("packets income (new/total):  {}/{}",
        data.get_packets_income(), data.get_total_packets_income());
    println!("packets outcome (new/total): {}/{}",
        data.get_packets_outcome(), data.get_total_packets_outcome());
    println!("errors income (new/total):   {}/{}",
        data.get_errors_income(), data.get_total_errors_income());
    println!("errors outcome (new/total):  {}/{}",
        data.get_errors_outcome(), data.get_total_errors_outcome());
}

Mutables accesses

This new version also brings the possibility to get mutable access to some elements such as:

It allows you to refresh a specific one instead of all of them if you're only interested into not monitoring everything. Example:

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

let mut s = System::new_all();
for disk in s.get_disks_mut() {
    disk.refresh();
}

Renamings

A few methods have been renamed to ensure coherence. Here is the list:

Not visible changes

Before this release, windows CPU usage update was performed inside a separate thread with a specific timeout. I simplified this mechanism a lot and it is now refreshing when SystemExt::refresh_cpu is called to let you control the refresh rate.

I also strongly changed SystemExt::new behaviour: before, it was getting the list of processes and some platform-specific things, making it a bit different on each platform. It's now much more coherent since it only initializes the minimum needed platform-specific things and don't get the processes.

On macOS, I discarded processes that we couldn't get enough information on, because sysinfo didn't have enough rights. I now keep them listed so you can see them, but they are not much fulfilled. A good way to check it is to check if they have a parent process id (if not, then it's a process we can't get information about).

On Windows (again), the network information was updated using a "counter". Strangely, in some cases, it just failed. Since I completely rewrote it, this error cannot appear again.

What's next?

With this release, I was able to simplify the windows codebase, which made me quite happy. It's now much simpler and easier to work on.

I was also able to extend the API without sacrificing performance (and that is a huge deal!). I still have room to improve performance, but at this point, I think there isn't much performance gain left, but we'll see!

On the API, I'd like to add more I/O information, about disk usage for instance. Also, adding such information on each process would be quite useful. But I'm afraid that it might be very bad for performance. I'll need to investigate more. I think I'll add a new refresh enum specifically for SystemExt::refresh_processes, so users can decide what part of the processes they want to update.

Words of the end

Thanks to the people who helped me on this release (either by reporting bugs or fixing them)! It's always very appreciated to get constructive feedback and help.

See you around!

Posted on the 08/02/2020 at 16:00 by @GuillaumeGomez

Next article

cfg(doctest) is stable and you should use it

Previous article

New sysinfo release (OSX performance improvements)
Back to articles list
RSS feedRSS feed