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