]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/CpuSet.pm
cpuset: replace 'kind' with an 'effective' boolean
[pve-common.git] / src / PVE / CpuSet.pm
index ef660b5c52ca04d2fe6fc2b5de6d905790ba4232..fe36536badc8bdb50fdcf97a4e67ab0892da2a4d 100644 (file)
@@ -3,39 +3,44 @@ package PVE::CpuSet;
 use strict;
 use warnings;
 use PVE::Tools;
-
-our $MAX_CPUID = 256; # should be enough for the next years
+use PVE::ProcFSTools;
 
 sub new {
-    my ($this) = @_;
-
-    my $class = ref($this) || $this;
+    my ($class, $members) = @_;
 
-    my $self = bless { members => {} }, $class;
+    $members //= {};
+    my $self = bless { members => $members }, $class;
 
     return $self;
 }
 
+# Create a new set with the contents of a cgroup-v1 subdirectory
 sub new_from_cgroup {
-    my ($this, $cgroup, $kind) = @_;
+    my ($class, $cgroup, $effective) = @_;
 
-    $kind //= 'cpus';
+    my $kind = $effective ? 'effective_cpus' : 'cpus';
 
     my $filename = "/sys/fs/cgroup/cpuset/$cgroup/cpuset.$kind";
     my $set_text = PVE::Tools::file_read_firstline($filename) // '';
 
-    my $cpuset = $this->new();
-    
-    my $members = $cpuset->{members};
+    my ($count, $members) = parse_cpuset($set_text);
+
+    die "got empty cpuset for cgroup '$cgroup'\n"
+       if !$count;
+
+    return $class->new($members);
+}
+
+sub parse_cpuset {
+    my ($set_text) = @_;
 
+    my $members = {};
     my $count = 0;
 
     foreach my $part (split(/,/, $set_text)) {
        if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
            my ($from, $to) = ($1, $2);
            $to //= $1;
-           die "cpu id '$from' is out of range\n" if $from >= $MAX_CPUID;
-           die "cpu id '$to' is out of range\n" if $to >= $MAX_CPUID;
            die "invalid range: $part ($to < $from)\n" if $to < $from;
            for (my $i = $from; $i <= $to; $i++) {
                $members->{$i} = 1;
@@ -46,10 +51,7 @@ sub new_from_cgroup {
        }
     }
 
-    die "got empty cpuset for cgroup '$cgroup'\n"
-       if !$count;
-
-    return $cpuset;
+    return ($count, $members);
 }
 
 sub write_to_cgroup {
@@ -68,16 +70,15 @@ sub write_to_cgroup {
 
     open(my $fh, '>', $filename) || die "failed to open '$filename' - $!\n";
     PVE::Tools::safe_print($filename, $fh, "$value\n");
-    close($fh);
+    close($fh) || die "failed to close '$filename' - $!\n";
 }
 
 sub insert {
     my ($self, @members) = @_;
 
     my $count = 0;
-    
+
     foreach my $cpu (@members) {
-       die "cpu id '$cpu' is out of range\n" if $cpu >= $MAX_CPUID;
        next if $self->{members}->{$cpu};
        $self->{members}->{$cpu} = 1;
        $count++;
@@ -90,9 +91,8 @@ sub delete {
     my ($self, @members) = @_;
 
     my $count = 0;
-    
+
     foreach my $cpu (@members) {
-       die "cpu id '$cpu' is out of range\n" if $cpu >= $MAX_CPUID;
        next if !$self->{members}->{$cpu};
        delete $self->{members}->{$cpu};
        $count++;
@@ -111,8 +111,8 @@ sub has {
 sub members {
     my ($self) = @_;
 
-    return sort keys %{$self->{members}};
-}    
+    return sort { $a <=> $b } keys %{$self->{members}};
+}
 
 sub size {
     my ($self) = @_;
@@ -132,8 +132,43 @@ sub is_equal {
     foreach my $id (keys %$members2) {
        return 0 if !$members1->{$id};
     }
-    
+
     return 1;
 }
 
+sub short_string {
+    my ($self) = @_;
+
+    my @members = $self->members();
+
+    my $res = '';
+    my ($last, $next);
+    foreach my $cpu (@members) {
+       if (!defined($last)) {
+           $last = $next = $cpu;
+       } elsif (($next + 1) == $cpu) {
+           $next = $cpu;
+       } else {
+           $res .= ',' if length($res);
+           if ($last != $next) {
+               $res .= "$last-$next";
+           } else {
+               $res .= "$last";
+           }
+           $last = $next = $cpu;
+       }
+    }
+
+    if (defined($last)) {
+       $res .= ',' if length($res);
+       if ($last != $next) {
+           $res .= "$last-$next";
+       } else {
+           $res .= "$last";
+       }
+    }
+
+    return $res;
+}
+
 1;