[pve-devel] [PATCH pve-manager 2/3] Fix #5708: Add CPU raw counters

Daniel Kral d.kral at proxmox.com
Thu Oct 3 11:40:47 CEST 2024


On 9/30/24 08:17, Sascha Westermann wrote:
> If the data is also to be processed by external metric servers, I think
> the integration in `PVE::ProcFSTools::read_proc_stat()` makes sense. The
> term `cpustat` would no longer conflict in this case, as the content
> would be virtually the same. I would create a new patch series for this,
> but when looking at `read_proc_stat` a few questions arose for me:
> 
>> sub read_proc_stat {
>>      my $res = { user => 0, nice => 0, system => 0, idle => 0 , iowait => 0, irq => 0, softirq => 0, steal => 0, guest => 0, guest_nice => 0, sum => 0};
> 
> In order to remain consistent with the structure, the same fields per
> CPU would also need to be initialized with 0. However, this is only
> done when I find an entry of the form cpu<num>, which implicitly gives
> me values - so the initialization would not do anything. In this
> context, I wonder whether there are any situations where no values can
> be set? I would actually say that this is not the case and that the
> initialization can be removed.

Those fields seem to be initialized to zero here, as they are summed 
later for `$res->{total}` [0]. If the `/proc/stat` file couldn't be read 
or for some reason no `cpu` was captured, those would be initialized to 
`undef`. As far as I'm aware, an addition with a `undef` value would 
convert it to `0` in numerical contexts, so removing it shouldn't be a 
problem, but I could also be missing something here.

---

At least for me, I think you wouldn't need to initialize the `cpu<num>` 
fields with zero, but just make sure that any capture group that uses a 
prefixed `?` could become `undef` [1], so that case needs to be handled, 
just like `$res->{guest}` and `$res->{guest_nice}` is.

> 
> Side note: `sum` is not used, it probably means `total`, right?

As far as I'm aware, I couldn't find a usage for the `sum` property 
anywhere the `read_proc_stat` is used and could be deleted.

> 
>>     if (my $fh = IO::File->new ("/proc/stat", "r")) {
>> 	while (defined (my $line = <$fh>)) {
>> 	    if ($line =~ m|^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)(?:\s+(\d+)\s+(\d+))?|) {
>> 		$res->{user} = $1 - ($9 // 0);
>> 		$res->{nice} = $2 - ($10 // 0);
>> 		$res->{system} = $3;
> 
> `user` contains `guest` and `nice` contains `guest_nice`, so I
> understand that the values are subtracted. Wouldn't it be better to use
> the original values here? Especially when these are passed out as raw
> values via API, it would certainly be helpful if they correspond 1:1
> with the documentation from /proc/stat.

I can only point you in the direction of the original author's commit, 
it seems like it was inspired by other monitoring tools, but I haven't 
checked the latter two references in the commit message [2].

I get your point, but there might already be many (external) users, 
which depend on these values as they are calculated here (thinking of 
InfluxDB/Grafana dashboards, API users, ...). So if it doesn't hurt your 
use case too badly (and others that would use your new data points 
too!), I would adopt that for the `cpu<num>` datapoints as well.

> 
> The values are output as a string in the JSON output. Is there anything
> against casting them to int?

Good catch! It would be great if any numerical value is also treated 
like that. Be aware that Perl doesn't really have an explicit way to 
'cast' variables as types are handled by context. The builtin `int` 
function only makes sure that we only get the integer part of an 
expression [3]. So be aware, but if it doesn't break something (or 
change probable existing expectations for API users), go ahead.

> 
>>     my $diff = ($ctime - $last_proc_stat->{ctime}) * $clock_ticks * $cpucount;
>>
>>     if ($diff > 1000) { # don't update too often
> 
> I don't understand the condition. `$ctime - $last_proc_stat->{ctime}`
> corresponds to the elapsed time in seconds as a float, `clock_ticks`
> would normally be 100. So that would mean that on a system with one CPU
> core an update may only take place every 10 seconds, but with 8 cores
> every 1.25 seconds? Is that an error? Is it even necessary to suppress
> updates if $diff > 0?

Unfortunately, as some other things here, these changes predate our git 
repository and I couldn't tell you exactly why it is that way.

As far as I can say, as this is retrieved from the WebGUI's node status 
page around every second, this seems like it should "buffer" changes to 
these two data points, so that there are no spikes for the cpu% and 
wait%. But I don't quite get why it is multiplied with `$clock_ticks` 
and `$cpu_count` either.

If you really want to change this, I would do that in another patch 
(series) and mark it as an "RFC" (Read for Comments), so it gets a 
little more discussion if that change conflicts with anyone.

---

Hope these remarks clear up some problems. Looking forward to your patches!

Cheers,
Daniel

[0] https://git.proxmox.com/?p=pve-common.git;a=commitdiff;h=5224b31b
[1] https://perldoc.perl.org/perlvar#$%3Cdigits%3E-($1,-$2,-...)
[2] https://git.proxmox.com/?p=pve-common.git;a=commitdiff;h=c140206b
[3] https://perldoc.perl.org/functions/int




More information about the pve-devel mailing list