Skip to content

Commit 98f63ee

Browse files
authored
Merge pull request kubernetes#87460 from nolancon/policies_refactor
Refactor Topology Manager policies to reduce code duplication
2 parents 25b4c17 + 4d76b1c commit 98f63ee

File tree

5 files changed

+96
-175
lines changed

5 files changed

+96
-175
lines changed

pkg/kubelet/cm/topologymanager/policy.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package topologymanager
1818

1919
import (
20+
"k8s.io/klog"
2021
"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
2122
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
2223
)
@@ -59,6 +60,86 @@ func mergePermutation(numaNodes []int, permutation []TopologyHint) TopologyHint
5960
return TopologyHint{mergedAffinity, preferred}
6061
}
6162

63+
func filterProvidersHints(providersHints []map[string][]TopologyHint) [][]TopologyHint {
64+
// Loop through all hint providers and save an accumulated list of the
65+
// hints returned by each hint provider. If no hints are provided, assume
66+
// that provider has no preference for topology-aware allocation.
67+
var allProviderHints [][]TopologyHint
68+
for _, hints := range providersHints {
69+
// If hints is nil, insert a single, preferred any-numa hint into allProviderHints.
70+
if len(hints) == 0 {
71+
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with any resource")
72+
allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
73+
continue
74+
}
75+
76+
// Otherwise, accumulate the hints for each resource type into allProviderHints.
77+
for resource := range hints {
78+
if hints[resource] == nil {
79+
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with resource '%s'", resource)
80+
allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
81+
continue
82+
}
83+
84+
if len(hints[resource]) == 0 {
85+
klog.Infof("[topologymanager] Hint Provider has no possible NUMA affinities for resource '%s'", resource)
86+
allProviderHints = append(allProviderHints, []TopologyHint{{nil, false}})
87+
continue
88+
}
89+
90+
allProviderHints = append(allProviderHints, hints[resource])
91+
}
92+
}
93+
return allProviderHints
94+
}
95+
96+
func mergeFilteredHints(numaNodes []int, filteredHints [][]TopologyHint) TopologyHint {
97+
// Set the default affinity as an any-numa affinity containing the list
98+
// of NUMA Nodes available on this machine.
99+
defaultAffinity, _ := bitmask.NewBitMask(numaNodes...)
100+
101+
// Set the bestHint to return from this function as {nil false}.
102+
// This will only be returned if no better hint can be found when
103+
// merging hints from each hint provider.
104+
bestHint := TopologyHint{defaultAffinity, false}
105+
iterateAllProviderTopologyHints(filteredHints, func(permutation []TopologyHint) {
106+
// Get the NUMANodeAffinity from each hint in the permutation and see if any
107+
// of them encode unpreferred allocations.
108+
mergedHint := mergePermutation(numaNodes, permutation)
109+
// Only consider mergedHints that result in a NUMANodeAffinity > 0 to
110+
// replace the current bestHint.
111+
if mergedHint.NUMANodeAffinity.Count() == 0 {
112+
return
113+
}
114+
115+
// If the current bestHint is non-preferred and the new mergedHint is
116+
// preferred, always choose the preferred hint over the non-preferred one.
117+
if mergedHint.Preferred && !bestHint.Preferred {
118+
bestHint = mergedHint
119+
return
120+
}
121+
122+
// If the current bestHint is preferred and the new mergedHint is
123+
// non-preferred, never update bestHint, regardless of mergedHint's
124+
// narowness.
125+
if !mergedHint.Preferred && bestHint.Preferred {
126+
return
127+
}
128+
129+
// If mergedHint and bestHint has the same preference, only consider
130+
// mergedHints that have a narrower NUMANodeAffinity than the
131+
// NUMANodeAffinity in the current bestHint.
132+
if !mergedHint.NUMANodeAffinity.IsNarrowerThan(bestHint.NUMANodeAffinity) {
133+
return
134+
}
135+
136+
// In all other cases, update bestHint to the current mergedHint
137+
bestHint = mergedHint
138+
})
139+
140+
return bestHint
141+
}
142+
62143
// Iterate over all permutations of hints in 'allProviderHints [][]TopologyHint'.
63144
//
64145
// This procedure is implemented as a recursive function over the set of hints

pkg/kubelet/cm/topologymanager/policy_best_effort.go

Lines changed: 4 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ limitations under the License.
1717
package topologymanager
1818

1919
import (
20-
"k8s.io/klog"
21-
"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
2220
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
2321
)
2422

@@ -48,88 +46,8 @@ func (p *bestEffortPolicy) canAdmitPodResult(hint *TopologyHint) lifecycle.PodAd
4846
}
4947

