@@ -52,24 +52,24 @@ func singleNUMAContainerLevelHandler(lh logr.Logger, pod *v1.Pod, info *filterIn
52
52
clh := lh .WithValues (logging .KeyContainer , initContainer .Name , logging .KeyContainerKind , cntKind )
53
53
clh .V (6 ).Info ("desired resources" , stringify .ResourceListToLoggable (initContainer .Resources .Requests )... )
54
54
55
- _ , match := resourcesAvailableInAnyNUMANodes (clh , info , initContainer .Resources .Requests )
55
+ _ , match , reason := resourcesAvailableInAnyNUMANodes (clh , info , initContainer .Resources .Requests )
56
56
if ! match {
57
57
msg := "cannot align " + cntKind + " container"
58
58
// we can't align init container, so definitely we can't align a pod
59
- clh .V (2 ).Info (msg )
60
- return framework .NewStatus (framework .Unschedulable , msg )
59
+ clh .V (2 ).Info (msg , "reason" , reason )
60
+ return framework .NewStatus (framework .Unschedulable , msg + ": " + reason )
61
61
}
62
62
}
63
63
64
64
for _ , container := range pod .Spec .Containers {
65
65
clh := lh .WithValues (logging .KeyContainer , container .Name , logging .KeyContainerKind , logging .KindContainerApp )
66
66
clh .V (6 ).Info ("container requests" , stringify .ResourceListToLoggable (container .Resources .Requests )... )
67
67
68
- numaID , match := resourcesAvailableInAnyNUMANodes (clh , info , container .Resources .Requests )
68
+ numaID , match , reason := resourcesAvailableInAnyNUMANodes (clh , info , container .Resources .Requests )
69
69
if ! match {
70
70
// we can't align container, so definitely we can't align a pod
71
- clh .V (2 ).Info ("cannot align container" )
72
- return framework .NewStatus (framework .Unschedulable , "cannot align container" )
71
+ clh .V (2 ).Info ("cannot align container" , "reason" , reason )
72
+ return framework .NewStatus (framework .Unschedulable , "cannot align container: " + reason )
73
73
}
74
74
75
75
// subtract the resources requested by the container from the given NUMA.
@@ -86,7 +86,7 @@ func singleNUMAContainerLevelHandler(lh logr.Logger, pod *v1.Pod, info *filterIn
86
86
87
87
// resourcesAvailableInAnyNUMANodes checks for sufficient resource and return the NUMAID that would be selected by Kubelet.
88
88
// this function requires NUMANodeList with properly populated NUMANode, NUMAID should be in range 0-63
89
- func resourcesAvailableInAnyNUMANodes (lh logr.Logger , info * filterInfo , resources v1.ResourceList ) (int , bool ) {
89
+ func resourcesAvailableInAnyNUMANodes (lh logr.Logger , info * filterInfo , resources v1.ResourceList ) (int , bool , string ) {
90
90
numaID := highestNUMAID
91
91
bitmask := bm .NewEmptyBitMask ()
92
92
// set all bits, each bit is a NUMA node, if resources couldn't be aligned
@@ -96,50 +96,54 @@ func resourcesAvailableInAnyNUMANodes(lh logr.Logger, info *filterInfo, resource
96
96
nodeResources := util .ResourceList (info .node .Allocatable )
97
97
98
98
for resource , quantity := range resources {
99
+ clh := lh .WithValues ("resource" , resource )
99
100
if quantity .IsZero () {
100
101
// why bother? everything's fine from the perspective of this resource
101
- lh .V (4 ).Info ("ignoring zero-qty resource request" , "resource" , resource )
102
+ clh .V (4 ).Info ("ignoring zero-qty resource request" )
102
103
continue
103
104
}
104
105
105
106
if _ , ok := nodeResources [resource ]; ! ok {
106
107
// some resources may not expose NUMA affinity (device plugins, extended resources), but all resources
107
108
// must be reported at node level; thus, if they are not present at node level, we can safely assume
108
109
// we don't have the resource at all.
109
- lh .V (2 ).Info ("early verdict: cannot meet request" , "resource" , resource , "suitable" , "false " )
110
- return numaID , false
110
+ clh .V (2 ).Info ("early verdict: cannot meet request" )
111
+ return - 1 , false , string ( resource )
111
112
}
112
113
113
114
// for each requested resource, calculate which NUMA slots are good fits, and then AND with the aggregated bitmask, IOW unset appropriate bit if we can't align resources, or set it
114
115
// obvious, bits which are not in the NUMA id's range would be unset
115
116
hasNUMAAffinity := false
116
117
resourceBitmask := bm .NewEmptyBitMask ()
117
118
for _ , numaNode := range info .numaNodes {
119
+ nlh := clh .WithValues ("numaCell" , numaNode .NUMAID )
118
120
numaQuantity , ok := numaNode .Resources [resource ]
119
121
if ! ok {
122
+ nlh .V (6 ).Info ("missing" )
120
123
continue
121
124
}
122
125
123
126
hasNUMAAffinity = true
124
127
if ! isResourceSetSuitable (info .qos , resource , quantity , numaQuantity ) {
128
+ nlh .V (6 ).Info ("discarded" , "quantity" , quantity .String (), "numaQuantity" , numaQuantity .String ())
125
129
continue
126
130
}
127
131
128
132
resourceBitmask .Add (numaNode .NUMAID )
129
- lh .V (6 ).Info ("feasible" , "numaCell" , numaNode . NUMAID , "resource" , resource )
133
+ nlh .V (6 ).Info ("feasible" )
130
134
}
131
135
132
136
// non-native resources or ephemeral-storage may not expose NUMA affinity,
133
137
// but since they are available at node level, this is fine
134
138
if ! hasNUMAAffinity && isHostLevelResource (resource ) {
135
- lh .V (6 ).Info ("resource available at host level (no NUMA affinity)" , "resource" , resource )
139
+ clh .V (6 ).Info ("resource available at host level (no NUMA affinity)" )
136
140
continue
137
141
}
138
142
139
143
bitmask .And (resourceBitmask )
140
144
if bitmask .IsEmpty () {
141
- lh .V (2 ).Info ("early verdict" , "resource" , resource , "suitable" , "false " )
142
- return numaID , false
145
+ lh .V (2 ).Info ("early verdict: cannot find affinity " )
146
+ return numaID , false , string ( resource )
143
147
}
144
148
}
145
149
// according to TopologyManager, the preferred NUMA affinity, is the narrowest one.
@@ -151,7 +155,7 @@ func resourcesAvailableInAnyNUMANodes(lh logr.Logger, info *filterInfo, resource
151
155
// at least one NUMA node is available
152
156
ret := ! bitmask .IsEmpty ()
153
157
lh .V (2 ).Info ("final verdict" , "suitable" , ret , "numaCell" , numaID )
154
- return numaID , ret
158
+ return numaID , ret , "generic"
155
159
}
156
160
157
161
func singleNUMAPodLevelHandler (lh logr.Logger , pod * v1.Pod , info * filterInfo ) * framework.Status {
@@ -160,10 +164,10 @@ func singleNUMAPodLevelHandler(lh logr.Logger, pod *v1.Pod, info *filterInfo) *f
160
164
resources := util .GetPodEffectiveRequest (pod )
161
165
lh .V (6 ).Info ("pod desired resources" , stringify .ResourceListToLoggable (resources )... )
162
166
163
- numaID , match := resourcesAvailableInAnyNUMANodes (lh , info , resources )
167
+ numaID , match , reason := resourcesAvailableInAnyNUMANodes (lh , info , resources )
164
168
if ! match {
165
- lh .V (2 ).Info ("cannot align pod" , "name" , pod .Name )
166
- return framework .NewStatus (framework .Unschedulable , "cannot align pod" )
169
+ lh .V (2 ).Info ("cannot align pod" , "name" , pod .Name , "reason" , reason )
170
+ return framework .NewStatus (framework .Unschedulable , "cannot align pod: " + reason )
167
171
}
168
172
lh .V (4 ).Info ("all container placed" , "numaCell" , numaID )
169
173
return nil
0 commit comments