github.com/kubewharf/katalyst-core@v0.5.3/pkg/scheduler/cache/nodeinfo.go (about) 1 /* 2 Copyright 2022 The Katalyst 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 cache 18 19 import ( 20 "sync" 21 22 v1 "k8s.io/api/core/v1" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/klog/v2" 25 26 apis "github.com/kubewharf/katalyst-api/pkg/apis/node/v1alpha1" 27 "github.com/kubewharf/katalyst-api/pkg/consts" 28 "github.com/kubewharf/katalyst-core/pkg/util/native" 29 ) 30 31 // PodInfo is pod level aggregated information. 32 type PodInfo struct { 33 QoSResourcesRequested *native.QoSResource 34 QoSResourcesNonZeroRequested *native.QoSResource 35 } 36 37 // NodeInfo is node level aggregated information. 38 type NodeInfo struct { 39 // Mutex guards all fields within this NodeInfo struct. 40 Mutex sync.RWMutex 41 42 // Total requested qos resources of this node. This includes assumed 43 // pods, which scheduler has sent for binding, but may not be scheduled yet. 44 QoSResourcesRequested *native.QoSResource 45 // Total requested qos resources of this node with a minimum value 46 // applied to each container's CPU and memory requests. This does not reflect 47 // the actual resource requests for this node, but is used to avoid scheduling 48 // many zero-request pods onto one node. 49 QoSResourcesNonZeroRequested *native.QoSResource 50 // We store qos allocatedResources (which is CNR.Status.BestEffortResourceAllocatable.*) explicitly 51 // as int64, to avoid conversions and accessing map. 52 QoSResourcesAllocatable *native.QoSResource 53 54 // record PodInfo here since we may have the functionality to 55 // change pod resources. 56 Pods map[string]*PodInfo 57 58 // node TopologyPolicy and TopologyZones from CNR status. 59 // is total CNR data necessary in extendedCache ? 60 ResourceTopology *ResourceTopology 61 62 // record assumed pod resource util pod is watched in CNR updated events. 63 AssumedPodResources native.PodResource 64 } 65 66 // NewNodeInfo returns a ready to use empty NodeInfo object. 67 // If any pods are given in arguments, their information will be aggregated in 68 // the returned object. 69 func NewNodeInfo() *NodeInfo { 70 ni := &NodeInfo{ 71 QoSResourcesRequested: &native.QoSResource{}, 72 QoSResourcesNonZeroRequested: &native.QoSResource{}, 73 QoSResourcesAllocatable: &native.QoSResource{}, 74 Pods: make(map[string]*PodInfo), 75 ResourceTopology: new(ResourceTopology), 76 AssumedPodResources: native.PodResource{}, 77 } 78 return ni 79 } 80 81 // UpdateNodeInfo updates the NodeInfo. 82 func (n *NodeInfo) UpdateNodeInfo(cnr *apis.CustomNodeResource) { 83 n.Mutex.Lock() 84 defer n.Mutex.Unlock() 85 86 n.updateReclaimed(cnr) 87 88 n.updateTopology(cnr) 89 } 90 91 func (n *NodeInfo) updateReclaimed(cnr *apis.CustomNodeResource) { 92 if cnr.Status.Resources.Allocatable != nil { 93 beResourceList := *cnr.Status.Resources.Allocatable 94 if reclaimedMilliCPU, ok := beResourceList[consts.ReclaimedResourceMilliCPU]; ok { 95 n.QoSResourcesAllocatable.ReclaimedMilliCPU = reclaimedMilliCPU.Value() 96 } else { 97 n.QoSResourcesAllocatable.ReclaimedMilliCPU = 0 98 } 99 100 if reclaimedMemory, ok := beResourceList[consts.ReclaimedResourceMemory]; ok { 101 n.QoSResourcesAllocatable.ReclaimedMemory = reclaimedMemory.Value() 102 } else { 103 n.QoSResourcesAllocatable.ReclaimedMemory = 0 104 } 105 } 106 } 107 108 func (n *NodeInfo) updateTopology(cnr *apis.CustomNodeResource) { 109 for _, topologyZone := range cnr.Status.TopologyZone { 110 if topologyZone.Type != apis.TopologyTypeSocket { 111 continue 112 } 113 for _, child := range topologyZone.Children { 114 if child.Type != apis.TopologyTypeNuma { 115 continue 116 } 117 118 for _, alloc := range child.Allocations { 119 namespace, name, _, err := native.ParseNamespaceNameUIDKey(alloc.Consumer) 120 if err != nil { 121 klog.Errorf("unexpected CNR numa consumer: %v", err) 122 continue 123 } 124 // delete all pod from AssumedPodResource 125 n.AssumedPodResources.DeletePod(&v1.Pod{ 126 ObjectMeta: metav1.ObjectMeta{ 127 Name: name, 128 Namespace: namespace, 129 }, 130 }) 131 } 132 } 133 } 134 135 n.ResourceTopology.Update(cnr) 136 } 137 138 // AddPod adds pod information to this NodeInfo. 139 func (n *NodeInfo) AddPod(key string, pod *v1.Pod) { 140 // always try to clean previous pod, and then insert 141 n.RemovePod(key, pod) 142 143 res, non0CPU, non0Mem := native.CalculateQoSResource(pod) 144 145 n.Mutex.Lock() 146 defer n.Mutex.Unlock() 147 148 n.Pods[key] = &PodInfo{ 149 QoSResourcesRequested: &res, 150 QoSResourcesNonZeroRequested: &native.QoSResource{ 151 ReclaimedMilliCPU: non0CPU, 152 ReclaimedMemory: non0Mem, 153 }, 154 } 155 156 n.QoSResourcesRequested.ReclaimedMilliCPU += res.ReclaimedMilliCPU 157 n.QoSResourcesRequested.ReclaimedMemory += res.ReclaimedMemory 158 159 n.QoSResourcesNonZeroRequested.ReclaimedMilliCPU += non0CPU 160 n.QoSResourcesNonZeroRequested.ReclaimedMemory += non0Mem 161 } 162 163 // RemovePod subtracts pod information from this NodeInfo. 164 func (n *NodeInfo) RemovePod(key string, pod *v1.Pod) { 165 n.Mutex.Lock() 166 defer n.Mutex.Unlock() 167 168 podInfo, ok := n.Pods[key] 169 if !ok { 170 return 171 } 172 173 n.QoSResourcesRequested.ReclaimedMilliCPU -= podInfo.QoSResourcesRequested.ReclaimedMilliCPU 174 n.QoSResourcesRequested.ReclaimedMemory -= podInfo.QoSResourcesRequested.ReclaimedMemory 175 176 n.QoSResourcesNonZeroRequested.ReclaimedMilliCPU -= podInfo.QoSResourcesNonZeroRequested.ReclaimedMilliCPU 177 n.QoSResourcesNonZeroRequested.ReclaimedMemory -= podInfo.QoSResourcesNonZeroRequested.ReclaimedMemory 178 delete(n.Pods, key) 179 } 180 181 func (n *NodeInfo) AddAssumedPod(pod *v1.Pod) { 182 n.Mutex.Lock() 183 defer n.Mutex.Unlock() 184 n.AssumedPodResources.AddPod(pod) 185 } 186 187 func (n *NodeInfo) DeleteAssumedPod(pod *v1.Pod) { 188 n.Mutex.Lock() 189 defer n.Mutex.Unlock() 190 191 n.AssumedPodResources.DeletePod(pod) 192 } 193 194 func (n *NodeInfo) GetResourceTopologyCopy(filterFn podFilter) *ResourceTopology { 195 n.Mutex.RLock() 196 defer n.Mutex.RUnlock() 197 198 if n.ResourceTopology == nil { 199 return nil 200 } 201 202 return n.ResourceTopology.WithPodReousrce(n.AssumedPodResources, filterFn) 203 }