5048
func (p *bestEffortPolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, lifecycle.PodAdmitResult) {
51-
hint := p.mergeProvidersHints(providersHints)
52-
admit := p.canAdmitPodResult(&hint)
53-
return hint, admit
54-
}
55-
56-
// Merge the hints from all hint providers to find the best one.
57-
func (p *bestEffortPolicy) mergeProvidersHints(providersHints []map[string][]TopologyHint) TopologyHint {
58-
// Set the default affinity as an any-numa affinity containing the list
59-
// of NUMA Nodes available on this machine.
60-
defaultAffinity, _ := bitmask.NewBitMask(p.numaNodes...)
61-
62-
// Loop through all hint providers and save an accumulated list of the
63-
// hints returned by each hint provider. If no hints are provided, assume
64-
// that provider has no preference for topology-aware allocation.
65-
var allProviderHints [][]TopologyHint
66-
for _, hints := range providersHints {
67-
// If hints is nil, insert a single, preferred any-numa hint into allProviderHints.
68-
if len(hints) == 0 {
69-
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with any resource")
70-
allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
71-
continue
72-
}
73-
74-
// Otherwise, accumulate the hints for each resource type into allProviderHints.
75-
for resource := range hints {
76-
if hints[resource] == nil {
77-
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with resource '%s'", resource)
78-
allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
79-
continue
80-
}
81-
82-
if len(hints[resource]) == 0 {
83-
klog.Infof("[topologymanager] Hint Provider has no possible NUMA affinities for resource '%s'", resource)
84-
allProviderHints = append(allProviderHints, []TopologyHint{{nil, false}})
85-
continue
86-
}
87-
88-
allProviderHints = append(allProviderHints, hints[resource])
89-
}
90-
}
91-
92-
// Iterate over all permutations of hints in 'allProviderHints'. Merge the
93-
// hints in each permutation by taking the bitwise-and of their affinity masks.
94-
// Return the hint with the narrowest NUMANodeAffinity of all merged
95-
// permutations that have at least one NUMA ID set. If no merged mask can be
96-
// found that has at least one NUMA ID set, return the 'defaultAffinity'.
97-
bestHint := TopologyHint{defaultAffinity, false}
98-
iterateAllProviderTopologyHints(allProviderHints, func(permutation []TopologyHint) {
99-
// Get the NUMANodeAffinity from each hint in the permutation and see if any
100-
// of them encode unpreferred allocations.
101-
mergedHint := mergePermutation(p.numaNodes, permutation)
102-
103-
// Only consider mergedHints that result in a NUMANodeAffinity > 0 to
104-
// replace the current bestHint.
105-
if mergedHint.NUMANodeAffinity.Count() == 0 {
106-
return
107-
}
108-
109-
// If the current bestHint is non-preferred and the new mergedHint is
110-
// preferred, always choose the preferred hint over the non-preferred one.
111-
if mergedHint.Preferred && !bestHint.Preferred {
112-
bestHint = mergedHint
113-
return
114-
}
115-
116-
// If the current bestHint is preferred and the new mergedHint is
117-
// non-preferred, never update bestHint, regardless of mergedHint's
118-
// narowness.
119-
if !mergedHint.Preferred && bestHint.Preferred {
120-
return
121-
}
122-
123-
// If mergedHint and bestHint has the same preference, only consider
124-
// mergedHints that have a narrower NUMANodeAffinity than the
125-
// NUMANodeAffinity in the current bestHint.
126-
if !mergedHint.NUMANodeAffinity.IsNarrowerThan(bestHint.NUMANodeAffinity) {
127-
return
128-
}
129-
130-
// In all other cases, update bestHint to the current mergedHint
131-
bestHint = mergedHint
132-
})
133-
134-
return bestHint
49+
filteredProvidersHints := filterProvidersHints(providersHints)
50+
bestHint := mergeFilteredHints(p.numaNodes, filteredProvidersHints)
51+
admit := p.canAdmitPodResult(&bestHint)
52+
return bestHint, admit
13553
}

pkg/kubelet/cm/topologymanager/policy_restricted.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ func (p *restrictedPolicy) canAdmitPodResult(hint *TopologyHint) lifecycle.PodAd
5252
}
5353

5454
func (p *restrictedPolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, lifecycle.PodAdmitResult) {
55-
hint := p.mergeProvidersHints(providersHints)
55+
filteredHints := filterProvidersHints(providersHints)
56+
hint := mergeFilteredHints(p.numaNodes, filteredHints)
5657
admit := p.canAdmitPodResult(&hint)
5758
return hint, admit
5859
}

pkg/kubelet/cm/topologymanager/policy_single_numa_node.go

Lines changed: 8 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717
package topologymanager
1818

1919
import (
20-
"k8s.io/klog"
2120
"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
2221
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
2322
)
@@ -55,7 +54,7 @@ func (p *singleNumaNodePolicy) canAdmitPodResult(hint *TopologyHint) lifecycle.P
5554
}
5655

