cpuset: remove max-cpu range check
[pve-common.git] / src / PVE / CpuSet.pm
1 package PVE::CpuSet;
2
3 use strict;
4 use warnings;
5 use PVE::Tools;
6 use PVE::ProcFSTools;
7
8 sub new {
9     my ($this) = @_;
10
11     my $class = ref($this) || $this;
12
13     my $self = bless { members => {} }, $class;
14
15     return $self;
16 }
17
18 sub new_from_cgroup {
19     my ($this, $cgroup, $kind) = @_;
20
21     $kind //= 'cpus';
22
23     my $filename = "/sys/fs/cgroup/cpuset/$cgroup/cpuset.$kind";
24     my $set_text = PVE::Tools::file_read_firstline($filename) // '';
25
26     my $cpuset = $this->new();
27     
28     my $members = $cpuset->{members};
29
30     my $count = 0;
31
32     foreach my $part (split(/,/, $set_text)) {
33         if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
34             my ($from, $to) = ($1, $2);
35             $to //= $1;
36             die "invalid range: $part ($to < $from)\n" if $to < $from;
37             for (my $i = $from; $i <= $to; $i++) {
38                 $members->{$i} = 1;
39                 $count++;
40             };
41         } else {
42             die "invalid range: $part\n";
43         }
44     }
45
46     die "got empty cpuset for cgroup '$cgroup'\n"
47         if !$count;
48
49     return $cpuset;
50 }
51
52 sub write_to_cgroup {
53     my ($self, $cgroup) = @_;
54
55     my $filename = "/sys/fs/cgroup/cpuset/$cgroup/cpuset.cpus";
56
57     my $value = '';
58     my @members = $self->members();
59     foreach my $cpuid (@members) {
60         $value .= ',' if length($value);
61         $value .= $cpuid;
62     }
63
64     die "unable to write empty cpu set\n" if !length($value);
65
66     open(my $fh, '>', $filename) || die "failed to open '$filename' - $!\n";
67     PVE::Tools::safe_print($filename, $fh, "$value\n");
68     close($fh) || die "failed to close '$filename' - $!\n";
69 }
70
71 sub insert {
72     my ($self, @members) = @_;
73
74     my $count = 0;
75     
76     foreach my $cpu (@members) {
77         next if $self->{members}->{$cpu};
78         $self->{members}->{$cpu} = 1;
79         $count++;
80     }
81
82     return $count;
83 }
84
85 sub delete {
86     my ($self, @members) = @_;
87
88     my $count = 0;
89     
90     foreach my $cpu (@members) {
91         next if !$self->{members}->{$cpu};
92         delete $self->{members}->{$cpu};
93         $count++;
94     }
95
96     return $count;
97 }
98
99 sub has {
100    my ($self, $cpuid) = @_;
101
102    return $self->{members}->{$cpuid};
103 }
104
105 # members: this list is always sorted!
106 sub members {
107     my ($self) = @_;
108
109     return sort keys %{$self->{members}};
110 }    
111
112 sub size {
113     my ($self) = @_;
114
115     return scalar(keys %{$self->{members}});
116 }
117
118 sub is_equal {
119     my ($self, $set2) = @_;
120
121     my $members1 = $self->{members};
122     my $members2 = $set2->{members};
123
124     foreach my $id (keys %$members1) {
125         return 0 if !$members2->{$id};
126     }
127     foreach my $id (keys %$members2) {
128         return 0 if !$members1->{$id};
129     }
130     
131     return 1;
132 }
133
134 sub short_string {
135     my ($self) = @_;
136
137     my @members = $self->members();
138
139     my $res = '';
140     my ($last, $next);
141     foreach my $cpu (@members) {
142         if (!defined($last)) {
143             $last = $next = $cpu;
144         } elsif (($next + 1) == $cpu) {
145             $next = $cpu;
146         } else {
147             $res .= ',' if length($res);
148             if ($last != $next) {
149                 $res .= "$last-$next";
150             } else {
151                 $res .= "$last";
152             }
153             $last = $next = $cpu;
154         }
155     }
156
157     if (defined($last)) {
158         $res .= ',' if length($res);
159         if ($last != $next) {
160             $res .= "$last-$next";
161         } else {
162             $res .= "$last";
163         }
164     }
165
166     return $res;
167 }
168
169 1;