github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/sysadvisor/plugin/qosaware/resource/cpu/assembler/headroomassembler/assembler_dedicated.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 headroomassembler
    18  
    19  import (
    20  	"fmt"
    21  
    22  	v1 "k8s.io/api/core/v1"
    23  	"k8s.io/apimachinery/pkg/api/resource"
    24  	"k8s.io/klog/v2"
    25  
    26  	"github.com/kubewharf/katalyst-core/pkg/agent/qrm-plugins/cpu/dynamicpolicy/state"
    27  	"github.com/kubewharf/katalyst-core/pkg/agent/sysadvisor/metacache"
    28  	"github.com/kubewharf/katalyst-core/pkg/agent/sysadvisor/plugin/qosaware/resource/cpu/region"
    29  	"github.com/kubewharf/katalyst-core/pkg/agent/sysadvisor/types"
    30  	"github.com/kubewharf/katalyst-core/pkg/config"
    31  	"github.com/kubewharf/katalyst-core/pkg/metaserver"
    32  	"github.com/kubewharf/katalyst-core/pkg/metrics"
    33  	"github.com/kubewharf/katalyst-core/pkg/util/machine"
    34  )
    35  
    36  type HeadroomAssemblerDedicated struct {
    37  	conf               *config.Configuration
    38  	regionMap          *map[string]region.QoSRegion
    39  	reservedForReclaim *map[int]int
    40  	numaAvailable      *map[int]int
    41  	nonBindingNumas    *machine.CPUSet
    42  
    43  	metaReader metacache.MetaReader
    44  	metaServer *metaserver.MetaServer
    45  	emitter    metrics.MetricEmitter
    46  }
    47  
    48  func NewHeadroomAssemblerDedicated(conf *config.Configuration, _ interface{}, regionMap *map[string]region.QoSRegion,
    49  	reservedForReclaim *map[int]int, numaAvailable *map[int]int, nonBindingNumas *machine.CPUSet,
    50  	metaReader metacache.MetaReader, metaServer *metaserver.MetaServer, emitter metrics.MetricEmitter,
    51  ) HeadroomAssembler {
    52  	return &HeadroomAssemblerDedicated{
    53  		conf:               conf,
    54  		regionMap:          regionMap,
    55  		reservedForReclaim: reservedForReclaim,
    56  		numaAvailable:      numaAvailable,
    57  		nonBindingNumas:    nonBindingNumas,
    58  
    59  		metaReader: metaReader,
    60  		metaServer: metaServer,
    61  		emitter:    emitter,
    62  	}
    63  }
    64  
    65  func (ha *HeadroomAssemblerDedicated) GetHeadroom() (resource.Quantity, error) {
    66  	dynamicConfig := ha.conf.GetDynamicConfiguration()
    67  	reserved := ha.conf.GetDynamicConfiguration().ReservedResourceForAllocate[v1.ResourceCPU]
    68  
    69  	// return zero when reclaim is disabled
    70  	if !dynamicConfig.EnableReclaim {
    71  		return *resource.NewQuantity(0, resource.DecimalSI), nil
    72  	}
    73  
    74  	headroomTotal := 0.0
    75  	emptyNUMAs := ha.metaServer.CPUDetails.NUMANodes()
    76  	exclusiveNUMAs := machine.NewCPUSet()
    77  
    78  	// sum up dedicated region headroom
    79  	for _, r := range *ha.regionMap {
    80  		if r.Type() == types.QoSRegionTypeDedicatedNumaExclusive {
    81  			regionInfo, ok := ha.metaReader.GetRegionInfo(r.Name())
    82  			if !ok || regionInfo == nil || regionInfo.Headroom < 0 {
    83  				return resource.Quantity{}, fmt.Errorf("failed to get headroom for %v", r.Name())
    84  			}
    85  			headroomTotal += regionInfo.Headroom
    86  			exclusiveNUMAs = exclusiveNUMAs.Union(r.GetBindingNumas())
    87  
    88  			klog.InfoS("dedicated NUMA headroom", "headroom", regionInfo.Headroom, "NUMAs", r.GetBindingNumas().String())
    89  		}
    90  		emptyNUMAs = emptyNUMAs.Difference(r.GetBindingNumas())
    91  	}
    92  
    93  	// add non binding reclaim pool size
    94  	reclaimPoolInfo, ok := ha.metaReader.GetPoolInfo(state.PoolNameReclaim)
    95  	if ok && reclaimPoolInfo != nil {
    96  		reclaimPoolNUMAs := machine.GetCPUAssignmentNUMAs(reclaimPoolInfo.TopologyAwareAssignments)
    97  		for _, numaID := range reclaimPoolNUMAs.Difference(exclusiveNUMAs).Difference(emptyNUMAs).ToSliceInt() {
    98  			headroom := float64(reclaimPoolInfo.TopologyAwareAssignments[numaID].Size())
    99  			headroomTotal += headroom
   100  
   101  			klog.InfoS("reclaim pool headroom", "headroom", headroom, "numaID", numaID)
   102  		}
   103  	}
   104  
   105  	// add empty numa headroom
   106  	for _, numaID := range emptyNUMAs.ToSliceInt() {
   107  		available, _ := (*ha.numaAvailable)[numaID]
   108  		reservedForAllocate := float64(reserved.Value()*int64(emptyNUMAs.Size())) / float64(ha.metaServer.NumNUMANodes)
   109  		reservedForReclaim, _ := (*ha.reservedForReclaim)[numaID]
   110  		headroom := float64(available) - reservedForAllocate + float64(reservedForReclaim)
   111  		headroomTotal += headroom
   112  
   113  		klog.InfoS("empty NUMA headroom", "headroom", headroom)
   114  	}
   115  
   116  	klog.Infof("[qosaware-cpu] total headroom assembled %.2f", headroomTotal)
   117  
   118  	return *resource.NewQuantity(int64(headroomTotal), resource.DecimalSI), nil
   119  }