mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #72913 from nolancon/topology-manager-socket-mask
Add Socket Mask for Topology Manager
This commit is contained in:
commit
3b4473f45a
@ -166,6 +166,7 @@ filegroup(
|
|||||||
"//pkg/kubelet/cm/cpumanager:all-srcs",
|
"//pkg/kubelet/cm/cpumanager:all-srcs",
|
||||||
"//pkg/kubelet/cm/cpuset:all-srcs",
|
"//pkg/kubelet/cm/cpuset:all-srcs",
|
||||||
"//pkg/kubelet/cm/devicemanager:all-srcs",
|
"//pkg/kubelet/cm/devicemanager:all-srcs",
|
||||||
|
"//pkg/kubelet/cm/topologymanager/socketmask:all-srcs",
|
||||||
"//pkg/kubelet/cm/util:all-srcs",
|
"//pkg/kubelet/cm/util:all-srcs",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
|
28
pkg/kubelet/cm/topologymanager/socketmask/BUILD
Normal file
28
pkg/kubelet/cm/topologymanager/socketmask/BUILD
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["socketmask.go"],
|
||||||
|
importpath = "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/socketmask",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = ["socketmask_test.go"],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
)
|
152
pkg/kubelet/cm/topologymanager/socketmask/socketmask.go
Normal file
152
pkg/kubelet/cm/topologymanager/socketmask/socketmask.go
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 The Kubernetes Authors.
|
||||||
|
|
||||||
|
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 socketmask
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
//SocketMask interface allows hint providers to create SocketMasks for TopologyHints
|
||||||
|
type SocketMask interface {
|
||||||
|
Add(sockets ...int) error
|
||||||
|
Remove(sockets ...int) error
|
||||||
|
And(masks ...SocketMask)
|
||||||
|
Or(masks ...SocketMask)
|
||||||
|
Clear()
|
||||||
|
Fill()
|
||||||
|
IsEqual(mask SocketMask) bool
|
||||||
|
IsEmpty() bool
|
||||||
|
IsSet(socket int) bool
|
||||||
|
String() string
|
||||||
|
Count() int
|
||||||
|
GetSockets() []int
|
||||||
|
}
|
||||||
|
|
||||||
|
type socketMask uint64
|
||||||
|
|
||||||
|
//NewSocketMask creates a new SocketMask
|
||||||
|
func NewSocketMask(sockets ...int) (SocketMask, error) {
|
||||||
|
s := socketMask(0)
|
||||||
|
err := (&s).Add(sockets...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add adds the sockets with topology affinity to the SocketMask
|
||||||
|
func (s *socketMask) Add(sockets ...int) error {
|
||||||
|
mask := *s
|
||||||
|
for _, i := range sockets {
|
||||||
|
if i < 0 || i >= 64 {
|
||||||
|
return fmt.Errorf("socket number must be in range 0-63")
|
||||||
|
}
|
||||||
|
mask |= 1 << uint64(i)
|
||||||
|
}
|
||||||
|
*s = mask
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove removes specified sockets from SocketMask
|
||||||
|
func (s *socketMask) Remove(sockets ...int) error {
|
||||||
|
mask := *s
|
||||||
|
for _, i := range sockets {
|
||||||
|
if i < 0 || i >= 64 {
|
||||||
|
return fmt.Errorf("socket number must be in range 0-63")
|
||||||
|
}
|
||||||
|
mask &^= 1 << uint64(i)
|
||||||
|
}
|
||||||
|
*s = mask
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//And performs and operation on all bits in masks
|
||||||
|
func (s *socketMask) And(masks ...SocketMask) {
|
||||||
|
for _, m := range masks {
|
||||||
|
*s &= *m.(*socketMask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Or performs or operation on all bits in masks
|
||||||
|
func (s *socketMask) Or(masks ...SocketMask) {
|
||||||
|
for _, m := range masks {
|
||||||
|
*s |= *m.(*socketMask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clear resets all bits in mask to zero
|
||||||
|
func (s *socketMask) Clear() {
|
||||||
|
*s = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//Fill sets all bits in mask to one
|
||||||
|
func (s *socketMask) Fill() {
|
||||||
|
*s = socketMask(^uint64(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
//IsEmpty checks mask to see if all bits are zero
|
||||||
|
func (s *socketMask) IsEmpty() bool {
|
||||||
|
return *s == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//IsSet checks socket in mask to see if bit is set to one
|
||||||
|
func (s *socketMask) IsSet(socket int) bool {
|
||||||
|
if socket < 0 || socket >= 64 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return (*s & (1 << uint64(socket))) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//IsEqual checks if masks are equal
|
||||||
|
func (s *socketMask) IsEqual(mask SocketMask) bool {
|
||||||
|
return *s == *mask.(*socketMask)
|
||||||
|
}
|
||||||
|
|
||||||
|
//String converts mask to string
|
||||||
|
func (s *socketMask) String() string {
|
||||||
|
str := ""
|
||||||
|
for i := uint64(0); i < 64; i++ {
|
||||||
|
if (*s & (1 << i)) > 0 {
|
||||||
|
str += "1"
|
||||||
|
} else {
|
||||||
|
str += "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
//Count counts number of bits in mask set to one
|
||||||
|
func (s *socketMask) Count() int {
|
||||||
|
count := 0
|
||||||
|
for i := uint64(0); i < 64; i++ {
|
||||||
|
if (*s & (1 << i)) > 0 {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetSockets returns each socket number with bits set to one
|
||||||
|
func (s *socketMask) GetSockets() []int {
|
||||||
|
var sockets []int
|
||||||
|
for i := uint64(0); i < 64; i++ {
|
||||||
|
if (*s & (1 << i)) > 0 {
|
||||||
|
sockets = append(sockets, int(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sockets
|
||||||
|
}
|
290
pkg/kubelet/cm/topologymanager/socketmask/socketmask_test.go
Normal file
290
pkg/kubelet/cm/topologymanager/socketmask/socketmask_test.go
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 The Kubernetes Authors.
|
||||||
|
|
||||||
|
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 socketmask
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewSocketMask(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
socket int
|
||||||
|
expectedMask string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "New SocketMask with socket 0 set",
|
||||||
|
socket: int(0),
|
||||||
|
expectedMask: "1000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
sm, _ := NewSocketMask(0)
|
||||||
|
if sm.String() != tc.expectedMask {
|
||||||
|
t.Errorf("Expected mask to be %v, got %v", tc.expectedMask, sm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAdd(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
firstSocket int
|
||||||
|
secondSocket int
|
||||||
|
expectedMask string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Reset bit 1 SocketMask to 0",
|
||||||
|
firstSocket: 0,
|
||||||
|
secondSocket: 1,
|
||||||
|
expectedMask: "1100000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
mask, _ := NewSocketMask()
|
||||||
|
mask.Add(tc.firstSocket, tc.secondSocket)
|
||||||
|
if mask.String() != tc.expectedMask {
|
||||||
|
t.Errorf("Expected mask to be %v, got %v", tc.expectedMask, mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemove(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
firstSocketSet int
|
||||||
|
secondSocketSet int
|
||||||
|
firstSocketRemove int
|
||||||
|
expectedMask string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Reset bit 1 SocketMask to 0",
|
||||||
|
firstSocketSet: 0,
|
||||||
|
secondSocketSet: 1,
|
||||||
|
firstSocketRemove: 0,
|
||||||
|
expectedMask: "0100000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
mask, _ := NewSocketMask(tc.firstSocketSet, tc.secondSocketSet)
|
||||||
|
mask.Remove(tc.firstSocketRemove)
|
||||||
|
if mask.String() != tc.expectedMask {
|
||||||
|
t.Errorf("Expected mask to be %v, got %v", tc.expectedMask, mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnd(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
firstMaskBit int
|
||||||
|
secondMaskBit int
|
||||||
|
andMask string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "And socket masks",
|
||||||
|
firstMaskBit: 0,
|
||||||
|
secondMaskBit: 0,
|
||||||
|
andMask: "1000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
firstMask, _ := NewSocketMask(tc.firstMaskBit)
|
||||||
|
secondMask, _ := NewSocketMask(tc.secondMaskBit)
|
||||||
|
firstMask.And(secondMask)
|
||||||
|
if firstMask.String() != string(tc.andMask) {
|
||||||
|
t.Errorf("Expected mask to be %v, got %v", tc.andMask, firstMask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOr(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
firstMaskBit int
|
||||||
|
secondMaskBit int
|
||||||
|
orMask string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Or socket masks",
|
||||||
|
firstMaskBit: int(0),
|
||||||
|
secondMaskBit: int(1),
|
||||||
|
orMask: "1100000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
firstMask, _ := NewSocketMask(tc.firstMaskBit)
|
||||||
|
secondMask, _ := NewSocketMask(tc.secondMaskBit)
|
||||||
|
firstMask.Or(secondMask)
|
||||||
|
if firstMask.String() != string(tc.orMask) {
|
||||||
|
t.Errorf("Expected mask to be %v, got %v", tc.orMask, firstMask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClear(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
firstBit int
|
||||||
|
secondBit int
|
||||||
|
clearedMask string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Clear socket masks",
|
||||||
|
firstBit: int(0),
|
||||||
|
secondBit: int(1),
|
||||||
|
clearedMask: "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
mask, _ := NewSocketMask(tc.firstBit, tc.secondBit)
|
||||||
|
mask.Clear()
|
||||||
|
if mask.String() != string(tc.clearedMask) {
|
||||||
|
t.Errorf("Expected mask to be %v, got %v", tc.clearedMask, mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFill(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
filledMask string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Fill socket masks",
|
||||||
|
filledMask: "1111111111111111111111111111111111111111111111111111111111111111",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
mask, _ := NewSocketMask()
|
||||||
|
mask.Fill()
|
||||||
|
if mask.String() != string(tc.filledMask) {
|
||||||
|
t.Errorf("Expected mask to be %v, got %v", tc.filledMask, mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsEmpty(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
maskBit int
|
||||||
|
expectedEmpty bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Check if mask is empty",
|
||||||
|
maskBit: int(0),
|
||||||
|
expectedEmpty: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
mask, _ := NewSocketMask(tc.maskBit)
|
||||||
|
empty := mask.IsEmpty()
|
||||||
|
if empty {
|
||||||
|
t.Errorf("Expected value to be %v, got %v", tc.expectedEmpty, empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsSet(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
maskBit int
|
||||||
|
expectedSet bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Check if mask bit is set",
|
||||||
|
maskBit: int(0),
|
||||||
|
expectedSet: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
mask, _ := NewSocketMask(tc.maskBit)
|
||||||
|
set := mask.IsSet(tc.maskBit)
|
||||||
|
if !set {
|
||||||
|
t.Errorf("Expected value to be %v, got %v", tc.expectedSet, set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsEqual(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
firstMaskBit int
|
||||||
|
secondMaskBit int
|
||||||
|
isEqual bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "And socket masks",
|
||||||
|
firstMaskBit: int(0),
|
||||||
|
secondMaskBit: int(0),
|
||||||
|
isEqual: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
firstMask, _ := NewSocketMask(tc.firstMaskBit)
|
||||||
|
secondMask, _ := NewSocketMask(tc.secondMaskBit)
|
||||||
|
isEqual := firstMask.IsEqual(secondMask)
|
||||||
|
if !isEqual {
|
||||||
|
t.Errorf("Expected mask to be %v, got %v", tc.isEqual, isEqual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCount(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
maskBit int
|
||||||
|
expectedCount int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Count number of bits set in full mask",
|
||||||
|
maskBit: 0,
|
||||||
|
expectedCount: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
mask, _ := NewSocketMask(tc.maskBit)
|
||||||
|
count := mask.Count()
|
||||||
|
if count != tc.expectedCount {
|
||||||
|
t.Errorf("Expected value to be %v, got %v", tc.expectedCount, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSockets(t *testing.T) {
|
||||||
|
tcases := []struct {
|
||||||
|
name string
|
||||||
|
firstSocket int
|
||||||
|
secondSocket int
|
||||||
|
expectedSockets []int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get number of each socket which has been set",
|
||||||
|
firstSocket: 0,
|
||||||
|
secondSocket: 1,
|
||||||
|
expectedSockets: []int{0, 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcases {
|
||||||
|
mask, _ := NewSocketMask(tc.firstSocket, tc.secondSocket)
|
||||||
|
sockets := mask.GetSockets()
|
||||||
|
if !reflect.DeepEqual(sockets, tc.expectedSockets) {
|
||||||
|
t.Errorf("Expected value to be %v, got %v", tc.expectedSockets, sockets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user