Ticket #3226 (closed Bugs: fixed)

Opened 5 years ago

Last modified 4 years ago

System statistics CPU utilization incorrectly shows 100% on multi-CPU 32-bit linux

Reported by: seattleneil Assigned to:
Priority: minor Milestone: 2.6
Component: System Dashboard Version: 2.5-branch
Keywords: CPU utilization Cc:
Confirmation: Need Feedback Distro:
Backend Engine: All Distro Ver:
Backend Ver: SVN Revision (if applicable):

Description

There is an error in modules/dashboard/phpsysinfo/class.Linux.inc.php. To calculate CPU utilization, this PHP script reads /proc/stat. However, on a 32-bit multi-CPU system with lots of idle CPU, the idle time field can exceed PHP's maximum integer size of 214748364732 which leads to an incorrect CPU utilization calculation. Here is an example /proc/stat output for my FreePBX system:

# cat /proc/stat
cpu  8961443 2639176 43824894 2243474696 379954 33798 41429 0 0
cpu0 539265 57837 356500 1123950062 121860 17211 24984 0 0
cpu1 8422178 2581339 43468393 1119524633 258094 16586 16444 0 0
...
...

Suggested fix is to replace the long integer arithmetic which is required to support /proc/stat with a call to vmstat, as shown below.

Replace:

    if ($bar) {
      $buf = rfts( '/proc/stat', 1 );
      if( $buf != "ERROR" ) {
        sscanf($buf, "%*s %Ld %Ld %Ld %Ld", $ab, $ac, $ad, $ae);
        // Find out the CPU load
        // user + sys = load
        // total = total
        $load = $ab + $ac + $ad;        // cpu.user + cpu.sys
        $total = $ab + $ac + $ad + $ae; // cpu.total

        // we need a second value, wait 1 second befor getting (< 1 second no good value will occour)
        sleep(1);
        $buf = rfts( '/proc/stat', 1 );
        sscanf($buf, "%*s %Ld %Ld %Ld %Ld", $ab, $ac, $ad, $ae);
        $load2 = $ab + $ac + $ad;
        $total2 = $ab + $ac + $ad + $ae;
        $results['cpupercent'] = ($total2 != $total)?((100*($load2 - $load)) / ($total2 - $total)):0;
      }
    }

with:

    if ($bar) {
        $results['cpupercent'] = 100 - exec("vmstat -n 1 2 | tail -1 | cut -c 73-74");
    }

Change History

09/21/08 18:31:41 changed by p_lindheimer

  • confirmation changed from Unreviewed to Need Feedback.

thank's for the suggestion. I'd like to hold off and see about just doing the calculation to get around the overflow vs. the cost of excec-ing vmstat, tail and cut. If anyone wants to toss out the code that won't overflow (toss it into floating point, ...) to fix the issue it would be great.

09/22/08 19:14:11 changed by p_lindheimer

  • milestone changed from 2.5 to 3.0.

03/11/09 05:10:31 changed by vietbach

I use asterisk/freepbx in vserver environment and has the same problem. I have tried the following changes and it seemed to fix the issue.

In modules/dashboard/phpsysinfo/class.Linux.inc.php, on line 122 and on line 132, replace:

sscanf($buf, "%*s %Ld %Ld %Ld %Ld", $ab, $ac, $ad, $ae);

with:

sscanf($buf, "%*s %f %f %f %f", $ab, $ac, $ad, $ae);

08/23/09 15:49:34 changed by p_lindheimer

  • status changed from new to closed.
  • resolution set to fixed.

(In [8093]) fixes #3226 read in variables as floats and not longs