github.com/projecteru2/core@v0.0.0-20240321043226-06bcc1c23f58/resource/plugins/cpumem/node_test.go (about) 1 package cpumem 2 3 import ( 4 "context" 5 "fmt" 6 "math" 7 "testing" 8 9 "github.com/cockroachdb/errors" 10 "github.com/docker/go-units" 11 enginetypes "github.com/projecteru2/core/engine/types" 12 "github.com/projecteru2/core/resource/plugins/cpumem/types" 13 plugintypes "github.com/projecteru2/core/resource/plugins/types" 14 coretypes "github.com/projecteru2/core/types" 15 "github.com/stretchr/testify/assert" 16 ) 17 18 func TestAddNode(t *testing.T) { 19 ctx := context.Background() 20 cm := initCPUMEM(ctx, t) 21 nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0) 22 node := nodes[0] 23 nodeForAdd := "test2" 24 25 req := plugintypes.NodeResourceRequest{ 26 "numa-cpu": []string{"0", "1"}, 27 } 28 29 info := &enginetypes.Info{NCPU: 2, MemTotal: 4 * units.GB} 30 31 // existent node 32 _, err := cm.AddNode(ctx, node, req, info) 33 assert.Equal(t, err, coretypes.ErrNodeExists) 34 35 // normal case 36 r, err := cm.AddNode(ctx, nodeForAdd, req, info) 37 assert.Nil(t, err) 38 assert.Equal(t, r.Capacity["memory"], int64(4*units.GB*rate/10)) 39 } 40 41 func TestRemoveNode(t *testing.T) { 42 ctx := context.Background() 43 cm := initCPUMEM(ctx, t) 44 nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0) 45 node := nodes[0] 46 nodeForDel := "test2" 47 48 _, err := cm.RemoveNode(ctx, node) 49 assert.Nil(t, err) 50 _, err = cm.RemoveNode(ctx, nodeForDel) 51 assert.Nil(t, err) 52 } 53 54 func TestGetNodesDeployCapacityWithCPUBind(t *testing.T) { 55 ctx := context.Background() 56 cm := initCPUMEM(ctx, t) 57 nodes := generateNodes(ctx, t, cm, 2, 2, 4*units.GB, 100, 0) 58 59 req := plugintypes.WorkloadResourceRequest{ 60 "cpu-bind": true, 61 "cpu-request": 0.5, 62 "memory-request": "1", 63 } 64 65 // non-existent node 66 _, err := cm.GetNodesDeployCapacity(ctx, []string{"xxx"}, req) 67 assert.True(t, errors.Is(err, coretypes.ErrInvaildCount)) 68 69 // normal 70 r, err := cm.GetNodesDeployCapacity(ctx, nodes, req) 71 assert.Nil(t, err) 72 assert.True(t, r.Total >= 1) 73 74 // more cpu 75 req = plugintypes.WorkloadResourceRequest{ 76 "cpu-bind": true, 77 "cpu-request": 2, 78 "memory-request": "1", 79 } 80 r, err = cm.GetNodesDeployCapacity(ctx, nodes, req) 81 assert.Nil(t, err) 82 assert.True(t, r.Total < 3) 83 84 // more 85 req = plugintypes.WorkloadResourceRequest{ 86 "cpu-bind": true, 87 "cpu-request": 3, 88 "memory-request": "1", 89 } 90 r, err = cm.GetNodesDeployCapacity(ctx, nodes, req) 91 assert.Nil(t, err) 92 assert.True(t, r.Total < 2) 93 94 // less 95 req = plugintypes.WorkloadResourceRequest{ 96 "cpu-bind": true, 97 "cpu-request": 1, 98 "memory-request": "1", 99 } 100 r, err = cm.GetNodesDeployCapacity(ctx, nodes, req) 101 assert.Nil(t, err) 102 assert.True(t, r.Total < 5) 103 104 // complex 105 nodes = generateNodes(ctx, t, cm, 1, 4, 12*units.GB, 100, 10) 106 nodes = append(nodes, generateNodes(ctx, t, cm, 1, 14, 12*units.GB, 100, 11)...) 107 nodes = append(nodes, generateNodes(ctx, t, cm, 1, 12, 12*units.GB, 100, 12)...) 108 nodes = append(nodes, generateNodes(ctx, t, cm, 1, 18, 12*units.GB, 100, 13)...) 109 nodes = append(nodes, generateNodes(ctx, t, cm, 1, 8, 12*units.GB, 100, 14)...) 110 111 req = plugintypes.WorkloadResourceRequest{ 112 "cpu-bind": true, 113 "cpu-request": 1.7, 114 "memory-request": "1", 115 } 116 r, err = cm.GetNodesDeployCapacity(ctx, nodes, req) 117 assert.Nil(t, err) 118 assert.Equal(t, r.Total, 28) 119 } 120 121 func TestGetNodesDeployCapacityWithMemoryAndCPUBind(t *testing.T) { 122 ctx := context.Background() 123 cm := initCPUMEM(ctx, t) 124 nodes := generateNodes(ctx, t, cm, 2, 2, 1024, 100, 0) 125 126 req := plugintypes.WorkloadResourceRequest{ 127 "cpu-bind": true, 128 "cpu-request": 0.1, 129 "memory-request": "1024", 130 } 131 132 r, err := cm.GetNodesDeployCapacity(ctx, nodes, req) 133 assert.Nil(t, err) 134 assert.Equal(t, r.Total, 2) 135 136 req["memory-request"] = "1025" 137 r, err = cm.GetNodesDeployCapacity(ctx, nodes, req) 138 assert.Nil(t, err) 139 assert.Equal(t, r.Total, 0) 140 } 141 142 func TestGetNodesDeployCapacityWithMaxShareLimit(t *testing.T) { 143 ctx := context.Background() 144 cm := initCPUMEM(ctx, t) 145 cm.config.Scheduler.MaxShare = 2 146 nodes := generateNodes(ctx, t, cm, 1, 6, 12*units.GB, 100, 0) 147 node := nodes[0] 148 149 req := plugintypes.WorkloadResourceRequest{ 150 "cpu-bind": true, 151 "cpu-request": 1.7, 152 "memory-request": "1", 153 } 154 155 r, err := cm.GetNodesDeployCapacity(ctx, nodes, req) 156 assert.Nil(t, err) 157 assert.Equal(t, r.Total, 2) 158 159 // numa node 160 resource := plugintypes.NodeResource{ 161 "cpu": 4.0, 162 "cpu_map": map[string]int64{ 163 "0": 0, 164 "1": 0, 165 "2": 100, 166 "3": 100, 167 }, 168 "memory": 12 * units.GB, 169 } 170 171 _, err = cm.SetNodeResourceCapacity(ctx, node, resource, nil, false, true) 172 assert.Nil(t, err) 173 174 req["cpu-request"] = 1.2 175 r, err = cm.GetNodesDeployCapacity(ctx, nodes, req) 176 assert.Nil(t, err) 177 assert.Equal(t, r.Total, 1) 178 } 179 180 func TestGetNodesDeployCapacityWithMemory(t *testing.T) { 181 ctx := context.Background() 182 cm := initCPUMEM(ctx, t) 183 nodes := generateNodes(ctx, t, cm, 2, 2, 4*units.GiB, 100, 0) 184 185 req := plugintypes.WorkloadResourceRequest{ 186 "memory-request": "-1", 187 } 188 189 // negative memory 190 _, err := cm.GetNodesDeployCapacity(ctx, nodes, req) 191 assert.True(t, errors.Is(err, types.ErrInvalidMemory)) 192 193 // cpu + mem 194 req = plugintypes.WorkloadResourceRequest{ 195 "cpu-request": 1, 196 "memory-request": fmt.Sprintf("%v", 512*units.MB), 197 } 198 199 r, err := cm.GetNodesDeployCapacity(ctx, nodes, req) 200 assert.Nil(t, err) 201 assert.Equal(t, r.Total, 16) 202 203 // unlimited cpu 204 req = plugintypes.WorkloadResourceRequest{ 205 "memory-request": fmt.Sprintf("%v", 512*units.MB), 206 } 207 r, err = cm.GetNodesDeployCapacity(ctx, nodes, req) 208 assert.Nil(t, err) 209 assert.Equal(t, r.Total, 16) 210 211 // insufficient cpu 212 req = plugintypes.WorkloadResourceRequest{ 213 "cpu-request": 3, 214 "memory-request": fmt.Sprintf("%v", 512*units.MB), 215 } 216 r, err = cm.GetNodesDeployCapacity(ctx, nodes, req) 217 assert.Nil(t, err) 218 assert.Equal(t, r.Total, 0) 219 220 // mem_request == 0 221 req = plugintypes.WorkloadResourceRequest{ 222 "cpu-request": 1, 223 } 224 r, err = cm.GetNodesDeployCapacity(ctx, nodes, req) 225 assert.Nil(t, err) 226 assert.Equal(t, r.Total, math.MaxInt) 227 } 228 229 func TestSetNodeResourceCapacity(t *testing.T) { 230 ctx := context.Background() 231 cm := initCPUMEM(ctx, t) 232 nodes := generateNodes(ctx, t, cm, 1, 2, 2*units.GB, 100, 0) 233 node := nodes[0] 234 235 _, err := cm.GetNodeResourceInfo(ctx, node, nil) 236 assert.Nil(t, err) 237 238 nodeResource := plugintypes.NodeResource{ 239 "cpu_map": map[string]int{ 240 "2": 100, 241 "3": 100, 242 }, 243 "numa_memory": types.NUMAMemory{ 244 "0": units.GiB, 245 "1": units.GiB, 246 }, 247 "numa": types.NUMA{ 248 "0": "0", 249 "1": "0", 250 "2": "1", 251 "3": "1", 252 }, 253 } 254 255 newNodeResource := plugintypes.NodeResource{ 256 "cpu_map": map[string]int{ 257 "0": 100, 258 "1": 100, 259 }, 260 "memory": 2 * units.GB, 261 "xxxx": map[string]interface{}{"cpu": ""}, 262 } 263 264 gb := fmt.Sprintf("%v", units.GB) 265 nodeResourceRequest := plugintypes.NodeResourceRequest{ 266 "cpu": "2:100,3:100", 267 "numa-memory": []string{gb, gb}, 268 "numa-cpu": []string{"0,1", "2,3"}, 269 } 270 271 noChangeRequest := plugintypes.NodeResourceRequest{ 272 "cpu": "0:100,1:100,2:100,3:100", 273 "memory": fmt.Sprintf("%v", 2*units.GB), 274 } 275 276 r, err := cm.SetNodeResourceCapacity(ctx, node, nodeResource, nil, true, true) 277 assert.Nil(t, err) 278 assert.Len(t, r.After["cpu_map"], 4) 279 280 r, err = cm.SetNodeResourceCapacity(ctx, node, nodeResource, nil, true, false) 281 assert.Nil(t, err) 282 assert.Len(t, r.After["cpu_map"], 2) 283 assert.Len(t, r.After["numa_memory"], 2) 284 assert.Len(t, r.After["numa"], 4) 285 286 r, err = cm.SetNodeResourceCapacity(ctx, node, nil, nodeResourceRequest, true, true) 287 assert.Nil(t, err) 288 assert.Len(t, r.After["cpu_map"], 4) 289 assert.Len(t, r.After["numa_memory"], 2) 290 assert.Len(t, r.After["numa"], 4) 291 292 r, err = cm.SetNodeResourceCapacity(ctx, node, nil, nodeResourceRequest, true, false) 293 assert.Nil(t, err) 294 assert.Len(t, r.After["cpu_map"], 2) 295 assert.Len(t, r.After["numa_memory"], 2) 296 assert.Len(t, r.After["numa"], 4) 297 298 r, err = cm.SetNodeResourceCapacity(ctx, node, nil, noChangeRequest, false, true) 299 assert.Nil(t, err) 300 assert.Len(t, r.After["cpu_map"], 4) 301 302 r, err = cm.SetNodeResourceCapacity(ctx, node, newNodeResource, nil, false, false) 303 assert.Nil(t, err) 304 assert.Len(t, r.After["cpu_map"], 2) 305 assert.Len(t, r.After["numa"], 0) 306 } 307 308 func TestGetAndFixNodeResourceInfo(t *testing.T) { 309 ctx := context.Background() 310 cm := initCPUMEM(ctx, t) 311 nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0) 312 node := nodes[0] 313 314 // invalid node 315 _, err := cm.GetNodeResourceInfo(ctx, "xxx", nil) 316 assert.True(t, errors.Is(err, coretypes.ErrInvaildCount)) 317 318 r, err := cm.GetNodeResourceInfo(ctx, node, nil) 319 assert.Nil(t, err) 320 assert.Len(t, r.Diffs, 0) 321 322 r.Capacity["numa"] = types.NUMA{"0": "0", "1": "1"} 323 r.Capacity["numa_memory"] = types.NUMAMemory{"0": units.GB, "1": units.GB} 324 325 _, err = cm.SetNodeResourceInfo(ctx, node, r.Capacity, r.Usage) 326 assert.Nil(t, err) 327 328 workloadsResource := []plugintypes.WorkloadResource{ 329 { 330 "cpu_request": 2.0, 331 "cpu_map": types.CPUMap{"0": 100, "1": 100}, 332 "memory_request": 2 * units.GB, 333 "numa_memory": types.NUMAMemory{"0": units.GB, "1": units.GB}, 334 }, 335 } 336 r, err = cm.GetNodeResourceInfo(ctx, node, workloadsResource) 337 assert.Nil(t, err) 338 assert.Len(t, r.Diffs, 6) 339 340 r, err = cm.FixNodeResource(ctx, node, workloadsResource) 341 assert.Nil(t, err) 342 assert.Len(t, r.Diffs, 6) 343 assert.Len(t, r.Usage["numa_memory"], 2) 344 } 345 346 func TestSetNodeResourceInfo(t *testing.T) { 347 ctx := context.Background() 348 cm := initCPUMEM(ctx, t) 349 nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0) 350 node := nodes[0] 351 352 r, err := cm.GetNodeResourceInfo(ctx, node, nil) 353 assert.Nil(t, err) 354 355 _, err = cm.SetNodeResourceInfo(ctx, "node-2", r.Capacity, r.Usage) 356 assert.Nil(t, err) 357 } 358 359 func TestSetNodeResourceUsage(t *testing.T) { 360 ctx := context.Background() 361 cm := initCPUMEM(ctx, t) 362 nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0) 363 node := nodes[0] 364 365 _, err := cm.GetNodeResourceInfo(ctx, node, nil) 366 assert.Nil(t, err) 367 368 nodeResource := plugintypes.NodeResource{ 369 "cpu_map": map[string]int{ 370 "0": 100, 371 "1": 100, 372 }, 373 "memory": 2 * units.GB, 374 } 375 376 nodeResourceRequest := plugintypes.NodeResourceRequest{ 377 "cpu": "0:100,1:100", 378 "memory": fmt.Sprintf("%v", 2*units.GB), 379 } 380 381 workloadsResource := []plugintypes.WorkloadResource{ 382 { 383 "cpu_request": 2.0, 384 "cpu_map": types.CPUMap{ 385 "0": 100, 386 "1": 100, 387 }, 388 "memory_request": 2 * units.GB, 389 }, 390 } 391 392 r, err := cm.SetNodeResourceUsage(ctx, node, nodeResource, nil, nil, true, true) 393 assert.Nil(t, err) 394 assert.Len(t, r.After["cpu_map"], 2) 395 396 r, err = cm.SetNodeResourceUsage(ctx, node, nodeResource, nil, nil, true, false) 397 assert.Nil(t, err) 398 assert.Len(t, r.After["cpu_map"], 2) 399 assert.Equal(t, r.After["cpu"], 0.0) 400 assert.Equal(t, r.After["memory"], int64(0)) 401 402 r, err = cm.SetNodeResourceUsage(ctx, node, nil, nodeResourceRequest, nil, true, true) 403 assert.Nil(t, err) 404 assert.Len(t, r.After["cpu_map"], 2) 405 406 r, err = cm.SetNodeResourceUsage(ctx, node, nil, nodeResourceRequest, nil, true, false) 407 assert.Nil(t, err) 408 assert.Len(t, r.After["cpu_map"], 2) 409 assert.Equal(t, r.After["cpu"], 0.0) 410 assert.Equal(t, r.After["memory"], int64(0)) 411 412 r, err = cm.SetNodeResourceUsage(ctx, node, nil, nil, workloadsResource, true, true) 413 assert.Nil(t, err) 414 assert.Len(t, r.After["cpu_map"], 2) 415 416 r, err = cm.SetNodeResourceUsage(ctx, node, nil, nil, workloadsResource, true, false) 417 assert.Nil(t, err) 418 assert.Len(t, r.After["cpu_map"], 2) 419 assert.Equal(t, r.After["cpu"], 0.0) 420 assert.Equal(t, r.After["memory"], int64(0)) 421 422 r, err = cm.SetNodeResourceUsage(ctx, node, nil, nil, nil, true, false) 423 assert.Nil(t, err) 424 assert.Len(t, r.After["cpu_map"], 2) 425 assert.Equal(t, r.After["cpu"], 0.0) 426 assert.Equal(t, r.After["memory"], int64(0)) 427 428 r, err = cm.SetNodeResourceUsage(ctx, node, nil, nodeResourceRequest, nil, false, false) 429 assert.Nil(t, err) 430 assert.Len(t, r.After["cpu_map"], 2) 431 assert.Equal(t, r.After["cpu"], 2.0) 432 assert.Equal(t, r.After["memory"], int64(2*units.GB)) 433 } 434 435 func TestGetMostIdleNode(t *testing.T) { 436 ctx := context.Background() 437 cm := initCPUMEM(ctx, t) 438 nodes := generateNodes(ctx, t, cm, 2, 2, 2*units.GB, 100, 0) 439 usage := plugintypes.NodeResourceRequest{"memory": "100"} 440 441 _, err := cm.SetNodeResourceUsage(ctx, nodes[1], nil, usage, nil, false, false) 442 assert.Nil(t, err) 443 444 r, err := cm.GetMostIdleNode(ctx, nodes) 445 assert.Nil(t, err) 446 assert.Equal(t, r.Nodename, nodes[0]) 447 448 nodes = append(nodes, "node-x") 449 _, err = cm.GetMostIdleNode(ctx, nodes) 450 assert.Error(t, err) 451 } 452 453 func BenchmarkGetNodesCapacity(b *testing.B) { 454 b.StopTimer() 455 t := &testing.T{} 456 ctx := context.Background() 457 cm := initCPUMEM(ctx, t) 458 nodes := generateNodes(ctx, t, cm, 1000, 24, 128*units.GB, 100, 0) 459 req := plugintypes.WorkloadResourceRequest{ 460 "cpu-bind": true, 461 "cpu-request": 1.3, 462 "memory-request": "1", 463 } 464 b.StartTimer() 465 466 for i := 0; i < b.N; i++ { 467 _, err := cm.GetNodesDeployCapacity(ctx, nodes, req) 468 assert.Nil(b, err) 469 } 470 }