mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
Update TopologyManager single-numa-node logic to handle "don't cares"
The logic has been updated to match the logic of the best-effort policy except in two places: 1) The hint filtering frunction has been updated to allow "don't care" hints encoded with a `nil` affinity mask, to pass through the filter in addition to hints that have just a single NUMA bit set. 2) After calculating the `bestHint` we transform "don't care" affinities encoded as having all NUMA bits set in their affinity masks into "don't care" affinities encoded as `nil`.
This commit is contained in:
parent
2905ffffa7
commit
7069b1d6e8
@ -18,6 +18,7 @@ package topologymanager
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,95 +60,100 @@ func (p *singleNumaNodePolicy) filterHints(allResourcesHints [][]TopologyHint) [
|
|||||||
for _, oneResourceHints := range allResourcesHints {
|
for _, oneResourceHints := range allResourcesHints {
|
||||||
var filtered []TopologyHint
|
var filtered []TopologyHint
|
||||||
for _, hint := range oneResourceHints {
|
for _, hint := range oneResourceHints {
|
||||||
|
if hint.NUMANodeAffinity == nil && hint.Preferred == true {
|
||||||
|
filtered = append(filtered, hint)
|
||||||
|
}
|
||||||
if hint.NUMANodeAffinity != nil && hint.NUMANodeAffinity.Count() == 1 && hint.Preferred == true {
|
if hint.NUMANodeAffinity != nil && hint.NUMANodeAffinity.Count() == 1 && hint.Preferred == true {
|
||||||
filtered = append(filtered, hint)
|
filtered = append(filtered, hint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filteredResourcesHints = append(filteredResourcesHints, filtered)
|
filteredResourcesHints = append(filteredResourcesHints, filtered)
|
||||||
}
|
}
|
||||||
return filteredResourcesHints
|
return filteredResourcesHints
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *singleNumaNodePolicy) mergeProvidersHints(providersHints []map[string][]TopologyHint) TopologyHint {
|
func (p *singleNumaNodePolicy) mergeProvidersHints(providersHints []map[string][]TopologyHint) TopologyHint {
|
||||||
|
// Set the default affinity as an any-numa affinity containing the list
|
||||||
|
// of NUMA Nodes available on this machine.
|
||||||
|
defaultAffinity, _ := bitmask.NewBitMask(p.numaNodes...)
|
||||||
|
|
||||||
// Loop through all provider hints and save an accumulated list of the
|
// Loop through all provider hints and save an accumulated list of the
|
||||||
// hints returned by each hint provider. If no hints are provided, assume
|
// hints returned by each hint provider. If no hints are provided, assume
|
||||||
// that provider has no preference for topology-aware allocation.
|
// that provider has no preference for topology-aware allocation.
|
||||||
var allResourcesHints [][]TopologyHint
|
var allProviderHints [][]TopologyHint
|
||||||
for _, hints := range providersHints {
|
for _, hints := range providersHints {
|
||||||
|
// If hints is nil, insert a single, preferred any-numa hint into allProviderHints.
|
||||||
if len(hints) == 0 {
|
if len(hints) == 0 {
|
||||||
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with any resource, " +
|
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with any resource")
|
||||||
"skipping.")
|
allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, accumulate the hints for each resource type into allProviderHints.
|
// Otherwise, accumulate the hints for each resource type into allProviderHints.
|
||||||
for resource := range hints {
|
for resource := range hints {
|
||||||
if hints[resource] == nil {
|
if hints[resource] == nil {
|
||||||
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with resource "+
|
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with resource '%s'", resource)
|
||||||
"'%s', skipping.", resource)
|
allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(hints[resource]) == 0 {
|
if len(hints[resource]) == 0 {
|
||||||
klog.Infof("[topologymanager] Hint Provider has no possible NUMA affinities for resource '%s'",
|
klog.Infof("[topologymanager] Hint Provider has no possible NUMA affinities for resource '%s'", resource)
|
||||||
resource)
|
allProviderHints = append(allProviderHints, []TopologyHint{{nil, false}})
|
||||||
// return defaultHint which will fail pod admission
|
continue
|
||||||
return TopologyHint{}
|
|
||||||
}
|
}
|
||||||
klog.Infof("[topologymanager] TopologyHints for resource '%v': %v", resource, hints[resource])
|
|
||||||
allResourcesHints = append(allResourcesHints, hints[resource])
|
allProviderHints = append(allProviderHints, hints[resource])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// In case allProviderHints length is zero it means that we have no
|
|
||||||
// preference for NUMA affinity. In that case update default hint preferred
|
|
||||||
// to true to allow scheduling.
|
|
||||||
if len(allResourcesHints) == 0 {
|
|
||||||
klog.Infof("[topologymanager] No preference for NUMA affinity from all providers")
|
|
||||||
return TopologyHint{nil, true}
|
|
||||||
}
|
|
||||||
|
|
||||||
allResourcesHints = p.filterHints(allResourcesHints)
|
// Filter to only include don't cares and hints with a single NUMA node.
|
||||||
// If no hints, or there is a resource with empty hints after filtering, then policy
|
allProviderHints = p.filterHints(allProviderHints)
|
||||||
// cannot be satisfied
|
|
||||||
if len(allResourcesHints) == 0 {
|
|
||||||
klog.Infof("[topologymanager] No hints that align to a single NUMA node.")
|
|
||||||
return TopologyHint{}
|
|
||||||
}
|
|
||||||
for _, hints := range allResourcesHints {
|
|
||||||
if len(hints) == 0 {
|
|
||||||
klog.Infof("[topologymanager] No hints that align to a single NUMA node for resource.")
|
|
||||||
return TopologyHint{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the bestHint to return from this function as {nil false}.
|
// Set the bestHint to return from this function as {nil false}.
|
||||||
// This will only be returned if no better hint can be found when
|
// This will only be returned if no better hint can be found when
|
||||||
// merging hints from each hint provider.
|
// merging hints from each hint provider.
|
||||||
bestHint := TopologyHint{}
|
bestHint := TopologyHint{defaultAffinity, false}
|
||||||
iterateAllProviderTopologyHints(allResourcesHints, func(permutation []TopologyHint) {
|
iterateAllProviderTopologyHints(allProviderHints, func(permutation []TopologyHint) {
|
||||||
|
// Get the NUMANodeAffinity from each hint in the permutation and see if any
|
||||||
|
// of them encode unpreferred allocations.
|
||||||
mergedHint := mergePermutation(p.numaNodes, permutation)
|
mergedHint := mergePermutation(p.numaNodes, permutation)
|
||||||
// Only consider mergedHints that result in a NUMANodeAffinity == 1 to
|
|
||||||
// replace the current defaultHint.
|
// Only consider mergedHints that result in a NUMANodeAffinity > 0 to
|
||||||
if mergedHint.NUMANodeAffinity.Count() != 1 {
|
// replace the current bestHint.
|
||||||
|
if mergedHint.NUMANodeAffinity.Count() == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current bestHint NUMANodeAffinity is nil, update bestHint
|
// If the current bestHint is non-preferred and the new mergedHint is
|
||||||
// to the current mergedHint.
|
// preferred, always choose the preferred hint over the non-preferred one.
|
||||||
if bestHint.NUMANodeAffinity == nil {
|
if mergedHint.Preferred && !bestHint.Preferred {
|
||||||
bestHint = mergedHint
|
bestHint = mergedHint
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only consider mergedHints that have a narrower NUMANodeAffinity
|
// If the current bestHint is preferred and the new mergedHint is
|
||||||
// than the NUMANodeAffinity in the current bestHint.
|
// non-preferred, never update bestHint, regardless of mergedHint's
|
||||||
|
// narowness.
|
||||||
|
if !mergedHint.Preferred && bestHint.Preferred {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If mergedHint and bestHint has the same preference, only consider
|
||||||
|
// mergedHints that have a narrower NUMANodeAffinity than the
|
||||||
|
// NUMANodeAffinity in the current bestHint.
|
||||||
if !mergedHint.NUMANodeAffinity.IsNarrowerThan(bestHint.NUMANodeAffinity) {
|
if !mergedHint.NUMANodeAffinity.IsNarrowerThan(bestHint.NUMANodeAffinity) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// In all other cases, update bestHint to the current mergedHint
|
// In all other cases, update bestHint to the current mergedHint
|
||||||
bestHint = mergedHint
|
bestHint = mergedHint
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if bestHint.NUMANodeAffinity.IsEqual(defaultAffinity) {
|
||||||
|
bestHint = TopologyHint{nil, bestHint.Preferred}
|
||||||
|
}
|
||||||
|
|
||||||
return bestHint
|
return bestHint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,9 @@ func TestPolicySingleNumaNodeFilterHints(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedResources: [][]TopologyHint{
|
expectedResources: [][]TopologyHint{
|
||||||
[]TopologyHint(nil),
|
[]TopologyHint(nil),
|
||||||
[]TopologyHint(nil),
|
{
|
||||||
|
{NUMANodeAffinity: nil, Preferred: true},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -98,6 +100,7 @@ func TestPolicySingleNumaNodeFilterHints(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
|
{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
|
||||||
|
{NUMANodeAffinity: nil, Preferred: true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user