]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/ProcFSTools.pm
ProcFSTools: read_proc_stat: add more cpu stats from /proc/stat
[pve-common.git] / src / PVE / ProcFSTools.pm
index e413ccf1c50b1f90575f9cb9a764c45fcc73a962..a75274a9faf03130c41376ec329a07098c4a58c6 100644 (file)
@@ -5,6 +5,7 @@ use warnings;
 use POSIX;
 use Time::HiRes qw (gettimeofday);
 use IO::File;
+use List::Util qw(sum);
 use PVE::Tools;
 use Cwd qw();
 
@@ -35,6 +36,7 @@ sub read_cpuinfo {
     my $fh = IO::File->new ($fn, "r");
     return $res if !$fh;
 
+    my $cpuid = 0;
     my $idhash = {};
     my $count = 0;
     while (defined(my $line = <$fh>)) {
@@ -47,7 +49,10 @@ sub read_cpuinfo {
        } elsif ($line =~ m/^flags\s*:\s*(.*)$/) {
            $res->{flags} = $1 if !length $res->{flags};
        } elsif ($line =~ m/^physical id\s*:\s*(\d+)\s*$/i) {
-           $idhash->{$1} = 1;
+           $cpuid = $1;
+           $idhash->{$1} = 1 if not defined($idhash->{$1});
+       } elsif ($line =~ m/^cpu cores\s*:\s*(\d+)\s*$/i) {
+           $idhash->{$cpuid} = $1 if defined($idhash->{$cpuid});
        }
     }
 
@@ -56,6 +61,8 @@ sub read_cpuinfo {
 
     $res->{sockets} = scalar(keys %$idhash) || 1;
 
+    $res->{cores} = sum(values %$idhash) || 1;
+
     $res->{cpus} = $count;
 
     $fh->close;
@@ -125,6 +132,33 @@ sub read_loadavg {
     return wantarray ? (0, 0, 0) : 0;
 }
 
+sub parse_pressure {
+    my ($path) = @_;
+
+    my $res = {};
+    my $v = qr/\d+\.\d+/;
+    my $fh = IO::File->new($path, "r") or return undef;
+    while (defined (my $line = <$fh>)) {
+       if ($line =~ /^(some|full)\s+avg10\=($v)\s+avg60\=($v)\s+avg300\=($v)\s+total\=(\d+)/) {
+           $res->{$1}->{avg10} = $2;
+           $res->{$1}->{avg60} = $3;
+           $res->{$1}->{avg300} = $4;
+           $res->{$1}->{total} = $4;
+       }
+    }
+    $fh->close;
+    return $res;
+}
+
+sub read_pressure {
+    my $res = {};
+    foreach my $type (qw(cpu memory io)) {
+       my $stats = parse_pressure("/proc/pressure/$type");
+       $res->{$type} = $stats if $stats;
+    }
+    return $res;
+}
+
 my $last_proc_stat;
 
 sub read_proc_stat {
@@ -134,13 +168,18 @@ sub read_proc_stat {
 
     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|) {
+           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;
                $res->{nice} = $2;
                $res->{system} = $3;
                $res->{idle} = $4;
                $res->{used} = $1+$2+$3;
                $res->{iowait} = $5;
+               $res->{irq} = $6;
+               $res->{softirq} = $7;
+               $res->{steal} = $8;
+               $res->{guest} = $9;
+               $res->{guest_nice} = $10;
            } elsif ($line =~ m|^cpu\d+\s|) {
                $cpucount++;
            }
@@ -152,6 +191,16 @@ sub read_proc_stat {
 
     my $ctime = gettimeofday; # floating point time in seconds
 
+    # the sum of all (non-guest) fields
+    $res->{total} = $res->{user}
+       + $res->{nice}
+       + $res->{system}
+       + $res->{iowait}
+       + $res->{irq}
+       + $res->{softirq}
+       + $res->{steal}
+       + $res->{idle};
+
     $res->{ctime} = $ctime;
     $res->{cpu} = 0;
     $res->{wait} = 0;
@@ -344,6 +393,7 @@ sub decode_mount {
 
 sub parse_mounts {
     my ($mounts) = @_;
+
     my $mntent = [];
     while ($mounts =~ /^\s*([^#].*)$/gm) {
        # lines from the file are encoded so we can just split at spaces
@@ -352,11 +402,14 @@ sub parse_mounts {
        # in glibc's parser frequency and pass seem to be optional
        $freq = $1 if $opts =~ s/\s+(\d+)$//;
        $passno = $1 if $opts =~ s/\s+(\d+)$//;
-       push @$mntent, [decode_mount($what),
-                       decode_mount($dir),
-                       decode_mount($fstype),
-                       decode_mount($opts),
-                       $freq, $passno];
+       push @$mntent, [
+           decode_mount($what),
+           decode_mount($dir),
+           decode_mount($fstype),
+           decode_mount($opts),
+           $freq,
+           $passno,
+       ];
     }
     return $mntent;
 }