volcano.sh/volcano@v1.9.0/pkg/scheduler/plugins/numaaware/provider/cpumanager/cpu_mng_test.go (about) 1 /* 2 Copyright 2021 The Volcano Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cpumanager 18 19 import ( 20 "reflect" 21 "testing" 22 23 v1 "k8s.io/api/core/v1" 24 "k8s.io/apimachinery/pkg/api/resource" 25 "k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology" 26 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask" 27 "k8s.io/utils/cpuset" 28 29 "volcano.sh/volcano/pkg/scheduler/api" 30 "volcano.sh/volcano/pkg/scheduler/plugins/numaaware/policy" 31 ) 32 33 var numaInfo = api.NumatopoInfo{ 34 CPUDetail: topology.CPUDetails{ 35 0: {NUMANodeID: 0, CoreID: 0, SocketID: 0}, 36 1: {NUMANodeID: 0, CoreID: 0, SocketID: 0}, 37 2: {NUMANodeID: 0, CoreID: 1, SocketID: 0}, 38 3: {NUMANodeID: 0, CoreID: 1, SocketID: 0}, 39 4: {NUMANodeID: 1, CoreID: 2, SocketID: 1}, 40 5: {NUMANodeID: 1, CoreID: 2, SocketID: 1}, 41 6: {NUMANodeID: 1, CoreID: 3, SocketID: 1}, 42 7: {NUMANodeID: 1, CoreID: 3, SocketID: 1}, 43 }, 44 } 45 46 func Test_GetTopologyHints(t *testing.T) { 47 teseCases := []struct { 48 name string 49 container v1.Container 50 resNumaSets api.ResNumaSets 51 expect []policy.TopologyHint 52 }{ 53 { 54 name: "test-1", 55 container: v1.Container{ 56 Resources: v1.ResourceRequirements{ 57 Requests: v1.ResourceList{ 58 "cpu": *resource.NewQuantity(4, ""), 59 }, 60 }, 61 }, 62 resNumaSets: api.ResNumaSets{ 63 "cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7), 64 }, 65 expect: []policy.TopologyHint{ 66 { 67 NUMANodeAffinity: func() bitmask.BitMask { 68 mask, _ := bitmask.NewBitMask(0) 69 return mask 70 }(), 71 Preferred: true, 72 }, 73 { 74 NUMANodeAffinity: func() bitmask.BitMask { 75 mask, _ := bitmask.NewBitMask(1) 76 return mask 77 }(), 78 Preferred: true, 79 }, 80 { 81 NUMANodeAffinity: func() bitmask.BitMask { 82 mask, _ := bitmask.NewBitMask(0, 1) 83 return mask 84 }(), 85 Preferred: false, 86 }, 87 }, 88 }, 89 { 90 name: "test-2", 91 container: v1.Container{ 92 Resources: v1.ResourceRequirements{ 93 Requests: v1.ResourceList{ 94 "cpu": *resource.NewQuantity(4, ""), 95 }, 96 }, 97 }, 98 resNumaSets: api.ResNumaSets{ 99 "cpu": cpuset.New(1, 2, 3, 4, 5, 6, 7), 100 }, 101 expect: []policy.TopologyHint{ 102 { 103 NUMANodeAffinity: func() bitmask.BitMask { 104 mask, _ := bitmask.NewBitMask(1) 105 return mask 106 }(), 107 Preferred: true, 108 }, 109 { 110 NUMANodeAffinity: func() bitmask.BitMask { 111 mask, _ := bitmask.NewBitMask(0, 1) 112 return mask 113 }(), 114 Preferred: false, 115 }, 116 }, 117 }, 118 { 119 name: "test-3", 120 container: v1.Container{ 121 Resources: v1.ResourceRequirements{ 122 Requests: v1.ResourceList{ 123 "cpu": *resource.NewQuantity(5, ""), 124 }, 125 }, 126 }, 127 resNumaSets: api.ResNumaSets{ 128 "cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7), 129 }, 130 expect: []policy.TopologyHint{ 131 { 132 NUMANodeAffinity: func() bitmask.BitMask { 133 mask, _ := bitmask.NewBitMask(0, 1) 134 return mask 135 }(), 136 Preferred: true, 137 }, 138 }, 139 }, 140 { 141 name: "test-4", 142 container: v1.Container{ 143 Resources: v1.ResourceRequirements{ 144 Requests: v1.ResourceList{ 145 "cpu": *resource.NewQuantity(8, ""), 146 }, 147 }, 148 }, 149 resNumaSets: api.ResNumaSets{ 150 "cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7), 151 }, 152 expect: []policy.TopologyHint{ 153 { 154 NUMANodeAffinity: func() bitmask.BitMask { 155 mask, _ := bitmask.NewBitMask(0, 1) 156 return mask 157 }(), 158 Preferred: true, 159 }, 160 }, 161 }, 162 { 163 name: "test-5", 164 container: v1.Container{ 165 Resources: v1.ResourceRequirements{ 166 Requests: v1.ResourceList{ 167 "cpu": *resource.NewQuantity(9, ""), 168 }, 169 }, 170 }, 171 resNumaSets: api.ResNumaSets{ 172 "cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7), 173 }, 174 expect: []policy.TopologyHint{}, 175 }, 176 { 177 name: "test-6", 178 container: v1.Container{ 179 Resources: v1.ResourceRequirements{ 180 Requests: v1.ResourceList{ 181 "cpu": *resource.NewQuantity(4, ""), 182 }, 183 }, 184 }, 185 resNumaSets: api.ResNumaSets{ 186 "cpu": cpuset.New(2, 3, 4, 5), 187 }, 188 expect: []policy.TopologyHint{ 189 { 190 NUMANodeAffinity: func() bitmask.BitMask { 191 mask, _ := bitmask.NewBitMask(0, 1) 192 return mask 193 }(), 194 Preferred: false, 195 }, 196 }, 197 }, 198 } 199 200 for _, testcase := range teseCases { 201 provider := NewProvider() 202 topologyHintmap := provider.GetTopologyHints(&testcase.container, &numaInfo, testcase.resNumaSets) 203 if !(reflect.DeepEqual(topologyHintmap["cpu"], testcase.expect) || 204 (len(topologyHintmap["cpu"]) == 0 && len(testcase.expect) == 0)) { 205 t.Errorf("%s failed. topologyHintmap = %v\n", testcase.name, topologyHintmap) 206 } 207 } 208 } 209 210 func Test_Allocate(t *testing.T) { 211 teseCases := []struct { 212 name string 213 container v1.Container 214 resNumaSets api.ResNumaSets 215 bestHit *policy.TopologyHint 216 expect cpuset.CPUSet 217 }{ 218 { 219 name: "test-1", 220 container: v1.Container{ 221 Resources: v1.ResourceRequirements{ 222 Requests: v1.ResourceList{ 223 "cpu": *resource.NewQuantity(4, ""), 224 }, 225 }, 226 }, 227 resNumaSets: api.ResNumaSets{ 228 "cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7), 229 }, 230 bestHit: &policy.TopologyHint{ 231 NUMANodeAffinity: func() bitmask.BitMask { 232 mask, _ := bitmask.NewBitMask(0) 233 return mask 234 }(), 235 Preferred: true, 236 }, 237 expect: cpuset.New(0, 1, 2, 3), 238 }, 239 { 240 name: "test-2", 241 container: v1.Container{ 242 Resources: v1.ResourceRequirements{ 243 Requests: v1.ResourceList{ 244 "cpu": *resource.NewQuantity(4, ""), 245 }, 246 }, 247 }, 248 resNumaSets: api.ResNumaSets{ 249 "cpu": cpuset.New(1, 2, 3, 4, 5, 6, 7), 250 }, 251 bestHit: &policy.TopologyHint{ 252 NUMANodeAffinity: func() bitmask.BitMask { 253 mask, _ := bitmask.NewBitMask(1) 254 return mask 255 }(), 256 Preferred: true, 257 }, 258 expect: cpuset.New(4, 5, 6, 7), 259 }, 260 { 261 name: "test-3", 262 container: v1.Container{ 263 Resources: v1.ResourceRequirements{ 264 Requests: v1.ResourceList{ 265 "cpu": *resource.NewQuantity(5, ""), 266 }, 267 }, 268 }, 269 resNumaSets: api.ResNumaSets{ 270 "cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7), 271 }, 272 bestHit: &policy.TopologyHint{ 273 NUMANodeAffinity: func() bitmask.BitMask { 274 mask, _ := bitmask.NewBitMask(0, 1) 275 return mask 276 }(), 277 Preferred: true, 278 }, 279 expect: cpuset.New(0, 1, 2, 3, 4), 280 }, 281 { 282 name: "test-4", 283 container: v1.Container{ 284 Resources: v1.ResourceRequirements{ 285 Requests: v1.ResourceList{ 286 "cpu": *resource.NewQuantity(5, ""), 287 }, 288 }, 289 }, 290 resNumaSets: api.ResNumaSets{ 291 "cpu": cpuset.New(1, 2, 3, 4, 5, 6, 7), 292 }, 293 bestHit: &policy.TopologyHint{ 294 NUMANodeAffinity: func() bitmask.BitMask { 295 mask, _ := bitmask.NewBitMask(0, 1) 296 return mask 297 }(), 298 Preferred: true, 299 }, 300 expect: cpuset.New(1, 4, 5, 6, 7), 301 }, 302 { 303 name: "test-5", 304 container: v1.Container{ 305 Resources: v1.ResourceRequirements{ 306 Requests: v1.ResourceList{ 307 "cpu": *resource.NewQuantity(8, ""), 308 }, 309 }, 310 }, 311 resNumaSets: api.ResNumaSets{ 312 "cpu": cpuset.New(1, 2, 3, 4, 5, 6, 7), 313 }, 314 bestHit: &policy.TopologyHint{ 315 NUMANodeAffinity: func() bitmask.BitMask { 316 mask, _ := bitmask.NewBitMask(0, 1) 317 return mask 318 }(), 319 Preferred: true, 320 }, 321 expect: cpuset.New(), 322 }, 323 } 324 325 for _, testcase := range teseCases { 326 provider := NewProvider() 327 assignMap := provider.Allocate(&testcase.container, testcase.bestHit, &numaInfo, testcase.resNumaSets) 328 if !(reflect.DeepEqual(assignMap["cpu"], testcase.expect)) { 329 t.Errorf("%s failed.\n", testcase.name) 330 } 331 } 332 }