Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import 'cpuset' from kubernetes repository in kubernetes/utils #267

Merged
merged 45 commits into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
b85b369
Add cpuset helper library.
ConnorDoyle Aug 22, 2017
d1715d6
Renamed CPUSet.AsSlice() => CPUSet.ToSlice()
ConnorDoyle Aug 23, 2017
4fa778d
Add CPUSetBuilder, make CPUSet immutable.
ConnorDoyle Aug 23, 2017
ddade34
CPU Manager initialization and lifecycle calls.
ConnorDoyle Aug 28, 2017
f1d8919
Revert "CPU manager wiring and `none` policy"
shyamjvs Sep 1, 2017
29447ad
Un-revert "CPU manager wiring and `none` policy"
ConnorDoyle Sep 1, 2017
ec56fa4
update BUILD files
ixdy Oct 12, 2017
cff40fd
Autogenerate BUILD files
ixdy Dec 23, 2017
7eb02a2
Autogenerated: hack/update-bazel.sh
ixdy Feb 16, 2018
7e40445
Move from glog to klog
dims Nov 9, 2018
4b7ce99
Updated OWNERS files to include link to docs
rlenferink Jan 30, 2019
698abcb
Obtain unsorted slice in cpuAccumulator#freeCores
tedyu May 3, 2019
c6ec728
Union all CPUSets in one round
tedyu May 3, 2019
784b297
Add test for CPUSet#UnionAll
tedyu May 16, 2019
f80a642
Merge pull request #77421 from tedyu/cpu-free-no-sort
k8s-ci-robot May 16, 2019
e9313b0
Merge pull request #77609 from tedyu/union-all-test
k8s-ci-robot May 17, 2019
095fd5a
switch over k/k to use klog v2
dims Apr 17, 2020
6a3eb90
Run hack/update-vendor.sh
dims May 14, 2020
a30212f
add sjenning as kubelet approver
sjenning Jun 16, 2020
3daa5f4
Provide additional methods under the CPUSet
Jan 18, 2021
8ad3669
hack/update-bazel.sh
BenTheElder Feb 28, 2021
c292b98
e2e: node: add tests for GetAllocatableResources
ffromani Oct 14, 2020
d75b841
Migrate pkg/kubelet/cm/ top level files to structured logging
utsavoza Mar 9, 2021
799a0c9
Merge pull request #100007 from utsavoza/ugo/issue-98976/09-03-2021
k8s-ci-robot Mar 16, 2021
0e7c4f7
cpuset.Parse: Fix edge cases and add negative tests
lack Mar 25, 2021
df4f9fd
Fix kubelet cpuset typo
saintube Jun 10, 2021
f2bcb51
Fix staticcheck failure in pkg/kubelet/cm/cpuset
tiloso Jul 1, 2021
0e0c352
Check in OWNERS modified by update-yamlfmt.sh
dims Dec 10, 2021
4104a4e
Cleanup OWNERS files (No Activity in the last year)
dims Dec 10, 2021
6dd4eaf
Fix comment typo
chymy Mar 14, 2022
fd3ebb5
Optimize: file /cpuset slice make cap (#112270)
demoManito Sep 30, 2022
145217e
cpuset: Convert Union arguments to variadic
iancoolidge Nov 8, 2022
1d9bc82
cpuset: Remove 'MustParse' method
iancoolidge Nov 8, 2022
0ac3d42
cpuset: Remove *Int64 methods
iancoolidge Nov 8, 2022
8370a8e
cpuset: Make 'ToSlice*' methods look like 'set' methods
iancoolidge Nov 8, 2022
d373be6
cpuset: hide 'Filter' API
iancoolidge Dec 19, 2022
26783f0
cpuset: Rename 'NewCPUSet' to 'New'
iancoolidge Dec 19, 2022
4477621
cpuset: Delete 'builder' methods
iancoolidge Nov 8, 2022
0ab6448
cpuset: Add package comment
iancoolidge Jan 3, 2023
b911e13
cpuset: Fix Parse() error message for n-k s.t. k<n
iancoolidge Jan 27, 2023
2160ea2
cpuset: Add a few more test cases
iancoolidge Jan 27, 2023
005e850
cpuset: Convert Fatalf to Errrof in tests
iancoolidge Feb 21, 2023
da7083c
cpuset: Move into cpuset/ directory
iancoolidge Mar 2, 2023
442de19
Merge branch 'devel-cpuset-src' of /usr/local/google/home/icoolidge/s…
iancoolidge Mar 2, 2023
3aa0d1f
cpuset: Fixup owners and add origin comment
iancoolidge Nov 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cpuset/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# See the OWNERS docs at https://go.k8s.io/owners
iancoolidge marked this conversation as resolved.
Show resolved Hide resolved

approvers:
- dchen1107
- derekwaynecarr
iancoolidge marked this conversation as resolved.
Show resolved Hide resolved
- ffromani
- klueska
- SergeyKanzhelev
256 changes: 256 additions & 0 deletions cpuset/cpuset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/*
Copyright 2017 The Kubernetes Authors.
iancoolidge marked this conversation as resolved.
Show resolved Hide resolved

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package cpuset represents a collection of CPUs in a 'set' data structure.
iancoolidge marked this conversation as resolved.
Show resolved Hide resolved
//
// It can be used to represent core IDs, hyper thread siblings, CPU nodes, or processor IDs.
//
// The only special thing about this package is that
// methods are provided to convert back and forth from Linux 'list' syntax.
// See http://man7.org/linux/man-pages/man7/cpuset.7.html#FORMATS for details.
//
// Future work can migrate this to use a 'set' library, and relax the dubious 'immutable' property.
//
// This package was originally developed in the 'kubernetes' repository.
package cpuset

import (
"bytes"
"fmt"
"reflect"
"sort"
"strconv"
"strings"
)

// CPUSet is a thread-safe, immutable set-like data structure for CPU IDs.
thockin marked this conversation as resolved.
Show resolved Hide resolved
type CPUSet struct {
elems map[int]struct{}
}

// New returns a new CPUSet containing the supplied elements.
func New(cpus ...int) CPUSet {
s := CPUSet{
elems: map[int]struct{}{},
}
for _, c := range cpus {
s.add(c)
}
return s
}

// add adds the supplied elements to the CPUSet.
// It is intended for internal use only, since it mutates the CPUSet.
func (s CPUSet) add(elems ...int) {
for _, elem := range elems {
s.elems[elem] = struct{}{}
}
}

// Size returns the number of elements in this set.
func (s CPUSet) Size() int {
return len(s.elems)
}

// IsEmpty returns true if there are zero elements in this set.
func (s CPUSet) IsEmpty() bool {
return s.Size() == 0
}

// Contains returns true if the supplied element is present in this set.
func (s CPUSet) Contains(cpu int) bool {
_, found := s.elems[cpu]
return found
}

// Equals returns true if the supplied set contains exactly the same elements
// as this set (s IsSubsetOf s2 and s2 IsSubsetOf s).
func (s CPUSet) Equals(s2 CPUSet) bool {
return reflect.DeepEqual(s.elems, s2.elems)
}

// filter returns a new CPU set that contains all of the elements from this
// set that match the supplied predicate, without mutating the source set.
func (s CPUSet) filter(predicate func(int) bool) CPUSet {
r := New()
for cpu := range s.elems {
if predicate(cpu) {
r.add(cpu)
}
}
return r
}

// IsSubsetOf returns true if the supplied set contains all the elements
func (s CPUSet) IsSubsetOf(s2 CPUSet) bool {
result := true
for cpu := range s.elems {
if !s2.Contains(cpu) {
result = false
break
}
}
return result
}

// Union returns a new CPU set that contains all of the elements from this
// set and all of the elements from the supplied sets, without mutating
// either source set.
func (s CPUSet) Union(s2 ...CPUSet) CPUSet {
r := New()
for cpu := range s.elems {
r.add(cpu)
}
for _, cs := range s2 {
for cpu := range cs.elems {
r.add(cpu)
}
}
return r
}

// Intersection returns a new CPU set that contains all of the elements
// that are present in both this set and the supplied set, without mutating
// either source set.
func (s CPUSet) Intersection(s2 CPUSet) CPUSet {
return s.filter(func(cpu int) bool { return s2.Contains(cpu) })
}

// Difference returns a new CPU set that contains all of the elements that
// are present in this set and not the supplied set, without mutating either
// source set.
func (s CPUSet) Difference(s2 CPUSet) CPUSet {
return s.filter(func(cpu int) bool { return !s2.Contains(cpu) })
}

// List returns a slice of integers that contains all elements from
// this set. The list is sorted.
func (s CPUSet) List() []int {
result := s.UnsortedList()
sort.Ints(result)
return result
}

// UnsortedList returns a slice of integers that contains all elements from
// this set.
func (s CPUSet) UnsortedList() []int {
result := make([]int, 0, len(s.elems))
for cpu := range s.elems {
result = append(result, cpu)
}
return result
}

// String returns a new string representation of the elements in this CPU set
// in canonical linux CPU list format.
//
// See: http://man7.org/linux/man-pages/man7/cpuset.7.html#FORMATS
func (s CPUSet) String() string {
if s.IsEmpty() {
return ""
}

elems := s.List()

type rng struct {
start int
end int
}

ranges := []rng{{elems[0], elems[0]}}

for i := 1; i < len(elems); i++ {
lastRange := &ranges[len(ranges)-1]
// if this element is adjacent to the high end of the last range
if elems[i] == lastRange.end+1 {
// then extend the last range to include this element
lastRange.end = elems[i]
continue
}
// otherwise, start a new range beginning with this element
ranges = append(ranges, rng{elems[i], elems[i]})
}

// construct string from ranges
var result bytes.Buffer
for _, r := range ranges {
if r.start == r.end {
result.WriteString(strconv.Itoa(r.start))
} else {
result.WriteString(fmt.Sprintf("%d-%d", r.start, r.end))
}
result.WriteString(",")
}
return strings.TrimRight(result.String(), ",")
}

// Parse CPUSet constructs a new CPU set from a Linux CPU list formatted string.
//
// See: http://man7.org/linux/man-pages/man7/cpuset.7.html#FORMATS
func Parse(s string) (CPUSet, error) {
// Handle empty string.
if s == "" {
return New(), nil
}

result := New()

// Split CPU list string:
// "0-5,34,46-48" => ["0-5", "34", "46-48"]
ranges := strings.Split(s, ",")

for _, r := range ranges {
boundaries := strings.SplitN(r, "-", 2)
if len(boundaries) == 1 {
// Handle ranges that consist of only one element like "34".
elem, err := strconv.Atoi(boundaries[0])
if err != nil {
return New(), err
}
result.add(elem)
} else if len(boundaries) == 2 {
// Handle multi-element ranges like "0-5".
start, err := strconv.Atoi(boundaries[0])
if err != nil {
return New(), err
}
end, err := strconv.Atoi(boundaries[1])
if err != nil {
return New(), err
}
if start > end {
thockin marked this conversation as resolved.
Show resolved Hide resolved
return New(), fmt.Errorf("invalid range %q (%d > %d)", r, start, end)
}
// start == end is acceptable (1-1 -> 1)

// Add all elements to the result.
// e.g. "0-5", "46-48" => [0, 1, 2, 3, 4, 5, 46, 47, 48].
for e := start; e <= end; e++ {
result.add(e)
}
}
}
return result, nil
}

// Clone returns a copy of this CPU set.
func (s CPUSet) Clone() CPUSet {
r := New()
for elem := range s.elems {
r.add(elem)
}
return r
}
Loading