-
Notifications
You must be signed in to change notification settings - Fork 90
/
policy_hint_handlers.go
157 lines (130 loc) · 5.74 KB
/
policy_hint_handlers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
Copyright 2022 The Katalyst Authors.
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package nativepolicy
import (
"context"
"fmt"
v1 "k8s.io/api/core/v1"
pluginapi "k8s.io/kubelet/pkg/apis/resourceplugin/v1alpha1"
"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
nativepolicyutil "github.com/kubewharf/katalyst-core/pkg/agent/qrm-plugins/cpu/nativepolicy/util"
cpuutil "github.com/kubewharf/katalyst-core/pkg/agent/qrm-plugins/cpu/util"
"github.com/kubewharf/katalyst-core/pkg/agent/qrm-plugins/util"
"github.com/kubewharf/katalyst-core/pkg/util/general"
"github.com/kubewharf/katalyst-core/pkg/util/machine"
)
func (p *NativePolicy) dedicatedCoresHintHandler(ctx context.Context,
req *pluginapi.ResourceRequest,
) (*pluginapi.ResourceHintsResponse, error) {
if req == nil {
return nil, fmt.Errorf("HintHandler got nil req")
}
reqInt, _, err := util.GetQuantityFromResourceReq(req)
if err != nil {
return nil, fmt.Errorf("getReqQuantityFromResourceReq failed with error: %v", err)
}
machineState := p.state.GetMachineState()
var hints map[string]*pluginapi.ListOfTopologyHints
allocationInfo := p.state.GetAllocationInfo(req.PodUid, req.ContainerName)
if allocationInfo != nil {
hints = cpuutil.RegenerateHints(allocationInfo, reqInt)
// regenerateHints failed. need to clear container record and re-calculate.
if hints == nil {
podEntries := p.state.GetPodEntries()
delete(podEntries[req.PodUid], req.ContainerName)
if len(podEntries[req.PodUid]) == 0 {
delete(podEntries, req.PodUid)
}
var err error
machineState, err = nativepolicyutil.GenerateMachineStateFromPodEntries(p.machineInfo.CPUTopology, podEntries)
if err != nil {
general.Errorf("pod: %s/%s, container: %s GenerateMachineStateFromPodEntries failed with error: %v",
req.PodNamespace, req.PodName, req.ContainerName, err)
return nil, fmt.Errorf("GenerateMachineStateFromPodEntries failed with error: %v", err)
}
}
}
// otherwise, calculate hint for container without allocated memory
if hints == nil {
// Get a list of available CPUs.
available := machineState.GetAvailableCPUSet(p.reservedCPUs)
// Get a list of reusable CPUs (e.g. CPUs reused from initContainers).
// It should be an empty CPUSet for a newly created pod.
reusable := p.cpusToReuse[req.PodUid]
// calculate hint for container without allocated cpus
hints = p.generateCPUTopologyHints(available, reusable, reqInt)
}
general.InfoS("TopologyHints generated", "pod", fmt.Sprintf("%s/%s", req.PodNamespace, req.PodName), "containerName", req.ContainerName, "cpuHints", hints)
return util.PackResourceHintsResponse(req, string(v1.ResourceCPU), hints)
}
func (p *NativePolicy) sharedPoolHintHandler(_ context.Context,
req *pluginapi.ResourceRequest,
) (*pluginapi.ResourceHintsResponse, error) {
return util.PackResourceHintsResponse(req, string(v1.ResourceCPU),
map[string]*pluginapi.ListOfTopologyHints{
string(v1.ResourceCPU): nil, // indicates that there is no numa preference
})
}
// generateCPUtopologyHints generates a set of TopologyHints given the set of
// available CPUs and the number of CPUs being requested.
//
// It follows the convention of marking all hints that have the same number of
// bits set as the narrowest matching NUMANodeAffinity with 'Preferred: true', and
// marking all others with 'Preferred: false'.
func (p *NativePolicy) generateCPUTopologyHints(availableCPUs machine.CPUSet, reusableCPUs machine.CPUSet, request int) map[string]*pluginapi.ListOfTopologyHints {
// Initialize minAffinitySize to include all NUMA Nodes.
minAffinitySize := p.machineInfo.CPUDetails.NUMANodes().Size()
hints := map[string]*pluginapi.ListOfTopologyHints{
string(v1.ResourceCPU): {
Hints: []*pluginapi.TopologyHint{},
},
}
// Iterate through all combinations of numa nodes bitmask and build hints from them.
bitmask.IterateBitMasks(p.machineInfo.CPUDetails.NUMANodes().ToSliceInt(), func(mask bitmask.BitMask) {
// First, update minAffinitySize for the current request size.
cpusInMask := p.machineInfo.CPUDetails.CPUsInNUMANodes(mask.GetBits()...).Size()
if cpusInMask >= request && mask.Count() < minAffinitySize {
minAffinitySize = mask.Count()
}
// Then check to see if we have enough CPUs available on the current
// numa node bitmask to satisfy the CPU request.
numMatching := 0
for _, c := range reusableCPUs.ToSliceInt() {
// Disregard this mask if its NUMANode isn't part of it.
if !mask.IsSet(p.machineInfo.CPUDetails[c].NUMANodeID) {
return
}
numMatching++
}
// Finally, check to see if enough available CPUs remain on the current
// NUMA node combination to satisfy the CPU request.
for _, c := range availableCPUs.ToSliceInt() {
if mask.IsSet(p.machineInfo.CPUDetails[c].NUMANodeID) {
numMatching++
}
}
// If they don't, then move onto the next combination.
if numMatching < request {
return
}
// Otherwise, create a new hint from the numa node bitmask and add it to the
// list of hints. We set all hint preferences to 'false' on the first
// pass through.
hints[string(v1.ResourceCPU)].Hints = append(hints[string(v1.ResourceCPU)].Hints, &pluginapi.TopologyHint{
Nodes: machine.MaskToUInt64Array(mask),
Preferred: mask.Count() == minAffinitySize,
})
})
return hints
}