Skip to content

Commit 442de19

Browse files
committed
Merge branch 'devel-cpuset-src' of /usr/local/google/home/icoolidge/src/k8s-cpuset into devel-cpuset
Followed instructions from https://gbayer.com/development/moving-files-from-one-git-repository-to-another-preserving-history/
2 parents a5ecb01 + da7083c commit 442de19

File tree

3 files changed

+619
-0
lines changed

3 files changed

+619
-0
lines changed

cpuset/OWNERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# See the OWNERS docs at https://go.k8s.io/owners
2+
3+
approvers:
4+
- derekwaynecarr
5+
emeritus_approvers:
6+
- ConnorDoyle
7+
- vishh

cpuset/cpuset.go

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
/*
2+
Copyright 2017 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package cpuset represents a collection of CPUs in a 'set' data structure.
18+
//
19+
// It can be used to represent core IDs, hyper thread siblings, CPU nodes, or processor IDs.
20+
//
21+
// The only special thing about this package is that
22+
// methods are provided to convert back and forth from Linux 'list' syntax.
23+
// See http://man7.org/linux/man-pages/man7/cpuset.7.html#FORMATS for details.
24+
//
25+
// Future work can migrate this to use a 'set' library, and relax the dubious 'immutable' property.
26+
package cpuset
27+
28+
import (
29+
"bytes"
30+
"fmt"
31+
"reflect"
32+
"sort"
33+
"strconv"
34+
"strings"
35+
)
36+
37+
// CPUSet is a thread-safe, immutable set-like data structure for CPU IDs.
38+
type CPUSet struct {
39+
elems map[int]struct{}
40+
}
41+
42+
// New returns a new CPUSet containing the supplied elements.
43+
func New(cpus ...int) CPUSet {
44+
s := CPUSet{
45+
elems: map[int]struct{}{},
46+
}
47+
for _, c := range cpus {
48+
s.add(c)
49+
}
50+
return s
51+
}
52+
53+
// add adds the supplied elements to the CPUSet.
54+
// It is intended for internal use only, since it mutates the CPUSet.
55+
func (s CPUSet) add(elems ...int) {
56+
for _, elem := range elems {
57+
s.elems[elem] = struct{}{}
58+
}
59+
}
60+
61+
// Size returns the number of elements in this set.
62+
func (s CPUSet) Size() int {
63+
return len(s.elems)
64+
}
65+
66+
// IsEmpty returns true if there are zero elements in this set.
67+
func (s CPUSet) IsEmpty() bool {
68+
return s.Size() == 0
69+
}
70+
71+
// Contains returns true if the supplied element is present in this set.
72+
func (s CPUSet) Contains(cpu int) bool {
73+
_, found := s.elems[cpu]
74+
return found
75+
}
76+
77+
// Equals returns true if the supplied set contains exactly the same elements
78+
// as this set (s IsSubsetOf s2 and s2 IsSubsetOf s).
79+
func (s CPUSet) Equals(s2 CPUSet) bool {
80+
return reflect.DeepEqual(s.elems, s2.elems)
81+
}
82+
83+
// filter returns a new CPU set that contains all of the elements from this
84+
// set that match the supplied predicate, without mutating the source set.
85+
func (s CPUSet) filter(predicate func(int) bool) CPUSet {
86+
r := New()
87+
for cpu := range s.elems {
88+
if predicate(cpu) {
89+
r.add(cpu)
90+
}
91+
}
92+
return r
93+
}
94+
95+
// IsSubsetOf returns true if the supplied set contains all the elements
96+
func (s CPUSet) IsSubsetOf(s2 CPUSet) bool {
97+
result := true
98+
for cpu := range s.elems {
99+
if !s2.Contains(cpu) {
100+
result = false
101+
break
102+
}
103+
}
104+
return result
105+
}
106+
107+
// Union returns a new CPU set that contains all of the elements from this
108+
// set and all of the elements from the supplied sets, without mutating
109+
// either source set.
110+
func (s CPUSet) Union(s2 ...CPUSet) CPUSet {
111+
r := New()
112+
for cpu := range s.elems {
113+
r.add(cpu)
114+
}
115+
for _, cs := range s2 {
116+
for cpu := range cs.elems {
117+
r.add(cpu)
118+
}
119+
}
120+
return r
121+
}
122+
123+
// Intersection returns a new CPU set that contains all of the elements
124+
// that are present in both this set and the supplied set, without mutating
125+
// either source set.
126+
func (s CPUSet) Intersection(s2 CPUSet) CPUSet {
127+
return s.filter(func(cpu int) bool { return s2.Contains(cpu) })
128+
}
129+
130+
// Difference returns a new CPU set that contains all of the elements that
131+
// are present in this set and not the supplied set, without mutating either
132+
// source set.
133+
func (s CPUSet) Difference(s2 CPUSet) CPUSet {
134+
return s.filter(func(cpu int) bool { return !s2.Contains(cpu) })
135+
}
136+
137+
// List returns a slice of integers that contains all elements from
138+
// this set. The list is sorted.
139+
func (s CPUSet) List() []int {
140+
result := s.UnsortedList()
141+
sort.Ints(result)
142+
return result
143+
}
144+
145+
// UnsortedList returns a slice of integers that contains all elements from
146+
// this set.
147+
func (s CPUSet) UnsortedList() []int {
148+
result := make([]int, 0, len(s.elems))
149+
for cpu := range s.elems {
150+
result = append(result, cpu)
151+
}
152+
return result
153+
}
154+
155+
// String returns a new string representation of the elements in this CPU set
156+
// in canonical linux CPU list format.
157+
//
158+
// See: http://man7.org/linux/man-pages/man7/cpuset.7.html#FORMATS
159+
func (s CPUSet) String() string {
160+
if s.IsEmpty() {
161+
return ""
162+
}
163+
164+
elems := s.List()
165+
166+
type rng struct {
167+
start int
168+
end int
169+
}
170+
171+
ranges := []rng{{elems[0], elems[0]}}
172+
173+
for i := 1; i < len(elems); i++ {
174+
lastRange := &ranges[len(ranges)-1]
175+
// if this element is adjacent to the high end of the last range
176+
if elems[i] == lastRange.end+1 {
177+
// then extend the last range to include this element
178+
lastRange.end = elems[i]
179+
continue
180+
}
181+
// otherwise, start a new range beginning with this element
182+
ranges = append(ranges, rng{elems[i], elems[i]})
183+
}
184+
185+
// construct string from ranges
186+
var result bytes.Buffer
187+
for _, r := range ranges {
188+
if r.start == r.end {
189+
result.WriteString(strconv.Itoa(r.start))
190+
} else {
191+
result.WriteString(fmt.Sprintf("%d-%d", r.start, r.end))
192+
}
193+
result.WriteString(",")
194+
}
195+
return strings.TrimRight(result.String(), ",")
196+
}
197+
198+
// Parse CPUSet constructs a new CPU set from a Linux CPU list formatted string.
199+
//
200+
// See: http://man7.org/linux/man-pages/man7/cpuset.7.html#FORMATS
201+
func Parse(s string) (CPUSet, error) {
202+
// Handle empty string.
203+
if s == "" {
204+
return New(), nil
205+
}
206+
207+
result := New()
208+
209+
// Split CPU list string:
210+
// "0-5,34,46-48" => ["0-5", "34", "46-48"]
211+
ranges := strings.Split(s, ",")
212+
213+
for _, r := range ranges {
214+
boundaries := strings.SplitN(r, "-", 2)
215+
if len(boundaries) == 1 {
216+
// Handle ranges that consist of only one element like "34".
217+
elem, err := strconv.Atoi(boundaries[0])
218+
if err != nil {
219+
return New(), err
220+
}
221+
result.add(elem)
222+
} else if len(boundaries) == 2 {
223+
// Handle multi-element ranges like "0-5".
224+
start, err := strconv.Atoi(boundaries[0])
225+
if err != nil {
226+
return New(), err
227+
}
228+
end, err := strconv.Atoi(boundaries[1])
229+
if err != nil {
230+
return New(), err
231+
}
232+
if start > end {
233+
return New(), fmt.Errorf("invalid range %q (%d > %d)", r, start, end)
234+
}
235+
// start == end is acceptable (1-1 -> 1)
236+
237+
// Add all elements to the result.
238+
// e.g. "0-5", "46-48" => [0, 1, 2, 3, 4, 5, 46, 47, 48].
239+
for e := start; e <= end; e++ {
240+
result.add(e)
241+
}
242+
}
243+
}
244+
return result, nil
245+
}
246+
247+
// Clone returns a copy of this CPU set.
248+
func (s CPUSet) Clone() CPUSet {
249+
r := New()
250+
for elem := range s.elems {
251+
r.add(elem)
252+
}
253+
return r
254+
}

0 commit comments

Comments
 (0)