5756
// Return hints that have valid bitmasks with exactly one bit set.
58-
func (p *singleNumaNodePolicy) filterHints(allResourcesHints [][]TopologyHint) [][]TopologyHint {
57+
func filterSingleNumaHints(allResourcesHints [][]TopologyHint) [][]TopologyHint {
5958
var filteredResourcesHints [][]TopologyHint
6059
for _, oneResourceHints := range allResourcesHints {
6160
var filtered []TopologyHint
@@ -72,93 +71,17 @@ func (p *singleNumaNodePolicy) filterHints(allResourcesHints [][]TopologyHint) [
7271
return filteredResourcesHints
7372
}
7473

75-
func (p *singleNumaNodePolicy) mergeProvidersHints(providersHints []map[string][]TopologyHint) TopologyHint {
76-
// Set the default affinity as an any-numa affinity containing the list
77-
// of NUMA Nodes available on this machine.
78-
defaultAffinity, _ := bitmask.NewBitMask(p.numaNodes...)
79-
80-
// Loop through all provider hints and save an accumulated list of the
81-
// hints returned by each hint provider. If no hints are provided, assume
82-
// that provider has no preference for topology-aware allocation.
83-
var allProviderHints [][]TopologyHint
84-
for _, hints := range providersHints {
85-
// If hints is nil, insert a single, preferred any-numa hint into allProviderHints.
86-
if len(hints) == 0 {
87-
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with any resource")
88-
allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
89-
continue
90-
}
91-
92-
// Otherwise, accumulate the hints for each resource type into allProviderHints.
93-
for resource := range hints {
94-
if hints[resource] == nil {
95-
klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with resource '%s'", resource)
96-
allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
97-
continue
98-
}
99-
100-
if len(hints[resource]) == 0 {
101-
klog.Infof("[topologymanager] Hint Provider has no possible NUMA affinities for resource '%s'", resource)
102-
allProviderHints = append(allProviderHints, []TopologyHint{{nil, false}})
103-
continue
104-
}
105-
106-
allProviderHints = append(allProviderHints, hints[resource])
107-
}
108-
}
109-
74+
func (p *singleNumaNodePolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, lifecycle.PodAdmitResult) {
75+
filteredHints := filterProvidersHints(providersHints)
11076
// Filter to only include don't cares and hints with a single NUMA node.
111-
allProviderHints = p.filterHints(allProviderHints)
112-
113-
// Set the bestHint to return from this function as {nil false}.
114-
// This will only be returned if no better hint can be found when
115-
// merging hints from each hint provider.
116-
bestHint := TopologyHint{defaultAffinity, false}
117-
iterateAllProviderTopologyHints(allProviderHints, func(permutation []TopologyHint) {
118-
// Get the NUMANodeAffinity from each hint in the permutation and see if any
119-
// of them encode unpreferred allocations.
120-
mergedHint := mergePermutation(p.numaNodes, permutation)
121-
122-
// Only consider mergedHints that result in a NUMANodeAffinity > 0 to
123-
// replace the current bestHint.
124-
if mergedHint.NUMANodeAffinity.Count() == 0 {
125-
return
126-
}
127-
128-
// If the current bestHint is non-preferred and the new mergedHint is
129-
// preferred, always choose the preferred hint over the non-preferred one.
130-
if mergedHint.Preferred && !bestHint.Preferred {
131-
bestHint = mergedHint
132-
return
133-
}
134-
135-
// If the current bestHint is preferred and the new mergedHint is
136-
// non-preferred, never update bestHint, regardless of mergedHint's
137-
// narowness.
138-
if !mergedHint.Preferred && bestHint.Preferred {
139-
return
140-
}
141-
142-
// If mergedHint and bestHint has the same preference, only consider
143-
// mergedHints that have a narrower NUMANodeAffinity than the
144-
// NUMANodeAffinity in the current bestHint.
145-
if !mergedHint.NUMANodeAffinity.IsNarrowerThan(bestHint.NUMANodeAffinity) {
146-
return
147-
}
148-
149-
// In all other cases, update bestHint to the current mergedHint
150-
bestHint = mergedHint
151-
})
77+
singleNumaHints := filterSingleNumaHints(filteredHints)
78+
bestHint := mergeFilteredHints(p.numaNodes, singleNumaHints)
15279

80+
defaultAffinity, _ := bitmask.NewBitMask(p.numaNodes...)
15381
if bestHint.NUMANodeAffinity.IsEqual(defaultAffinity) {
15482
bestHint = TopologyHint{nil, bestHint.Preferred}
15583
}
15684

157-
return bestHint
158-
}
159-
160-
func (p *singleNumaNodePolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, lifecycle.PodAdmitResult) {
161-
hint := p.mergeProvidersHints(providersHints)
162-
admit := p.canAdmitPodResult(&hint)
163-
return hint, admit
85+
admit := p.canAdmitPodResult(&bestHint)
86+
return bestHint, admit
16487
}

pkg/kubelet/cm/topologymanager/policy_single_numa_node_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,8 @@ func TestPolicySingleNumaNodeFilterHints(t *testing.T) {
155155
},
156156
}
157157

158-
numaNodes := []int{0, 1, 2, 3}
159158
for _, tc := range tcases {
160-
policy := NewSingleNumaNodePolicy(numaNodes)
161-
actual := policy.(*singleNumaNodePolicy).filterHints(tc.allResources)
159+
actual := filterSingleNumaHints(tc.allResources)
162160
if !reflect.DeepEqual(tc.expectedResources, actual) {
163161
t.Errorf("Test Case: %s", tc.name)
164162
t.Errorf("Expected result to be %v, got %v", tc.expectedResources, actual)

0 commit comments

Comments
 (0)