articles

New sysinfo release

Hi everyone! Today, sysinfo has received a new update with nice improvements. As a reminder, sysinfo is crate used to get systems' information (Linux, Windows, OSX and raspberry pi are supported). Let's take a look:

More specific refresh methods

Some people complained that they didn't have enough control over what they were refreshing system (aka CPU, memory and components' temperature) information. And they were right! Therefore, it's now possible to refresh each one of them separately:

RunSystemExt::refresh_cpu();
SystemExt::refresh_memory();
SystemExt::refresh_temperatures();

The RefreshKind type has been updated in order to reflect. So if you want to refresh CPU and memory but not temperatures, you can do:

RunSystemExt::refresh_specifics(
    RefreshKind::new()
                .with_cpu()
                .with_memory(),
);

Improvements on Raspberry

Some components couldn't get parsed on the new raspberry pi because some items changed name. This is now fixed.

Another issue was that some disks couldn't be seen, this is fixed as well.

Windows (great) speed improvements

The core of this new release is here. Let's take a look at some benchmarks:

running 8 tests
test bench_new                ... bench: 597,681,058 ns/iter (+/- 520,389,224)
test bench_refresh_all        ... bench: 192,556,222 ns/iter (+/- 107,715,769)
test bench_refresh_disk_lists ... bench:     345,887 ns/iter (+/- 29,159)
test bench_refresh_disks      ... bench:     112,346 ns/iter (+/- 15,075)
test bench_refresh_network    ... bench:         203 ns/iter (+/- 14)
test bench_refresh_process    ... bench:       2,706 ns/iter (+/- 176)
test bench_refresh_processes  ... bench: 191,591,762 ns/iter (+/- 5,917,054)
test bench_refresh_system     ... bench:       2,489 ns/iter (+/- 456)

From this, we see that bench_new, bench_refresh_all and bench_refresh_processes are very slow and this is where I focused my work.

For the story, it all started when tkozybski opened an issue about those functions being slow. But then they also suggested me to swith from K32EnumProcesses function to NtQuerySystemInformation. So I made the switch and ran the benchmarks again:

test bench_new                ... bench:  77,663,289 ns/iter (+/- 238,399,443)
test bench_refresh_all        ... bench:  33,411,871 ns/iter (+/- 43,782,658)
test bench_refresh_processes  ... bench:  32,410,543 ns/iter (+/- 3,301,203)

O.O

Just by a simple switch without any optimization, my code is already 7.7 times faster for bench_new and 5.8 times faster for the two others. This is insane! But I was still far from the best optimization I could have.

Next step: adding parallel iterations to update my process list:

test bench_new                ... bench:  73,458,698 ns/iter (+/- 213,167,964)
test bench_refresh_all        ... bench:   7,969,382 ns/iter (+/- 1,070,554)
test bench_refresh_processes  ... bench:   7,770,861 ns/iter (+/- 522,609)

Not much changes for bench_new but bench_refresh_all and bench_refresh_processes are running almost 5 times faster! This is starting to look really good at this point!

Now, at this point, I was just re-creating my process list every time. So let's see when I update it instead:

test bench_new                ... bench:  48,019,473 ns/iter (+/- 210,328,340)
test bench_refresh_all        ... bench:   1,984,283 ns/iter (+/- 258,629)
test bench_refresh_processes  ... bench:   1,755,207 ns/iter (+/- 150,654)

Slight improvement for bench_new but bench_refresh_all and bench_refresh_processes are now running 7 times faster.

Now if we compare before and after:

I have to admit: this is damn impressive and I'm quite proud of the result!

Little traps

Just as a side note, I fell into a small but annoying trap: when you use the NtQuerySystemInformation function with the SystemProcessInformation, it returns a list of SYSTEM_PROCESS_INFORMATION (followed by X other types, because why not!). Inside this type, there is a field ImageName which contains the name (no way!), its length and its maximum length. So at this point, I guess you just think like me: "this means that the string has a length of Length!". Well, no. You fell into the trap as well.

I *think* that Length is actually the allocated size for the string and that MaximumLength is the maximum size it could reach. It doesn't make much sense from my point of view and this is annoying to double check what the actual string's length is but I guess there is a hidden reason behind it. (If someone has more information about it, I'd be curious to know!)

Conclusion

Anyway, this release is mostly about Windows. It's been a while I didn't update its implementation and I think it'll be very nice for all Windows users out there to finally have a very efficient crate to retrieve system information.

In the future, I'd like to be able to get components' temperature but for the moment, I didn't find how yet (C++ APIs exist but I don't want to rely on non-C) but I definitely will with time and perseverance!

Posted on the 07/12/2019 at 02:30 by @GuillaumeGomez

Next article

New sysinfo release (OSX performance improvements)

Previous article

Rust 2020: what about feedbacks?
Back to articles list
RSS feedRSS feed