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:
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:
SystemExt::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:
SystemExt::refresh_specifics( RefreshKind::new() .with_cpu() .with_memory(), );
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.
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_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)
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_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_refresh_processes are now running 7 times faster.
Now if we compare before and after:
bench_new: 12 times faster
bench_refresh_all: 97 times faster
bench_refresh_processes: 109 times faster
I have to admit: this is damn impressive and I'm quite proud of the result!
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!)
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!