diff --git a/pkg/kubelet/cm/topologymanager/policy_single_numa_node.go b/pkg/kubelet/cm/topologymanager/policy_single_numa_node.go index eb8cbd1e12a..ccbbe213aec 100644 --- a/pkg/kubelet/cm/topologymanager/policy_single_numa_node.go +++ b/pkg/kubelet/cm/topologymanager/policy_single_numa_node.go @@ -18,6 +18,7 @@ package topologymanager import ( "k8s.io/klog" + "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask" "k8s.io/kubernetes/pkg/kubelet/lifecycle" ) @@ -59,95 +60,100 @@ func (p *singleNumaNodePolicy) filterHints(allResourcesHints [][]TopologyHint) [ for _, oneResourceHints := range allResourcesHints { var filtered []TopologyHint 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 { filtered = append(filtered, hint) } } - filteredResourcesHints = append(filteredResourcesHints, filtered) } return filteredResourcesHints } 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 // hints returned by each hint provider. If no hints are provided, assume // that provider has no preference for topology-aware allocation. - var allResourcesHints [][]TopologyHint + var allProviderHints [][]TopologyHint for _, hints := range providersHints { + // If hints is nil, insert a single, preferred any-numa hint into allProviderHints. if len(hints) == 0 { - klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with any resource, " + - "skipping.") + klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with any resource") + allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}}) continue } // Otherwise, accumulate the hints for each resource type into allProviderHints. for resource := range hints { if hints[resource] == nil { - klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with resource "+ - "'%s', skipping.", resource) + klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with resource '%s'", resource) + allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}}) continue } if len(hints[resource]) == 0 { - klog.Infof("[topologymanager] Hint Provider has no possible NUMA affinities for resource '%s'", - resource) - // return defaultHint which will fail pod admission - return TopologyHint{} + klog.Infof("[topologymanager] Hint Provider has no possible NUMA affinities for resource '%s'", resource) + allProviderHints = append(allProviderHints, []TopologyHint{{nil, false}}) + continue } - 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) - // If no hints, or there is a resource with empty hints after filtering, then policy - // 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{} - } - } + // Filter to only include don't cares and hints with a single NUMA node. + allProviderHints = p.filterHints(allProviderHints) // Set the bestHint to return from this function as {nil false}. // This will only be returned if no better hint can be found when // merging hints from each hint provider. - bestHint := TopologyHint{} - iterateAllProviderTopologyHints(allResourcesHints, func(permutation []TopologyHint) { + bestHint := TopologyHint{defaultAffinity, false} + 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) - // Only consider mergedHints that result in a NUMANodeAffinity == 1 to - // replace the current defaultHint. - if mergedHint.NUMANodeAffinity.Count() != 1 { + + // Only consider mergedHints that result in a NUMANodeAffinity > 0 to + // replace the current bestHint. + if mergedHint.NUMANodeAffinity.Count() == 0 { return } - // If the current bestHint NUMANodeAffinity is nil, update bestHint - // to the current mergedHint. - if bestHint.NUMANodeAffinity == nil { + // If the current bestHint is non-preferred and the new mergedHint is + // preferred, always choose the preferred hint over the non-preferred one. + if mergedHint.Preferred && !bestHint.Preferred { bestHint = mergedHint return } - // Only consider mergedHints that have a narrower NUMANodeAffinity - // than the NUMANodeAffinity in the current bestHint. + // If the current bestHint is preferred and the new mergedHint is + // 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) { return } + // In all other cases, update bestHint to the current mergedHint bestHint = mergedHint }) + + if bestHint.NUMANodeAffinity.IsEqual(defaultAffinity) { + bestHint = TopologyHint{nil, bestHint.Preferred} + } + return bestHint } diff --git a/pkg/kubelet/cm/topologymanager/policy_single_numa_node_test.go b/pkg/kubelet/cm/topologymanager/policy_single_numa_node_test.go index c4a8b669c89..d8664e46b5c 100644 --- a/pkg/kubelet/cm/topologymanager/policy_single_numa_node_test.go +++ b/pkg/kubelet/cm/topologymanager/policy_single_numa_node_test.go @@ -77,7 +77,9 @@ func TestPolicySingleNumaNodeFilterHints(t *testing.T) { }, expectedResources: [][]TopologyHint{ []TopologyHint(nil), - []TopologyHint(nil), + { + {NUMANodeAffinity: nil, Preferred: true}, + }, }, }, { @@ -98,6 +100,7 @@ func TestPolicySingleNumaNodeFilterHints(t *testing.T) { }, { {NUMANodeAffinity: NewTestBitMask(1), Preferred: true}, + {NUMANodeAffinity: nil, Preferred: true}, }, }, },