From a1c3f18e0689a1a2a59f8d8d90242338f8e4394b Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Wed, 26 Oct 2016 11:13:33 +0200 Subject: [PATCH] CpuSet: Simply class to handle cpu sets --- src/Makefile | 1 + src/PVE/CpuSet.pm | 139 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 src/PVE/CpuSet.pm diff --git a/src/Makefile b/src/Makefile index a07e2e4..b72b21e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,6 +7,7 @@ MAN1DIR=${MANDIR}/man1/ PERLDIR=${PREFIX}/share/perl5 LIB_SOURCES= \ + CpuSet.pm \ Daemon.pm \ SectionConfig.pm \ Network.pm \ diff --git a/src/PVE/CpuSet.pm b/src/PVE/CpuSet.pm new file mode 100644 index 0000000..ef660b5 --- /dev/null +++ b/src/PVE/CpuSet.pm @@ -0,0 +1,139 @@ +package PVE::CpuSet; + +use strict; +use warnings; +use PVE::Tools; + +our $MAX_CPUID = 256; # should be enough for the next years + +sub new { + my ($this) = @_; + + my $class = ref($this) || $this; + + my $self = bless { members => {} }, $class; + + return $self; +} + +sub new_from_cgroup { + my ($this, $cgroup, $kind) = @_; + + $kind //= '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 = 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; + $count++; + }; + } else { + die "invalid range: $part\n"; + } + } + + die "got empty cpuset for cgroup '$cgroup'\n" + if !$count; + + return $cpuset; +} + +sub write_to_cgroup { + my ($self, $cgroup) = @_; + + my $filename = "/sys/fs/cgroup/cpuset/$cgroup/cpuset.cpus"; + + my $value = ''; + my @members = $self->members(); + foreach my $cpuid (@members) { + $value .= ',' if length($value); + $value .= $cpuid; + } + + die "unable to write empty cpu set\n" if !length($value); + + open(my $fh, '>', $filename) || die "failed to open '$filename' - $!\n"; + PVE::Tools::safe_print($filename, $fh, "$value\n"); + close($fh); +} + +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++; + } + + return $count; +} + +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++; + } + + return $count; +} + +sub has { + my ($self, $cpuid) = @_; + + return $self->{members}->{$cpuid}; +} + +# members: this list is always sorted! +sub members { + my ($self) = @_; + + return sort keys %{$self->{members}}; +} + +sub size { + my ($self) = @_; + + return scalar(keys %{$self->{members}}); +} + +sub is_equal { + my ($self, $set2) = @_; + + my $members1 = $self->{members}; + my $members2 = $set2->{members}; + + foreach my $id (keys %$members1) { + return 0 if !$members2->{$id}; + } + foreach my $id (keys %$members2) { + return 0 if !$members1->{$id}; + } + + return 1; +} + +1;