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