k8s.io/kubernetes@v1.29.3/pkg/kubelet/cm/topologymanager/numa_info.go (about) 1 /* 2 Copyright 2022 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 topologymanager 18 19 import ( 20 "fmt" 21 22 cadvisorapi "github.com/google/cadvisor/info/v1" 23 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask" 24 ) 25 26 type NUMADistances map[int][]uint64 27 28 type NUMAInfo struct { 29 Nodes []int 30 NUMADistances NUMADistances 31 } 32 33 func NewNUMAInfo(topology []cadvisorapi.Node, opts PolicyOptions) (*NUMAInfo, error) { 34 var numaNodes []int 35 distances := map[int][]uint64{} 36 for _, node := range topology { 37 numaNodes = append(numaNodes, node.Id) 38 39 var nodeDistance []uint64 40 if opts.PreferClosestNUMA { 41 nodeDistance = node.Distances 42 if nodeDistance == nil { 43 return nil, fmt.Errorf("error getting NUMA distances from cadvisor") 44 } 45 } 46 distances[node.Id] = nodeDistance 47 } 48 49 numaInfo := &NUMAInfo{ 50 Nodes: numaNodes, 51 NUMADistances: distances, 52 } 53 54 return numaInfo, nil 55 } 56 57 func (n *NUMAInfo) Narrowest(m1 bitmask.BitMask, m2 bitmask.BitMask) bitmask.BitMask { 58 if m1.IsNarrowerThan(m2) { 59 return m1 60 } 61 return m2 62 } 63 64 func (n *NUMAInfo) Closest(m1 bitmask.BitMask, m2 bitmask.BitMask) bitmask.BitMask { 65 // If the length of both bitmasks aren't the same, choose the one that is narrowest. 66 if m1.Count() != m2.Count() { 67 return n.Narrowest(m1, m2) 68 } 69 70 m1Distance := n.NUMADistances.CalculateAverageFor(m1) 71 m2Distance := n.NUMADistances.CalculateAverageFor(m2) 72 // If average distance is the same, take bitmask with more lower-number bits set. 73 if m1Distance == m2Distance { 74 if m1.IsLessThan(m2) { 75 return m1 76 } 77 return m2 78 } 79 80 // Otherwise, return the bitmask with the shortest average distance between NUMA nodes. 81 if m1Distance < m2Distance { 82 return m1 83 } 84 85 return m2 86 } 87 88 func (n NUMAInfo) DefaultAffinityMask() bitmask.BitMask { 89 defaultAffinity, _ := bitmask.NewBitMask(n.Nodes...) 90 return defaultAffinity 91 } 92 93 func (d NUMADistances) CalculateAverageFor(bm bitmask.BitMask) float64 { 94 // This should never happen, but just in case make sure we do not divide by zero. 95 if bm.Count() == 0 { 96 return 0 97 } 98 99 var count float64 = 0 100 var sum float64 = 0 101 for _, node1 := range bm.GetBits() { 102 for _, node2 := range bm.GetBits() { 103 sum += float64(d[node1][node2]) 104 count++ 105 } 106 } 107 108 return sum / count 109 }