[pve-devel] [PATCH container 05/20] cgroup: add get_io_stats and parse_nested_keyed_file

w.bumiller at proxmox.com w.bumiller at proxmox.com
Fri Apr 3 16:37:25 CEST 2020


From: Wolfgang Bumiller <w.bumiller at proxmox.com>

Signed-off-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
---
 src/PVE/LXC/CGroup.pm | 71 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/src/PVE/LXC/CGroup.pm b/src/PVE/LXC/CGroup.pm
index 7561fb2..207c0c1 100644
--- a/src/PVE/LXC/CGroup.pm
+++ b/src/PVE/LXC/CGroup.pm
@@ -12,6 +12,11 @@ package PVE::LXC::CGroup;
 use strict;
 use warnings;
 
+use PVE::Tools qw(
+    file_get_contents
+    file_read_firstline
+);
+
 use PVE::LXC::Command;
 
 # We don't want to do a command socket round trip for every cgroup read/write,
@@ -125,4 +130,70 @@ sub get_path {
     return "/sys/fs/cgroup/$controller/$path";
 }
 
+# Parse a 'Nested keyed' file:
+#
+# See kernel documentation `admin-guide/cgroup-v2.rst` 4.1.
+my sub parse_nested_keyed_file($) {
+    my ($data) = @_;
+    my $res = {};
+    foreach my $line (split(/\n/, $data)) {
+	my ($key, @values) = split(/\s+/, $line);
+
+	my $d = ($res->{$key} = {});
+
+	foreach my $value (@values) {
+	    if (my ($key, $value) = ($value =~ /^([^=]+)=(.*)$/)) {
+		$d->{$key} = $value;
+	    } else {
+		warn "bad key=value pair in nested keyed file\n";
+	    }
+	}
+    }
+}
+
+# Get I/O stats for a container.
+sub get_io_stats {
+    my ($self) = @_;
+
+    my $res = {
+	diskread => 0,
+	diskwrite => 0,
+    };
+
+    if (cgroup_mode() == 2) {
+	if (defined(my $path = $self->get_path('io'))) {
+	    # cgroupv2 environment, io controller enabled
+	    my $io_stat = file_get_contents("$path/io.stat");
+
+	    my $data = parse_nested_keyed_file($io_stat);
+	    foreach my $dev (keys %$data) {
+		my $dev = $data->{$dev};
+		if (my $b = $dev->{rbytes}) {
+		    $res->{diskread} += $b;
+		}
+		if (my $b = $dev->{wbytes}) {
+		    $res->{diskread} += $b;
+		}
+	    }
+	} else {
+	    # io controller not enabled or container not running
+	    return undef;
+	}
+    } elsif (defined(my $path = $self->get_path('blkio'))) {
+	# cgroupv1 environment:
+	my $io = file_get_contents("$path/blkio.throttle.io_service_bytes_recursive");
+	foreach my $line (split(/\n/, $io)) {
+	    if (my ($type, $bytes) = ($line =~ /^\d+:\d+\s+(Read|Write)\s+(\d+)$/)) {
+		$res->{diskread} += $bytes if $type eq 'Read';
+		$res->{diskwrite} += $bytes if $type eq 'Write';
+	    }
+	}
+    } else {
+	# container not running
+	return undef;
+    }
+
+    return $res;
+}
+
 1;
-- 
2.20.1





More information about the pve-devel mailing list