k8s.io/kubernetes@v1.29.3/pkg/kubelet/cm/memorymanager/policy_static_test.go (about) 1 /* 2 Copyright 2020 The Kubernetes 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 memorymanager 18 19 import ( 20 "fmt" 21 "reflect" 22 "testing" 23 24 "k8s.io/klog/v2" 25 26 cadvisorapi "github.com/google/cadvisor/info/v1" 27 "github.com/google/go-cmp/cmp" 28 29 v1 "k8s.io/api/core/v1" 30 "k8s.io/apimachinery/pkg/api/resource" 31 "k8s.io/kubernetes/pkg/kubelet/cm/memorymanager/state" 32 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager" 33 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask" 34 ) 35 36 const ( 37 mb = 1024 * 1024 38 gb = mb * 1024 39 pageSize1Gb = 1048576 40 hugepages1Gi = v1.ResourceName(v1.ResourceHugePagesPrefix + "1Gi") 41 ) 42 43 var ( 44 containerRestartPolicyAlways = v1.ContainerRestartPolicyAlways 45 46 requirementsGuaranteed = &v1.ResourceRequirements{ 47 Limits: v1.ResourceList{ 48 v1.ResourceCPU: resource.MustParse("1000Mi"), 49 v1.ResourceMemory: resource.MustParse("1Gi"), 50 hugepages1Gi: resource.MustParse("1Gi"), 51 }, 52 Requests: v1.ResourceList{ 53 v1.ResourceCPU: resource.MustParse("1000Mi"), 54 v1.ResourceMemory: resource.MustParse("1Gi"), 55 hugepages1Gi: resource.MustParse("1Gi"), 56 }, 57 } 58 requirementsBurstable = &v1.ResourceRequirements{ 59 Limits: v1.ResourceList{ 60 v1.ResourceCPU: resource.MustParse("1000Mi"), 61 v1.ResourceMemory: resource.MustParse("2Gi"), 62 hugepages1Gi: resource.MustParse("2Gi"), 63 }, 64 Requests: v1.ResourceList{ 65 v1.ResourceCPU: resource.MustParse("1000Mi"), 66 v1.ResourceMemory: resource.MustParse("1Gi"), 67 hugepages1Gi: resource.MustParse("1Gi"), 68 }, 69 } 70 ) 71 72 func areMemoryBlocksEqual(mb1, mb2 []state.Block) bool { 73 if len(mb1) != len(mb2) { 74 return false 75 } 76 77 copyMemoryBlocks := make([]state.Block, len(mb2)) 78 copy(copyMemoryBlocks, mb2) 79 for _, block := range mb1 { 80 for i, copyBlock := range copyMemoryBlocks { 81 if reflect.DeepEqual(block, copyBlock) { 82 // move the element that equals to the block to the end of the slice 83 copyMemoryBlocks[i] = copyMemoryBlocks[len(copyMemoryBlocks)-1] 84 85 // remove the last element from our slice 86 copyMemoryBlocks = copyMemoryBlocks[:len(copyMemoryBlocks)-1] 87 88 break 89 } 90 } 91 } 92 93 return len(copyMemoryBlocks) == 0 94 } 95 96 func areContainerMemoryAssignmentsEqual(t *testing.T, cma1, cma2 state.ContainerMemoryAssignments) bool { 97 if len(cma1) != len(cma2) { 98 return false 99 } 100 101 for podUID, container := range cma1 { 102 if _, ok := cma2[podUID]; !ok { 103 t.Logf("[memorymanager_tests] the assignment does not have pod UID %s", podUID) 104 return false 105 } 106 107 for containerName, memoryBlocks := range container { 108 if _, ok := cma2[podUID][containerName]; !ok { 109 t.Logf("[memorymanager_tests] the assignment does not have container name %s", containerName) 110 return false 111 } 112 113 if !areMemoryBlocksEqual(memoryBlocks, cma2[podUID][containerName]) { 114 t.Logf("[memorymanager_tests] assignments memory blocks are different: %v != %v", memoryBlocks, cma2[podUID][containerName]) 115 return false 116 } 117 } 118 } 119 return true 120 } 121 122 type testStaticPolicy struct { 123 description string 124 assignments state.ContainerMemoryAssignments 125 expectedAssignments state.ContainerMemoryAssignments 126 machineState state.NUMANodeMap 127 expectedMachineState state.NUMANodeMap 128 systemReserved systemReservedMemory 129 expectedError error 130 machineInfo *cadvisorapi.MachineInfo 131 pod *v1.Pod 132 topologyHint *topologymanager.TopologyHint 133 expectedTopologyHints map[string][]topologymanager.TopologyHint 134 initContainersReusableMemory reusableMemory 135 } 136 137 func initTests(t *testing.T, testCase *testStaticPolicy, hint *topologymanager.TopologyHint, initContainersReusableMemory reusableMemory) (Policy, state.State, error) { 138 manager := topologymanager.NewFakeManager() 139 if hint != nil { 140 manager = topologymanager.NewFakeManagerWithHint(hint) 141 } 142 143 p, err := NewPolicyStatic(testCase.machineInfo, testCase.systemReserved, manager) 144 if err != nil { 145 return nil, nil, err 146 } 147 if initContainersReusableMemory != nil { 148 p.(*staticPolicy).initContainersReusableMemory = initContainersReusableMemory 149 } 150 s := state.NewMemoryState() 151 s.SetMachineState(testCase.machineState) 152 s.SetMemoryAssignments(testCase.assignments) 153 return p, s, nil 154 } 155 156 func newNUMAAffinity(bits ...int) bitmask.BitMask { 157 affinity, err := bitmask.NewBitMask(bits...) 158 if err != nil { 159 panic(err) 160 } 161 return affinity 162 } 163 164 func TestStaticPolicyNew(t *testing.T) { 165 testCases := []testStaticPolicy{ 166 { 167 description: "should fail, when machine does not have reserved memory for the system workloads", 168 expectedError: fmt.Errorf("[memorymanager] you should specify the system reserved memory"), 169 }, 170 { 171 description: "should succeed, when at least one NUMA node has reserved memory", 172 systemReserved: systemReservedMemory{ 173 0: map[v1.ResourceName]uint64{}, 174 1: map[v1.ResourceName]uint64{ 175 v1.ResourceMemory: 512 * mb, 176 }, 177 }, 178 }, 179 } 180 181 for _, testCase := range testCases { 182 t.Run(testCase.description, func(t *testing.T) { 183 _, _, err := initTests(t, &testCase, nil, nil) 184 if !reflect.DeepEqual(err, testCase.expectedError) { 185 t.Fatalf("The actual error: %v is different from the expected one: %v", err, testCase.expectedError) 186 } 187 }) 188 } 189 } 190 191 func TestStaticPolicyName(t *testing.T) { 192 testCases := []testStaticPolicy{ 193 { 194 description: "should return the correct policy name", 195 systemReserved: systemReservedMemory{ 196 0: map[v1.ResourceName]uint64{ 197 v1.ResourceMemory: 512 * mb, 198 }, 199 }, 200 }, 201 } 202 for _, testCase := range testCases { 203 t.Run(testCase.description, func(t *testing.T) { 204 p, _, err := initTests(t, &testCase, nil, nil) 205 if err != nil { 206 t.Fatalf("Unexpected error: %v", err) 207 } 208 if p.Name() != string(policyTypeStatic) { 209 t.Errorf("policy name is different, expected: %q, actual: %q", p.Name(), policyTypeStatic) 210 } 211 }) 212 } 213 } 214 215 func TestStaticPolicyStart(t *testing.T) { 216 testCases := []testStaticPolicy{ 217 { 218 description: "should fail, if machine state is empty, but it has memory assignments", 219 assignments: state.ContainerMemoryAssignments{ 220 "pod": map[string][]state.Block{ 221 "container1": { 222 { 223 NUMAAffinity: []int{0}, 224 Type: v1.ResourceMemory, 225 Size: 512 * mb, 226 }, 227 }, 228 }, 229 }, 230 systemReserved: systemReservedMemory{ 231 0: map[v1.ResourceName]uint64{ 232 v1.ResourceMemory: 512 * mb, 233 }, 234 }, 235 expectedError: fmt.Errorf("[memorymanager] machine state can not be empty when it has memory assignments"), 236 }, 237 { 238 description: "should fill the state with default values, when the state is empty", 239 expectedAssignments: state.ContainerMemoryAssignments{}, 240 expectedMachineState: state.NUMANodeMap{ 241 0: &state.NUMANodeState{ 242 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 243 v1.ResourceMemory: { 244 Allocatable: 1536 * mb, 245 Free: 1536 * mb, 246 Reserved: 0, 247 SystemReserved: 512 * mb, 248 TotalMemSize: 3 * gb, 249 }, 250 hugepages1Gi: { 251 Allocatable: gb, 252 Free: gb, 253 Reserved: 0, 254 SystemReserved: 0, 255 TotalMemSize: gb, 256 }, 257 }, 258 NumberOfAssignments: 0, 259 Cells: []int{0}, 260 }, 261 }, 262 systemReserved: systemReservedMemory{ 263 0: map[v1.ResourceName]uint64{ 264 v1.ResourceMemory: 512 * mb, 265 }, 266 }, 267 machineInfo: &cadvisorapi.MachineInfo{ 268 Topology: []cadvisorapi.Node{ 269 { 270 Id: 0, 271 Memory: 3 * gb, 272 HugePages: []cadvisorapi.HugePagesInfo{ 273 { 274 // size in KB 275 PageSize: pageSize1Gb, 276 NumPages: 1, 277 }, 278 }, 279 }, 280 }, 281 }, 282 }, 283 { 284 description: "should fail when machine state does not have all NUMA nodes", 285 machineState: state.NUMANodeMap{ 286 0: &state.NUMANodeState{ 287 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 288 v1.ResourceMemory: { 289 Allocatable: 1536 * mb, 290 Free: 1536 * mb, 291 Reserved: 0, 292 SystemReserved: 512 * mb, 293 TotalMemSize: 2 * gb, 294 }, 295 hugepages1Gi: { 296 Allocatable: gb, 297 Free: gb, 298 Reserved: 0, 299 SystemReserved: 0, 300 TotalMemSize: gb, 301 }, 302 }, 303 Cells: []int{0}, 304 NumberOfAssignments: 0, 305 }, 306 }, 307 systemReserved: systemReservedMemory{ 308 0: map[v1.ResourceName]uint64{ 309 v1.ResourceMemory: 512 * mb, 310 }, 311 }, 312 machineInfo: &cadvisorapi.MachineInfo{ 313 Topology: []cadvisorapi.Node{ 314 { 315 Id: 0, 316 Memory: 2 * gb, 317 HugePages: []cadvisorapi.HugePagesInfo{ 318 { 319 // size in KB 320 PageSize: pageSize1Gb, 321 NumPages: 1, 322 }, 323 }, 324 }, 325 { 326 Id: 1, 327 Memory: 2 * gb, 328 HugePages: []cadvisorapi.HugePagesInfo{ 329 { 330 // size in KB 331 PageSize: pageSize1Gb, 332 NumPages: 1, 333 }, 334 }, 335 }, 336 }, 337 }, 338 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 339 }, 340 { 341 description: "should fail when machine state does not have memory resource", 342 machineState: state.NUMANodeMap{ 343 0: &state.NUMANodeState{ 344 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 345 hugepages1Gi: { 346 Allocatable: gb, 347 Free: gb, 348 Reserved: 0, 349 SystemReserved: 0, 350 TotalMemSize: gb, 351 }, 352 }, 353 Cells: []int{0}, 354 NumberOfAssignments: 0, 355 }, 356 }, 357 machineInfo: &cadvisorapi.MachineInfo{ 358 Topology: []cadvisorapi.Node{ 359 { 360 Id: 0, 361 Memory: 2 * gb, 362 HugePages: []cadvisorapi.HugePagesInfo{ 363 { 364 // size in KB 365 PageSize: pageSize1Gb, 366 NumPages: 1, 367 }, 368 }, 369 }, 370 }, 371 }, 372 systemReserved: systemReservedMemory{ 373 0: map[v1.ResourceName]uint64{ 374 v1.ResourceMemory: 512 * mb, 375 }, 376 }, 377 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 378 }, 379 { 380 description: "should fail when machine state has wrong size of total memory", 381 machineState: state.NUMANodeMap{ 382 0: &state.NUMANodeState{ 383 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 384 v1.ResourceMemory: { 385 Allocatable: 1536 * mb, 386 Free: 1536 * mb, 387 Reserved: 0, 388 SystemReserved: 512 * mb, 389 TotalMemSize: 1536 * mb, 390 }, 391 }, 392 Cells: []int{0}, 393 NumberOfAssignments: 0, 394 }, 395 }, 396 systemReserved: systemReservedMemory{ 397 0: map[v1.ResourceName]uint64{ 398 v1.ResourceMemory: 512 * mb, 399 }, 400 }, 401 machineInfo: &cadvisorapi.MachineInfo{ 402 Topology: []cadvisorapi.Node{ 403 { 404 Id: 0, 405 Memory: 2 * gb, 406 HugePages: []cadvisorapi.HugePagesInfo{ 407 { 408 // size in KB 409 PageSize: pageSize1Gb, 410 NumPages: 1, 411 }, 412 }, 413 }, 414 }, 415 }, 416 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 417 }, 418 { 419 description: "should fail when machine state has wrong size of system reserved memory", 420 machineState: state.NUMANodeMap{ 421 0: &state.NUMANodeState{ 422 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 423 v1.ResourceMemory: { 424 Allocatable: 1536 * mb, 425 Free: 1536 * mb, 426 Reserved: 0, 427 SystemReserved: 1024, 428 TotalMemSize: 2 * gb, 429 }, 430 }, 431 Cells: []int{0}, 432 NumberOfAssignments: 0, 433 }, 434 }, 435 systemReserved: systemReservedMemory{ 436 0: map[v1.ResourceName]uint64{ 437 v1.ResourceMemory: 512 * mb, 438 }, 439 }, 440 machineInfo: &cadvisorapi.MachineInfo{ 441 Topology: []cadvisorapi.Node{ 442 { 443 Id: 0, 444 Memory: 2 * gb, 445 HugePages: []cadvisorapi.HugePagesInfo{ 446 { 447 // size in KB 448 PageSize: pageSize1Gb, 449 NumPages: 1, 450 }, 451 }, 452 }, 453 }, 454 }, 455 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 456 }, 457 { 458 description: "should fail when machine state reserved memory is different from the memory of all containers memory assignments", 459 assignments: state.ContainerMemoryAssignments{ 460 "pod": map[string][]state.Block{ 461 "container1": { 462 { 463 NUMAAffinity: []int{0}, 464 Type: v1.ResourceMemory, 465 Size: 512 * mb, 466 }, 467 }, 468 }, 469 }, 470 machineState: state.NUMANodeMap{ 471 0: &state.NUMANodeState{ 472 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 473 v1.ResourceMemory: { 474 Allocatable: 1536 * mb, 475 Free: 1536 * mb, 476 Reserved: 0, 477 SystemReserved: 512 * mb, 478 TotalMemSize: 2 * gb, 479 }, 480 }, 481 Cells: []int{0}, 482 NumberOfAssignments: 1, 483 }, 484 }, 485 systemReserved: systemReservedMemory{ 486 0: map[v1.ResourceName]uint64{ 487 v1.ResourceMemory: 512 * mb, 488 }, 489 }, 490 machineInfo: &cadvisorapi.MachineInfo{ 491 Topology: []cadvisorapi.Node{ 492 { 493 Id: 0, 494 Memory: 2 * gb, 495 HugePages: []cadvisorapi.HugePagesInfo{ 496 { 497 // size in KB 498 PageSize: pageSize1Gb, 499 NumPages: 1, 500 }, 501 }, 502 }, 503 }, 504 }, 505 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 506 }, 507 { 508 description: "should fail when machine state has wrong size of hugepages", 509 machineState: state.NUMANodeMap{ 510 0: &state.NUMANodeState{ 511 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 512 v1.ResourceMemory: { 513 Allocatable: 1536 * mb, 514 Free: 1536 * mb, 515 Reserved: 0, 516 SystemReserved: 512 * mb, 517 TotalMemSize: 2 * gb, 518 }, 519 hugepages1Gi: { 520 Allocatable: gb, 521 Free: gb, 522 Reserved: 0, 523 SystemReserved: 0, 524 TotalMemSize: gb, 525 }, 526 }, 527 Cells: []int{0}, 528 NumberOfAssignments: 0, 529 }, 530 }, 531 systemReserved: systemReservedMemory{ 532 0: map[v1.ResourceName]uint64{ 533 v1.ResourceMemory: 512 * mb, 534 }, 535 }, 536 machineInfo: &cadvisorapi.MachineInfo{ 537 Topology: []cadvisorapi.Node{ 538 { 539 Id: 0, 540 Memory: 2 * gb, 541 HugePages: []cadvisorapi.HugePagesInfo{ 542 { 543 // size in KB 544 PageSize: pageSize1Gb, 545 NumPages: 2, 546 }, 547 }, 548 }, 549 }, 550 }, 551 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 552 }, 553 { 554 description: "should fail when machine state has wrong size of system reserved hugepages", 555 machineState: state.NUMANodeMap{ 556 0: &state.NUMANodeState{ 557 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 558 v1.ResourceMemory: { 559 Allocatable: 1536 * mb, 560 Free: 1536 * mb, 561 Reserved: 0, 562 SystemReserved: 512 * mb, 563 TotalMemSize: 2 * gb, 564 }, 565 hugepages1Gi: { 566 Allocatable: gb, 567 Free: gb, 568 Reserved: 0, 569 SystemReserved: gb, 570 TotalMemSize: 2 * gb, 571 }, 572 }, 573 Cells: []int{0}, 574 NumberOfAssignments: 0, 575 }, 576 }, 577 systemReserved: systemReservedMemory{ 578 0: map[v1.ResourceName]uint64{ 579 v1.ResourceMemory: 512 * mb, 580 }, 581 }, 582 machineInfo: &cadvisorapi.MachineInfo{ 583 Topology: []cadvisorapi.Node{ 584 { 585 Id: 0, 586 Memory: 2 * gb, 587 HugePages: []cadvisorapi.HugePagesInfo{ 588 { 589 // size in KB 590 PageSize: pageSize1Gb, 591 NumPages: 2, 592 }, 593 }, 594 }, 595 }, 596 }, 597 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 598 }, 599 { 600 description: "should fail when the hugepages reserved machine state is different from the hugepages of all containers memory assignments", 601 assignments: state.ContainerMemoryAssignments{ 602 "pod1": map[string][]state.Block{ 603 "container1": { 604 { 605 NUMAAffinity: []int{0}, 606 Type: hugepages1Gi, 607 Size: gb, 608 }, 609 }, 610 }, 611 "pod2": map[string][]state.Block{ 612 "container2": { 613 { 614 NUMAAffinity: []int{0}, 615 Type: hugepages1Gi, 616 Size: gb, 617 }, 618 }, 619 }, 620 }, 621 machineState: state.NUMANodeMap{ 622 0: &state.NUMANodeState{ 623 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 624 v1.ResourceMemory: { 625 Allocatable: 1536 * mb, 626 Free: 1536 * mb, 627 Reserved: 0, 628 SystemReserved: 512 * mb, 629 TotalMemSize: 2 * gb, 630 }, 631 hugepages1Gi: { 632 Allocatable: 4 * gb, 633 Free: gb, 634 Reserved: 3 * gb, 635 SystemReserved: 0, 636 TotalMemSize: 4 * gb, 637 }, 638 }, 639 Cells: []int{0}, 640 NumberOfAssignments: 2, 641 }, 642 }, 643 systemReserved: systemReservedMemory{ 644 0: map[v1.ResourceName]uint64{ 645 v1.ResourceMemory: 512 * mb, 646 }, 647 }, 648 machineInfo: &cadvisorapi.MachineInfo{ 649 Topology: []cadvisorapi.Node{ 650 { 651 Id: 0, 652 Memory: 2 * gb, 653 HugePages: []cadvisorapi.HugePagesInfo{ 654 { 655 // size in KB 656 PageSize: pageSize1Gb, 657 NumPages: 4, 658 }, 659 }, 660 }, 661 }, 662 }, 663 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 664 }, 665 { 666 description: "should fail when machine state does not have NUMA node that used under the memory assignment", 667 assignments: state.ContainerMemoryAssignments{ 668 "pod1": map[string][]state.Block{ 669 "container1": { 670 { 671 NUMAAffinity: []int{1}, 672 Type: v1.ResourceMemory, 673 Size: gb, 674 }, 675 }, 676 }, 677 }, 678 machineState: state.NUMANodeMap{ 679 0: &state.NUMANodeState{ 680 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 681 v1.ResourceMemory: { 682 Allocatable: 1536 * mb, 683 Free: 1536 * mb, 684 Reserved: 0, 685 SystemReserved: 512 * mb, 686 TotalMemSize: 2 * gb, 687 }, 688 hugepages1Gi: { 689 Allocatable: gb, 690 Free: gb, 691 Reserved: 0, 692 SystemReserved: 0, 693 TotalMemSize: gb, 694 }, 695 }, 696 Cells: []int{0}, 697 NumberOfAssignments: 0, 698 }, 699 }, 700 systemReserved: systemReservedMemory{ 701 0: map[v1.ResourceName]uint64{ 702 v1.ResourceMemory: 512 * mb, 703 }, 704 }, 705 machineInfo: &cadvisorapi.MachineInfo{ 706 Topology: []cadvisorapi.Node{ 707 { 708 Id: 0, 709 Memory: 2 * gb, 710 HugePages: []cadvisorapi.HugePagesInfo{ 711 { 712 // size in KB 713 PageSize: pageSize1Gb, 714 NumPages: 1, 715 }, 716 }, 717 }, 718 }, 719 }, 720 expectedError: fmt.Errorf("[memorymanager] (pod: pod1, container: container1) the memory assignment uses the NUMA that does not exist"), 721 }, 722 { 723 description: "should fail when machine state does not have resource that used under the memory assignment", 724 assignments: state.ContainerMemoryAssignments{ 725 "pod1": map[string][]state.Block{ 726 "container1": { 727 { 728 NUMAAffinity: []int{0}, 729 Type: v1.ResourceMemory, 730 Size: gb, 731 }, 732 { 733 NUMAAffinity: []int{0}, 734 Type: hugepages2M, 735 Size: gb, 736 }, 737 }, 738 }, 739 }, 740 machineState: state.NUMANodeMap{ 741 0: &state.NUMANodeState{ 742 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 743 v1.ResourceMemory: { 744 Allocatable: 1536 * mb, 745 Free: 1536 * mb, 746 Reserved: 0, 747 SystemReserved: 512 * mb, 748 TotalMemSize: 2 * gb, 749 }, 750 hugepages1Gi: { 751 Allocatable: gb, 752 Free: gb, 753 Reserved: 0, 754 SystemReserved: 0, 755 TotalMemSize: gb, 756 }, 757 }, 758 Cells: []int{0}, 759 NumberOfAssignments: 2, 760 }, 761 }, 762 systemReserved: systemReservedMemory{ 763 0: map[v1.ResourceName]uint64{ 764 v1.ResourceMemory: 512 * mb, 765 }, 766 }, 767 machineInfo: &cadvisorapi.MachineInfo{ 768 Topology: []cadvisorapi.Node{ 769 { 770 Id: 0, 771 Memory: 2 * gb, 772 HugePages: []cadvisorapi.HugePagesInfo{ 773 { 774 // size in KB 775 PageSize: pageSize1Gb, 776 NumPages: 1, 777 }, 778 }, 779 }, 780 }, 781 }, 782 expectedError: fmt.Errorf("[memorymanager] (pod: pod1, container: container1) the memory assignment uses memory resource that does not exist"), 783 }, 784 { 785 description: "should fail when machine state number of assignments is different from the expected one", 786 assignments: state.ContainerMemoryAssignments{ 787 "pod1": map[string][]state.Block{ 788 "container1": { 789 { 790 NUMAAffinity: []int{0}, 791 Type: v1.ResourceMemory, 792 Size: gb, 793 }, 794 { 795 NUMAAffinity: []int{0}, 796 Type: hugepages1Gi, 797 Size: gb, 798 }, 799 }, 800 }, 801 }, 802 machineState: state.NUMANodeMap{ 803 0: &state.NUMANodeState{ 804 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 805 v1.ResourceMemory: { 806 Allocatable: 1536 * mb, 807 Free: 1536 * mb, 808 Reserved: 0, 809 SystemReserved: 512 * mb, 810 TotalMemSize: 2 * gb, 811 }, 812 hugepages1Gi: { 813 Allocatable: gb, 814 Free: gb, 815 Reserved: 0, 816 SystemReserved: 0, 817 TotalMemSize: gb, 818 }, 819 }, 820 Cells: []int{0}, 821 NumberOfAssignments: 1, 822 }, 823 }, 824 systemReserved: systemReservedMemory{ 825 0: map[v1.ResourceName]uint64{ 826 v1.ResourceMemory: 512 * mb, 827 }, 828 }, 829 machineInfo: &cadvisorapi.MachineInfo{ 830 Topology: []cadvisorapi.Node{ 831 { 832 Id: 0, 833 Memory: 2 * gb, 834 HugePages: []cadvisorapi.HugePagesInfo{ 835 { 836 // size in KB 837 PageSize: pageSize1Gb, 838 NumPages: 1, 839 }, 840 }, 841 }, 842 }, 843 }, 844 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 845 }, 846 { 847 description: "should validate cross NUMA reserved memory vs container assignments", 848 assignments: state.ContainerMemoryAssignments{ 849 "pod1": map[string][]state.Block{ 850 "container1": { 851 { 852 NUMAAffinity: []int{0, 1}, 853 Type: v1.ResourceMemory, 854 Size: 768 * mb, 855 }, 856 { 857 NUMAAffinity: []int{0, 1}, 858 Type: hugepages1Gi, 859 Size: gb, 860 }, 861 }, 862 }, 863 "pod2": map[string][]state.Block{ 864 "container2": { 865 { 866 NUMAAffinity: []int{0, 1}, 867 Type: v1.ResourceMemory, 868 Size: 256 * mb, 869 }, 870 { 871 NUMAAffinity: []int{0, 1}, 872 Type: hugepages1Gi, 873 Size: gb, 874 }, 875 }, 876 }, 877 }, 878 expectedAssignments: state.ContainerMemoryAssignments{ 879 "pod1": map[string][]state.Block{ 880 "container1": { 881 { 882 NUMAAffinity: []int{0, 1}, 883 Type: v1.ResourceMemory, 884 Size: 768 * mb, 885 }, 886 { 887 NUMAAffinity: []int{0, 1}, 888 Type: hugepages1Gi, 889 Size: gb, 890 }, 891 }, 892 }, 893 "pod2": map[string][]state.Block{ 894 "container2": { 895 { 896 NUMAAffinity: []int{0, 1}, 897 Type: v1.ResourceMemory, 898 Size: 256 * mb, 899 }, 900 { 901 NUMAAffinity: []int{0, 1}, 902 Type: hugepages1Gi, 903 Size: gb, 904 }, 905 }, 906 }, 907 }, 908 machineState: state.NUMANodeMap{ 909 0: &state.NUMANodeState{ 910 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 911 v1.ResourceMemory: { 912 Allocatable: 640 * mb, 913 Free: 0, 914 Reserved: 640 * mb, 915 SystemReserved: 512 * mb, 916 TotalMemSize: 2176 * mb, 917 }, 918 hugepages1Gi: { 919 Allocatable: gb, 920 Free: 0, 921 Reserved: gb, 922 SystemReserved: 0, 923 TotalMemSize: gb, 924 }, 925 }, 926 Cells: []int{0, 1}, 927 NumberOfAssignments: 4, 928 }, 929 1: &state.NUMANodeState{ 930 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 931 v1.ResourceMemory: { 932 Allocatable: 640 * mb, 933 Free: 256 * mb, 934 Reserved: 384 * mb, 935 SystemReserved: 512 * mb, 936 TotalMemSize: 2176 * mb, 937 }, 938 hugepages1Gi: { 939 Allocatable: gb, 940 Free: 0, 941 Reserved: gb, 942 SystemReserved: 0, 943 TotalMemSize: gb, 944 }, 945 }, 946 Cells: []int{0, 1}, 947 NumberOfAssignments: 4, 948 }, 949 }, 950 expectedMachineState: state.NUMANodeMap{ 951 0: &state.NUMANodeState{ 952 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 953 v1.ResourceMemory: { 954 Allocatable: 640 * mb, 955 Free: 0, 956 Reserved: 640 * mb, 957 SystemReserved: 512 * mb, 958 TotalMemSize: 2176 * mb, 959 }, 960 hugepages1Gi: { 961 Allocatable: gb, 962 Free: 0, 963 Reserved: gb, 964 SystemReserved: 0, 965 TotalMemSize: gb, 966 }, 967 }, 968 Cells: []int{0, 1}, 969 NumberOfAssignments: 4, 970 }, 971 1: &state.NUMANodeState{ 972 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 973 v1.ResourceMemory: { 974 Allocatable: 640 * mb, 975 Free: 256 * mb, 976 Reserved: 384 * mb, 977 SystemReserved: 512 * mb, 978 TotalMemSize: 2176 * mb, 979 }, 980 hugepages1Gi: { 981 Allocatable: gb, 982 Free: 0, 983 Reserved: gb, 984 SystemReserved: 0, 985 TotalMemSize: gb, 986 }, 987 }, 988 Cells: []int{0, 1}, 989 NumberOfAssignments: 4, 990 }, 991 }, 992 systemReserved: systemReservedMemory{ 993 0: map[v1.ResourceName]uint64{ 994 v1.ResourceMemory: 512 * mb, 995 }, 996 1: map[v1.ResourceName]uint64{ 997 v1.ResourceMemory: 512 * mb, 998 }, 999 }, 1000 machineInfo: &cadvisorapi.MachineInfo{ 1001 Topology: []cadvisorapi.Node{ 1002 { 1003 Id: 0, 1004 Memory: 2176 * mb, 1005 HugePages: []cadvisorapi.HugePagesInfo{ 1006 { 1007 // size in KB 1008 PageSize: pageSize1Gb, 1009 NumPages: 1, 1010 }, 1011 }, 1012 }, 1013 { 1014 Id: 1, 1015 Memory: 2176 * mb, 1016 HugePages: []cadvisorapi.HugePagesInfo{ 1017 { 1018 // size in KB 1019 PageSize: pageSize1Gb, 1020 NumPages: 1, 1021 }, 1022 }, 1023 }, 1024 }, 1025 }, 1026 }, 1027 } 1028 1029 for _, testCase := range testCases { 1030 t.Run(testCase.description, func(t *testing.T) { 1031 t.Logf("[Start] %s", testCase.description) 1032 p, s, err := initTests(t, &testCase, nil, nil) 1033 if err != nil { 1034 t.Fatalf("Unexpected error: %v", err) 1035 } 1036 1037 err = p.Start(s) 1038 if !reflect.DeepEqual(err, testCase.expectedError) { 1039 t.Fatalf("The actual error: %v is different from the expected one: %v", err, testCase.expectedError) 1040 } 1041 1042 if err != nil { 1043 return 1044 } 1045 1046 assignments := s.GetMemoryAssignments() 1047 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) { 1048 t.Fatalf("Actual assignments: %v is different from the expected one: %v", assignments, testCase.expectedAssignments) 1049 } 1050 1051 machineState := s.GetMachineState() 1052 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) { 1053 t.Fatalf("The actual machine state: %v is different from the expected one: %v", machineState, testCase.expectedMachineState) 1054 } 1055 }) 1056 } 1057 } 1058 1059 func TestStaticPolicyAllocate(t *testing.T) { 1060 testCases := []testStaticPolicy{ 1061 { 1062 description: "should do nothing for non-guaranteed pods", 1063 expectedAssignments: state.ContainerMemoryAssignments{}, 1064 machineState: state.NUMANodeMap{ 1065 0: &state.NUMANodeState{ 1066 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1067 v1.ResourceMemory: { 1068 Allocatable: 1536 * mb, 1069 Free: 1536 * mb, 1070 Reserved: 0, 1071 SystemReserved: 512 * mb, 1072 TotalMemSize: 2 * gb, 1073 }, 1074 hugepages1Gi: { 1075 Allocatable: gb, 1076 Free: gb, 1077 Reserved: 0, 1078 SystemReserved: 0, 1079 TotalMemSize: gb, 1080 }, 1081 }, 1082 Cells: []int{}, 1083 }, 1084 }, 1085 expectedMachineState: state.NUMANodeMap{ 1086 0: &state.NUMANodeState{ 1087 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1088 v1.ResourceMemory: { 1089 Allocatable: 1536 * mb, 1090 Free: 1536 * mb, 1091 Reserved: 0, 1092 SystemReserved: 512 * mb, 1093 TotalMemSize: 2 * gb, 1094 }, 1095 hugepages1Gi: { 1096 Allocatable: gb, 1097 Free: gb, 1098 Reserved: 0, 1099 SystemReserved: 0, 1100 TotalMemSize: gb, 1101 }, 1102 }, 1103 Cells: []int{}, 1104 }, 1105 }, 1106 systemReserved: systemReservedMemory{ 1107 0: map[v1.ResourceName]uint64{ 1108 v1.ResourceMemory: 512 * mb, 1109 }, 1110 }, 1111 pod: getPod("pod1", "container1", requirementsBurstable), 1112 expectedTopologyHints: nil, 1113 topologyHint: &topologymanager.TopologyHint{}, 1114 }, 1115 { 1116 description: "should do nothing once container already exists under the state file", 1117 assignments: state.ContainerMemoryAssignments{ 1118 "pod1": map[string][]state.Block{ 1119 "container1": { 1120 { 1121 NUMAAffinity: []int{0}, 1122 Type: v1.ResourceMemory, 1123 Size: gb, 1124 }, 1125 }, 1126 }, 1127 }, 1128 expectedAssignments: state.ContainerMemoryAssignments{ 1129 "pod1": map[string][]state.Block{ 1130 "container1": { 1131 { 1132 NUMAAffinity: []int{0}, 1133 Type: v1.ResourceMemory, 1134 Size: gb, 1135 }, 1136 }, 1137 }, 1138 }, 1139 machineState: state.NUMANodeMap{ 1140 0: &state.NUMANodeState{ 1141 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1142 v1.ResourceMemory: { 1143 Allocatable: 1536 * mb, 1144 Free: 512 * mb, 1145 Reserved: 1024 * mb, 1146 SystemReserved: 512 * mb, 1147 TotalMemSize: 2 * gb, 1148 }, 1149 hugepages1Gi: { 1150 Allocatable: gb, 1151 Free: gb, 1152 Reserved: 0, 1153 SystemReserved: 0, 1154 TotalMemSize: gb, 1155 }, 1156 }, 1157 Cells: []int{}, 1158 }, 1159 }, 1160 expectedMachineState: state.NUMANodeMap{ 1161 0: &state.NUMANodeState{ 1162 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1163 v1.ResourceMemory: { 1164 Allocatable: 1536 * mb, 1165 Free: 512 * mb, 1166 Reserved: 1024 * mb, 1167 SystemReserved: 512 * mb, 1168 TotalMemSize: 2 * gb, 1169 }, 1170 hugepages1Gi: { 1171 Allocatable: gb, 1172 Free: gb, 1173 Reserved: 0, 1174 SystemReserved: 0, 1175 TotalMemSize: gb, 1176 }, 1177 }, 1178 Cells: []int{}, 1179 }, 1180 }, 1181 systemReserved: systemReservedMemory{ 1182 0: map[v1.ResourceName]uint64{ 1183 v1.ResourceMemory: 512 * mb, 1184 }, 1185 }, 1186 pod: getPod("pod1", "container1", requirementsGuaranteed), 1187 expectedTopologyHints: nil, 1188 topologyHint: &topologymanager.TopologyHint{}, 1189 }, 1190 { 1191 description: "should calculate a default topology hint when no NUMA affinity was provided by the topology manager hint", 1192 assignments: state.ContainerMemoryAssignments{}, 1193 expectedAssignments: state.ContainerMemoryAssignments{ 1194 "pod1": map[string][]state.Block{ 1195 "container1": { 1196 { 1197 NUMAAffinity: []int{0}, 1198 Type: v1.ResourceMemory, 1199 Size: gb, 1200 }, 1201 { 1202 NUMAAffinity: []int{0}, 1203 Type: hugepages1Gi, 1204 Size: gb, 1205 }, 1206 }, 1207 }, 1208 }, 1209 machineState: state.NUMANodeMap{ 1210 0: &state.NUMANodeState{ 1211 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1212 v1.ResourceMemory: { 1213 Allocatable: 1536 * mb, 1214 Free: 1536 * mb, 1215 Reserved: 0, 1216 SystemReserved: 512 * mb, 1217 TotalMemSize: 2 * gb, 1218 }, 1219 hugepages1Gi: { 1220 Allocatable: gb, 1221 Free: gb, 1222 Reserved: 0, 1223 SystemReserved: 0, 1224 TotalMemSize: gb, 1225 }, 1226 }, 1227 Cells: []int{0}, 1228 }, 1229 }, 1230 expectedMachineState: state.NUMANodeMap{ 1231 0: &state.NUMANodeState{ 1232 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1233 v1.ResourceMemory: { 1234 Allocatable: 1536 * mb, 1235 Free: 512 * mb, 1236 Reserved: 1024 * mb, 1237 SystemReserved: 512 * mb, 1238 TotalMemSize: 2 * gb, 1239 }, 1240 hugepages1Gi: { 1241 Allocatable: gb, 1242 Free: 0, 1243 Reserved: gb, 1244 SystemReserved: 0, 1245 TotalMemSize: gb, 1246 }, 1247 }, 1248 Cells: []int{0}, 1249 NumberOfAssignments: 2, 1250 }, 1251 }, 1252 systemReserved: systemReservedMemory{ 1253 0: map[v1.ResourceName]uint64{ 1254 v1.ResourceMemory: 512 * mb, 1255 }, 1256 }, 1257 pod: getPod("pod1", "container1", requirementsGuaranteed), 1258 topologyHint: &topologymanager.TopologyHint{}, 1259 }, 1260 { 1261 description: "should fail when no NUMA affinity was provided under the topology manager hint and calculation of the default hint failed", 1262 assignments: state.ContainerMemoryAssignments{ 1263 "pod1": map[string][]state.Block{ 1264 "container1": { 1265 { 1266 NUMAAffinity: []int{0}, 1267 Type: v1.ResourceMemory, 1268 Size: gb, 1269 }, 1270 { 1271 NUMAAffinity: []int{0}, 1272 Type: hugepages1Gi, 1273 Size: gb, 1274 }, 1275 }, 1276 }, 1277 }, 1278 machineState: state.NUMANodeMap{ 1279 0: &state.NUMANodeState{ 1280 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1281 v1.ResourceMemory: { 1282 Allocatable: 1536 * mb, 1283 Free: 512 * mb, 1284 Reserved: 1024 * mb, 1285 SystemReserved: 512 * mb, 1286 TotalMemSize: 2 * gb, 1287 }, 1288 hugepages1Gi: { 1289 Allocatable: gb, 1290 Free: 0, 1291 Reserved: gb, 1292 SystemReserved: 0, 1293 TotalMemSize: gb, 1294 }, 1295 }, 1296 Cells: []int{0}, 1297 NumberOfAssignments: 2, 1298 }, 1299 }, 1300 systemReserved: systemReservedMemory{ 1301 0: map[v1.ResourceName]uint64{ 1302 v1.ResourceMemory: 512 * mb, 1303 }, 1304 }, 1305 pod: getPod("pod2", "container2", requirementsGuaranteed), 1306 expectedError: fmt.Errorf("[memorymanager] failed to get the default NUMA affinity, no NUMA nodes with enough memory is available"), 1307 topologyHint: &topologymanager.TopologyHint{}, 1308 }, 1309 { 1310 description: "should fail when no NUMA affinity was provided under the topology manager preferred hint and default hint has preferred false", 1311 assignments: state.ContainerMemoryAssignments{ 1312 "pod1": map[string][]state.Block{ 1313 "container1": { 1314 { 1315 NUMAAffinity: []int{0}, 1316 Type: v1.ResourceMemory, 1317 Size: 512 * mb, 1318 }, 1319 }, 1320 }, 1321 }, 1322 machineState: state.NUMANodeMap{ 1323 0: &state.NUMANodeState{ 1324 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1325 v1.ResourceMemory: { 1326 Allocatable: gb, 1327 Free: 512 * mb, 1328 Reserved: 512 * mb, 1329 SystemReserved: 512 * mb, 1330 TotalMemSize: 1536 * mb, 1331 }, 1332 hugepages1Gi: { 1333 Allocatable: gb, 1334 Free: gb, 1335 Reserved: 0, 1336 SystemReserved: 0, 1337 TotalMemSize: gb, 1338 }, 1339 }, 1340 Cells: []int{0}, 1341 NumberOfAssignments: 1, 1342 }, 1343 1: &state.NUMANodeState{ 1344 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1345 v1.ResourceMemory: { 1346 Allocatable: 512 * mb, 1347 Free: 512 * mb, 1348 Reserved: 0, 1349 SystemReserved: 512 * mb, 1350 TotalMemSize: 1536 * mb, 1351 }, 1352 hugepages1Gi: { 1353 Allocatable: gb, 1354 Free: gb, 1355 Reserved: 0, 1356 SystemReserved: 0, 1357 TotalMemSize: gb, 1358 }, 1359 }, 1360 Cells: []int{1}, 1361 NumberOfAssignments: 0, 1362 }, 1363 2: &state.NUMANodeState{ 1364 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1365 v1.ResourceMemory: { 1366 Allocatable: 512 * mb, 1367 Free: 512 * mb, 1368 Reserved: 0, 1369 SystemReserved: 512 * mb, 1370 TotalMemSize: 1536 * mb, 1371 }, 1372 hugepages1Gi: { 1373 Allocatable: gb, 1374 Free: gb, 1375 Reserved: 0, 1376 SystemReserved: 0, 1377 TotalMemSize: gb, 1378 }, 1379 }, 1380 Cells: []int{2}, 1381 NumberOfAssignments: 0, 1382 }, 1383 }, 1384 systemReserved: systemReservedMemory{ 1385 0: map[v1.ResourceName]uint64{ 1386 v1.ResourceMemory: 512 * mb, 1387 }, 1388 1: map[v1.ResourceName]uint64{ 1389 v1.ResourceMemory: 512 * mb, 1390 }, 1391 2: map[v1.ResourceName]uint64{ 1392 v1.ResourceMemory: 512 * mb, 1393 }, 1394 }, 1395 pod: getPod("pod2", "container2", requirementsGuaranteed), 1396 expectedError: fmt.Errorf("[memorymanager] failed to find the default preferred hint"), 1397 topologyHint: &topologymanager.TopologyHint{Preferred: true}, 1398 }, 1399 { 1400 description: "should fail when NUMA affinity provided under the topology manager hint did not satisfy container requirements and extended hint generation failed", 1401 machineState: state.NUMANodeMap{ 1402 0: &state.NUMANodeState{ 1403 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1404 v1.ResourceMemory: { 1405 Allocatable: 512 * mb, 1406 Free: 512 * mb, 1407 Reserved: 0, 1408 SystemReserved: 512 * mb, 1409 TotalMemSize: gb, 1410 }, 1411 hugepages1Gi: { 1412 Allocatable: gb, 1413 Free: gb, 1414 Reserved: 0, 1415 SystemReserved: 0, 1416 TotalMemSize: gb, 1417 }, 1418 }, 1419 Cells: []int{0}, 1420 NumberOfAssignments: 0, 1421 }, 1422 1: &state.NUMANodeState{ 1423 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1424 v1.ResourceMemory: { 1425 Allocatable: 1536 * mb, 1426 Free: 512 * mb, 1427 Reserved: gb, 1428 SystemReserved: 512 * mb, 1429 TotalMemSize: 2 * gb, 1430 }, 1431 hugepages1Gi: { 1432 Allocatable: gb, 1433 Free: gb, 1434 Reserved: 0, 1435 SystemReserved: 0, 1436 TotalMemSize: gb, 1437 }, 1438 }, 1439 Cells: []int{1, 2}, 1440 NumberOfAssignments: 1, 1441 }, 1442 2: &state.NUMANodeState{ 1443 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1444 v1.ResourceMemory: { 1445 Allocatable: 1536 * mb, 1446 Free: 512 * mb, 1447 Reserved: gb, 1448 SystemReserved: 512 * mb, 1449 TotalMemSize: 2 * gb, 1450 }, 1451 hugepages1Gi: { 1452 Allocatable: gb, 1453 Free: gb, 1454 Reserved: 0, 1455 SystemReserved: 0, 1456 TotalMemSize: gb, 1457 }, 1458 }, 1459 Cells: []int{1, 2}, 1460 NumberOfAssignments: 1, 1461 }, 1462 }, 1463 systemReserved: systemReservedMemory{ 1464 0: map[v1.ResourceName]uint64{ 1465 v1.ResourceMemory: 512 * mb, 1466 }, 1467 1: map[v1.ResourceName]uint64{ 1468 v1.ResourceMemory: 512 * mb, 1469 }, 1470 2: map[v1.ResourceName]uint64{ 1471 v1.ResourceMemory: 512 * mb, 1472 }, 1473 }, 1474 pod: getPod("pod1", "container1", requirementsGuaranteed), 1475 expectedError: fmt.Errorf("[memorymanager] failed to find NUMA nodes to extend the current topology hint"), 1476 topologyHint: &topologymanager.TopologyHint{NUMANodeAffinity: newNUMAAffinity(0), Preferred: false}, 1477 }, 1478 { 1479 description: "should fail when the topology manager provided the preferred hint and extended hint has preferred false", 1480 assignments: state.ContainerMemoryAssignments{ 1481 "pod1": map[string][]state.Block{ 1482 "container1": { 1483 { 1484 NUMAAffinity: []int{0}, 1485 Type: v1.ResourceMemory, 1486 Size: 512 * mb, 1487 }, 1488 }, 1489 }, 1490 }, 1491 machineState: state.NUMANodeMap{ 1492 0: &state.NUMANodeState{ 1493 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1494 v1.ResourceMemory: { 1495 Allocatable: gb, 1496 Free: 512 * mb, 1497 Reserved: 512 * mb, 1498 SystemReserved: 512 * mb, 1499 TotalMemSize: 1536 * mb, 1500 }, 1501 hugepages1Gi: { 1502 Allocatable: gb, 1503 Free: gb, 1504 Reserved: 0, 1505 SystemReserved: 0, 1506 TotalMemSize: gb, 1507 }, 1508 }, 1509 Cells: []int{0}, 1510 NumberOfAssignments: 1, 1511 }, 1512 1: &state.NUMANodeState{ 1513 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1514 v1.ResourceMemory: { 1515 Allocatable: 512 * mb, 1516 Free: 512 * mb, 1517 Reserved: 0, 1518 SystemReserved: 512 * mb, 1519 TotalMemSize: 1536 * mb, 1520 }, 1521 hugepages1Gi: { 1522 Allocatable: gb, 1523 Free: gb, 1524 Reserved: 0, 1525 SystemReserved: 0, 1526 TotalMemSize: gb, 1527 }, 1528 }, 1529 Cells: []int{1}, 1530 NumberOfAssignments: 0, 1531 }, 1532 2: &state.NUMANodeState{ 1533 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1534 v1.ResourceMemory: { 1535 Allocatable: 512 * mb, 1536 Free: 512 * mb, 1537 Reserved: 0, 1538 SystemReserved: 512 * mb, 1539 TotalMemSize: 1536 * mb, 1540 }, 1541 hugepages1Gi: { 1542 Allocatable: gb, 1543 Free: gb, 1544 Reserved: 0, 1545 SystemReserved: 0, 1546 TotalMemSize: gb, 1547 }, 1548 }, 1549 Cells: []int{2}, 1550 NumberOfAssignments: 0, 1551 }, 1552 }, 1553 systemReserved: systemReservedMemory{ 1554 0: map[v1.ResourceName]uint64{ 1555 v1.ResourceMemory: 512 * mb, 1556 }, 1557 1: map[v1.ResourceName]uint64{ 1558 v1.ResourceMemory: 512 * mb, 1559 }, 1560 2: map[v1.ResourceName]uint64{ 1561 v1.ResourceMemory: 512 * mb, 1562 }, 1563 }, 1564 pod: getPod("pod2", "container2", requirementsGuaranteed), 1565 expectedError: fmt.Errorf("[memorymanager] failed to find the extended preferred hint"), 1566 topologyHint: &topologymanager.TopologyHint{NUMANodeAffinity: newNUMAAffinity(1), Preferred: true}, 1567 }, 1568 { 1569 description: "should succeed to allocate memory from multiple NUMA nodes", 1570 assignments: state.ContainerMemoryAssignments{}, 1571 expectedAssignments: state.ContainerMemoryAssignments{ 1572 "pod1": map[string][]state.Block{ 1573 "container1": { 1574 { 1575 NUMAAffinity: []int{0, 1}, 1576 Type: v1.ResourceMemory, 1577 Size: gb, 1578 }, 1579 { 1580 NUMAAffinity: []int{0, 1}, 1581 Type: hugepages1Gi, 1582 Size: gb, 1583 }, 1584 }, 1585 }, 1586 }, 1587 machineState: state.NUMANodeMap{ 1588 0: &state.NUMANodeState{ 1589 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1590 v1.ResourceMemory: { 1591 Allocatable: 512 * mb, 1592 Free: 512 * mb, 1593 Reserved: 0, 1594 SystemReserved: 512 * mb, 1595 TotalMemSize: gb, 1596 }, 1597 hugepages1Gi: { 1598 Allocatable: gb, 1599 Free: gb, 1600 Reserved: 0, 1601 SystemReserved: 0, 1602 TotalMemSize: gb, 1603 }, 1604 }, 1605 Cells: []int{0}, 1606 NumberOfAssignments: 0, 1607 }, 1608 1: &state.NUMANodeState{ 1609 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1610 v1.ResourceMemory: { 1611 Allocatable: 512 * mb, 1612 Free: 512 * mb, 1613 Reserved: 0, 1614 SystemReserved: 512 * mb, 1615 TotalMemSize: gb, 1616 }, 1617 hugepages1Gi: { 1618 Allocatable: gb, 1619 Free: gb, 1620 Reserved: 0, 1621 SystemReserved: 0, 1622 TotalMemSize: gb, 1623 }, 1624 }, 1625 Cells: []int{1}, 1626 NumberOfAssignments: 0, 1627 }, 1628 2: &state.NUMANodeState{ 1629 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1630 v1.ResourceMemory: { 1631 Allocatable: 512 * mb, 1632 Free: 512 * mb, 1633 Reserved: 0, 1634 SystemReserved: 512 * mb, 1635 TotalMemSize: gb, 1636 }, 1637 hugepages1Gi: { 1638 Allocatable: gb, 1639 Free: gb, 1640 Reserved: 0, 1641 SystemReserved: 0, 1642 TotalMemSize: gb, 1643 }, 1644 }, 1645 Cells: []int{2}, 1646 NumberOfAssignments: 0, 1647 }, 1648 3: &state.NUMANodeState{ 1649 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1650 v1.ResourceMemory: { 1651 Allocatable: 512 * mb, 1652 Free: 512 * mb, 1653 Reserved: 0, 1654 SystemReserved: 512 * mb, 1655 TotalMemSize: gb, 1656 }, 1657 hugepages1Gi: { 1658 Allocatable: gb, 1659 Free: gb, 1660 Reserved: 0, 1661 SystemReserved: 0, 1662 TotalMemSize: gb, 1663 }, 1664 }, 1665 Cells: []int{3}, 1666 NumberOfAssignments: 0, 1667 }, 1668 }, 1669 expectedMachineState: state.NUMANodeMap{ 1670 0: &state.NUMANodeState{ 1671 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1672 v1.ResourceMemory: { 1673 Allocatable: 512 * mb, 1674 Free: 0, 1675 Reserved: 512 * mb, 1676 SystemReserved: 512 * mb, 1677 TotalMemSize: gb, 1678 }, 1679 hugepages1Gi: { 1680 Allocatable: gb, 1681 Free: 0, 1682 Reserved: gb, 1683 SystemReserved: 0, 1684 TotalMemSize: gb, 1685 }, 1686 }, 1687 Cells: []int{0, 1}, 1688 NumberOfAssignments: 2, 1689 }, 1690 1: &state.NUMANodeState{ 1691 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1692 v1.ResourceMemory: { 1693 Allocatable: 512 * mb, 1694 Free: 0, 1695 Reserved: 512 * mb, 1696 SystemReserved: 512 * mb, 1697 TotalMemSize: gb, 1698 }, 1699 hugepages1Gi: { 1700 Allocatable: gb, 1701 Free: gb, 1702 Reserved: 0, 1703 SystemReserved: 0, 1704 TotalMemSize: gb, 1705 }, 1706 }, 1707 Cells: []int{0, 1}, 1708 NumberOfAssignments: 2, 1709 }, 1710 2: &state.NUMANodeState{ 1711 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1712 v1.ResourceMemory: { 1713 Allocatable: 512 * mb, 1714 Free: 512 * mb, 1715 Reserved: 0, 1716 SystemReserved: 512 * mb, 1717 TotalMemSize: gb, 1718 }, 1719 hugepages1Gi: { 1720 Allocatable: gb, 1721 Free: gb, 1722 Reserved: 0, 1723 SystemReserved: 0, 1724 TotalMemSize: gb, 1725 }, 1726 }, 1727 Cells: []int{2}, 1728 NumberOfAssignments: 0, 1729 }, 1730 3: &state.NUMANodeState{ 1731 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1732 v1.ResourceMemory: { 1733 Allocatable: 512 * mb, 1734 Free: 512 * mb, 1735 Reserved: 0, 1736 SystemReserved: 512 * mb, 1737 TotalMemSize: gb, 1738 }, 1739 hugepages1Gi: { 1740 Allocatable: gb, 1741 Free: gb, 1742 Reserved: 0, 1743 SystemReserved: 0, 1744 TotalMemSize: gb, 1745 }, 1746 }, 1747 Cells: []int{3}, 1748 NumberOfAssignments: 0, 1749 }, 1750 }, 1751 systemReserved: systemReservedMemory{ 1752 0: map[v1.ResourceName]uint64{ 1753 v1.ResourceMemory: 512 * mb, 1754 }, 1755 1: map[v1.ResourceName]uint64{ 1756 v1.ResourceMemory: 512 * mb, 1757 }, 1758 2: map[v1.ResourceName]uint64{ 1759 v1.ResourceMemory: 512 * mb, 1760 }, 1761 3: map[v1.ResourceName]uint64{ 1762 v1.ResourceMemory: 512 * mb, 1763 }, 1764 }, 1765 pod: getPod("pod1", "container1", requirementsGuaranteed), 1766 topologyHint: &topologymanager.TopologyHint{Preferred: true}, 1767 }, 1768 } 1769 1770 for _, testCase := range testCases { 1771 t.Run(testCase.description, func(t *testing.T) { 1772 t.Logf("TestStaticPolicyAllocate %s", testCase.description) 1773 p, s, err := initTests(t, &testCase, testCase.topologyHint, nil) 1774 if err != nil { 1775 t.Fatalf("Unexpected error: %v", err) 1776 } 1777 1778 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.Containers[0]) 1779 if !reflect.DeepEqual(err, testCase.expectedError) { 1780 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError) 1781 } 1782 1783 if err != nil { 1784 return 1785 } 1786 1787 assignments := s.GetMemoryAssignments() 1788 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) { 1789 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments) 1790 } 1791 1792 machineState := s.GetMachineState() 1793 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) { 1794 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState) 1795 } 1796 }) 1797 } 1798 } 1799 1800 func TestStaticPolicyAllocateWithInitContainers(t *testing.T) { 1801 testCases := []testStaticPolicy{ 1802 { 1803 description: "should re-use init containers memory, init containers requests 1Gi and 2Gi, apps containers 3Gi and 4Gi", 1804 assignments: state.ContainerMemoryAssignments{}, 1805 expectedAssignments: state.ContainerMemoryAssignments{ 1806 "pod1": map[string][]state.Block{ 1807 "initContainer1": { 1808 { 1809 NUMAAffinity: []int{0}, 1810 Type: v1.ResourceMemory, 1811 Size: 0, 1812 }, 1813 { 1814 NUMAAffinity: []int{0}, 1815 Type: hugepages1Gi, 1816 Size: 0, 1817 }, 1818 }, 1819 "initContainer2": { 1820 { 1821 NUMAAffinity: []int{0}, 1822 Type: v1.ResourceMemory, 1823 Size: 0, 1824 }, 1825 { 1826 NUMAAffinity: []int{0}, 1827 Type: hugepages1Gi, 1828 Size: 0, 1829 }, 1830 }, 1831 "container1": { 1832 { 1833 NUMAAffinity: []int{0}, 1834 Type: v1.ResourceMemory, 1835 Size: 3 * gb, 1836 }, 1837 { 1838 NUMAAffinity: []int{0}, 1839 Type: hugepages1Gi, 1840 Size: 3 * gb, 1841 }, 1842 }, 1843 "container2": { 1844 { 1845 NUMAAffinity: []int{0}, 1846 Type: v1.ResourceMemory, 1847 Size: 4 * gb, 1848 }, 1849 { 1850 NUMAAffinity: []int{0}, 1851 Type: hugepages1Gi, 1852 Size: 4 * gb, 1853 }, 1854 }, 1855 }, 1856 }, 1857 machineState: state.NUMANodeMap{ 1858 0: &state.NUMANodeState{ 1859 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1860 v1.ResourceMemory: { 1861 Allocatable: 7680 * mb, 1862 Free: 7680 * mb, 1863 Reserved: 0, 1864 SystemReserved: 512 * mb, 1865 TotalMemSize: 8 * gb, 1866 }, 1867 hugepages1Gi: { 1868 Allocatable: 8 * gb, 1869 Free: 8 * gb, 1870 Reserved: 0, 1871 SystemReserved: 0, 1872 TotalMemSize: 8 * gb, 1873 }, 1874 }, 1875 Cells: []int{0}, 1876 }, 1877 }, 1878 expectedMachineState: state.NUMANodeMap{ 1879 0: &state.NUMANodeState{ 1880 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1881 v1.ResourceMemory: { 1882 Allocatable: 7680 * mb, 1883 Free: 512 * mb, 1884 Reserved: 7 * gb, 1885 SystemReserved: 512 * mb, 1886 TotalMemSize: 8 * gb, 1887 }, 1888 hugepages1Gi: { 1889 Allocatable: 8 * gb, 1890 Free: 1 * gb, 1891 Reserved: 7 * gb, 1892 SystemReserved: 0, 1893 TotalMemSize: 8 * gb, 1894 }, 1895 }, 1896 Cells: []int{0}, 1897 NumberOfAssignments: 8, 1898 }, 1899 }, 1900 systemReserved: systemReservedMemory{ 1901 0: map[v1.ResourceName]uint64{ 1902 v1.ResourceMemory: 512 * mb, 1903 }, 1904 }, 1905 pod: getPodWithInitContainers( 1906 "pod1", 1907 []v1.Container{ 1908 { 1909 Name: "container1", 1910 Resources: v1.ResourceRequirements{ 1911 Limits: v1.ResourceList{ 1912 v1.ResourceCPU: resource.MustParse("1000Mi"), 1913 v1.ResourceMemory: resource.MustParse("3Gi"), 1914 hugepages1Gi: resource.MustParse("3Gi"), 1915 }, 1916 Requests: v1.ResourceList{ 1917 v1.ResourceCPU: resource.MustParse("1000Mi"), 1918 v1.ResourceMemory: resource.MustParse("3Gi"), 1919 hugepages1Gi: resource.MustParse("3Gi"), 1920 }, 1921 }, 1922 }, 1923 { 1924 Name: "container2", 1925 Resources: v1.ResourceRequirements{ 1926 Limits: v1.ResourceList{ 1927 v1.ResourceCPU: resource.MustParse("1000Mi"), 1928 v1.ResourceMemory: resource.MustParse("4Gi"), 1929 hugepages1Gi: resource.MustParse("4Gi"), 1930 }, 1931 Requests: v1.ResourceList{ 1932 v1.ResourceCPU: resource.MustParse("1000Mi"), 1933 v1.ResourceMemory: resource.MustParse("4Gi"), 1934 hugepages1Gi: resource.MustParse("4Gi"), 1935 }, 1936 }, 1937 }, 1938 }, 1939 []v1.Container{ 1940 { 1941 Name: "initContainer1", 1942 Resources: v1.ResourceRequirements{ 1943 Limits: v1.ResourceList{ 1944 v1.ResourceCPU: resource.MustParse("1000Mi"), 1945 v1.ResourceMemory: resource.MustParse("1Gi"), 1946 hugepages1Gi: resource.MustParse("1Gi"), 1947 }, 1948 Requests: v1.ResourceList{ 1949 v1.ResourceCPU: resource.MustParse("1000Mi"), 1950 v1.ResourceMemory: resource.MustParse("1Gi"), 1951 hugepages1Gi: resource.MustParse("1Gi"), 1952 }, 1953 }, 1954 }, 1955 { 1956 Name: "initContainer2", 1957 Resources: v1.ResourceRequirements{ 1958 Limits: v1.ResourceList{ 1959 v1.ResourceCPU: resource.MustParse("1000Mi"), 1960 v1.ResourceMemory: resource.MustParse("2Gi"), 1961 hugepages1Gi: resource.MustParse("2Gi"), 1962 }, 1963 Requests: v1.ResourceList{ 1964 v1.ResourceCPU: resource.MustParse("1000Mi"), 1965 v1.ResourceMemory: resource.MustParse("2Gi"), 1966 hugepages1Gi: resource.MustParse("2Gi"), 1967 }, 1968 }, 1969 }, 1970 }, 1971 ), 1972 topologyHint: &topologymanager.TopologyHint{}, 1973 }, 1974 { 1975 description: "should re-use init containers memory, init containers requests 4Gi and 3Gi, apps containers 2Gi and 1Gi", 1976 assignments: state.ContainerMemoryAssignments{}, 1977 expectedAssignments: state.ContainerMemoryAssignments{ 1978 "pod1": map[string][]state.Block{ 1979 "initContainer1": { 1980 { 1981 NUMAAffinity: []int{0}, 1982 Type: v1.ResourceMemory, 1983 Size: 0, 1984 }, 1985 { 1986 NUMAAffinity: []int{0}, 1987 Type: hugepages1Gi, 1988 Size: 0, 1989 }, 1990 }, 1991 "initContainer2": { 1992 { 1993 NUMAAffinity: []int{0}, 1994 Type: v1.ResourceMemory, 1995 Size: gb, 1996 }, 1997 { 1998 NUMAAffinity: []int{0}, 1999 Type: hugepages1Gi, 2000 Size: gb, 2001 }, 2002 }, 2003 "container1": { 2004 { 2005 NUMAAffinity: []int{0}, 2006 Type: v1.ResourceMemory, 2007 Size: 2 * gb, 2008 }, 2009 { 2010 NUMAAffinity: []int{0}, 2011 Type: hugepages1Gi, 2012 Size: 2 * gb, 2013 }, 2014 }, 2015 "container2": { 2016 { 2017 NUMAAffinity: []int{0}, 2018 Type: v1.ResourceMemory, 2019 Size: gb, 2020 }, 2021 { 2022 NUMAAffinity: []int{0}, 2023 Type: hugepages1Gi, 2024 Size: gb, 2025 }, 2026 }, 2027 }, 2028 }, 2029 machineState: state.NUMANodeMap{ 2030 0: &state.NUMANodeState{ 2031 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2032 v1.ResourceMemory: { 2033 Allocatable: 7680 * mb, 2034 Free: 7680 * mb, 2035 Reserved: 0, 2036 SystemReserved: 512 * mb, 2037 TotalMemSize: 8 * gb, 2038 }, 2039 hugepages1Gi: { 2040 Allocatable: 8 * gb, 2041 Free: 8 * gb, 2042 Reserved: 0, 2043 SystemReserved: 0, 2044 TotalMemSize: 8 * gb, 2045 }, 2046 }, 2047 Cells: []int{0}, 2048 }, 2049 }, 2050 expectedMachineState: state.NUMANodeMap{ 2051 0: &state.NUMANodeState{ 2052 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2053 v1.ResourceMemory: { 2054 Allocatable: 7680 * mb, 2055 Free: 3584 * mb, 2056 Reserved: 4 * gb, 2057 SystemReserved: 512 * mb, 2058 TotalMemSize: 8 * gb, 2059 }, 2060 hugepages1Gi: { 2061 Allocatable: 8 * gb, 2062 Free: 4 * gb, 2063 Reserved: 4 * gb, 2064 SystemReserved: 0, 2065 TotalMemSize: 8 * gb, 2066 }, 2067 }, 2068 Cells: []int{0}, 2069 NumberOfAssignments: 8, 2070 }, 2071 }, 2072 systemReserved: systemReservedMemory{ 2073 0: map[v1.ResourceName]uint64{ 2074 v1.ResourceMemory: 512 * mb, 2075 }, 2076 }, 2077 pod: getPodWithInitContainers( 2078 "pod1", 2079 []v1.Container{ 2080 { 2081 Name: "container1", 2082 Resources: v1.ResourceRequirements{ 2083 Limits: v1.ResourceList{ 2084 v1.ResourceCPU: resource.MustParse("1000Mi"), 2085 v1.ResourceMemory: resource.MustParse("2Gi"), 2086 hugepages1Gi: resource.MustParse("2Gi"), 2087 }, 2088 Requests: v1.ResourceList{ 2089 v1.ResourceCPU: resource.MustParse("1000Mi"), 2090 v1.ResourceMemory: resource.MustParse("2Gi"), 2091 hugepages1Gi: resource.MustParse("2Gi"), 2092 }, 2093 }, 2094 }, 2095 { 2096 Name: "container2", 2097 Resources: v1.ResourceRequirements{ 2098 Limits: v1.ResourceList{ 2099 v1.ResourceCPU: resource.MustParse("1000Mi"), 2100 v1.ResourceMemory: resource.MustParse("1Gi"), 2101 hugepages1Gi: resource.MustParse("1Gi"), 2102 }, 2103 Requests: v1.ResourceList{ 2104 v1.ResourceCPU: resource.MustParse("1000Mi"), 2105 v1.ResourceMemory: resource.MustParse("1Gi"), 2106 hugepages1Gi: resource.MustParse("1Gi"), 2107 }, 2108 }, 2109 }, 2110 }, 2111 []v1.Container{ 2112 { 2113 Name: "initContainer1", 2114 Resources: v1.ResourceRequirements{ 2115 Limits: v1.ResourceList{ 2116 v1.ResourceCPU: resource.MustParse("1000Mi"), 2117 v1.ResourceMemory: resource.MustParse("4Gi"), 2118 hugepages1Gi: resource.MustParse("4Gi"), 2119 }, 2120 Requests: v1.ResourceList{ 2121 v1.ResourceCPU: resource.MustParse("1000Mi"), 2122 v1.ResourceMemory: resource.MustParse("4Gi"), 2123 hugepages1Gi: resource.MustParse("4Gi"), 2124 }, 2125 }, 2126 }, 2127 { 2128 Name: "initContainer2", 2129 Resources: v1.ResourceRequirements{ 2130 Limits: v1.ResourceList{ 2131 v1.ResourceCPU: resource.MustParse("1000Mi"), 2132 v1.ResourceMemory: resource.MustParse("3Gi"), 2133 hugepages1Gi: resource.MustParse("3Gi"), 2134 }, 2135 Requests: v1.ResourceList{ 2136 v1.ResourceCPU: resource.MustParse("1000Mi"), 2137 v1.ResourceMemory: resource.MustParse("3Gi"), 2138 hugepages1Gi: resource.MustParse("3Gi"), 2139 }, 2140 }, 2141 }, 2142 }, 2143 ), 2144 topologyHint: &topologymanager.TopologyHint{}, 2145 }, 2146 { 2147 description: "should re-use init containers memory, init containers requests 7Gi and 4Gi, apps containers 4Gi and 3Gi", 2148 assignments: state.ContainerMemoryAssignments{}, 2149 expectedAssignments: state.ContainerMemoryAssignments{ 2150 "pod1": map[string][]state.Block{ 2151 "initContainer1": { 2152 { 2153 NUMAAffinity: []int{0}, 2154 Type: v1.ResourceMemory, 2155 Size: 0, 2156 }, 2157 { 2158 NUMAAffinity: []int{0}, 2159 Type: hugepages1Gi, 2160 Size: 0, 2161 }, 2162 }, 2163 "initContainer2": { 2164 { 2165 NUMAAffinity: []int{0}, 2166 Type: v1.ResourceMemory, 2167 Size: 0, 2168 }, 2169 { 2170 NUMAAffinity: []int{0}, 2171 Type: hugepages1Gi, 2172 Size: 0, 2173 }, 2174 }, 2175 "container1": { 2176 { 2177 NUMAAffinity: []int{0}, 2178 Type: v1.ResourceMemory, 2179 Size: 4 * gb, 2180 }, 2181 { 2182 NUMAAffinity: []int{0}, 2183 Type: hugepages1Gi, 2184 Size: 4 * gb, 2185 }, 2186 }, 2187 "container2": { 2188 { 2189 NUMAAffinity: []int{0}, 2190 Type: v1.ResourceMemory, 2191 Size: 3 * gb, 2192 }, 2193 { 2194 NUMAAffinity: []int{0}, 2195 Type: hugepages1Gi, 2196 Size: 3 * gb, 2197 }, 2198 }, 2199 }, 2200 }, 2201 machineState: state.NUMANodeMap{ 2202 0: &state.NUMANodeState{ 2203 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2204 v1.ResourceMemory: { 2205 Allocatable: 7680 * mb, 2206 Free: 7680 * mb, 2207 Reserved: 0, 2208 SystemReserved: 512 * mb, 2209 TotalMemSize: 8 * gb, 2210 }, 2211 hugepages1Gi: { 2212 Allocatable: 8 * gb, 2213 Free: 8 * gb, 2214 Reserved: 0, 2215 SystemReserved: 0, 2216 TotalMemSize: 8 * gb, 2217 }, 2218 }, 2219 Cells: []int{0}, 2220 }, 2221 }, 2222 expectedMachineState: state.NUMANodeMap{ 2223 0: &state.NUMANodeState{ 2224 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2225 v1.ResourceMemory: { 2226 Allocatable: 7680 * mb, 2227 Free: 512 * mb, 2228 Reserved: 7 * gb, 2229 SystemReserved: 512 * mb, 2230 TotalMemSize: 8 * gb, 2231 }, 2232 hugepages1Gi: { 2233 Allocatable: 8 * gb, 2234 Free: 1 * gb, 2235 Reserved: 7 * gb, 2236 SystemReserved: 0, 2237 TotalMemSize: 8 * gb, 2238 }, 2239 }, 2240 Cells: []int{0}, 2241 NumberOfAssignments: 8, 2242 }, 2243 }, 2244 systemReserved: systemReservedMemory{ 2245 0: map[v1.ResourceName]uint64{ 2246 v1.ResourceMemory: 512 * mb, 2247 }, 2248 }, 2249 pod: getPodWithInitContainers( 2250 "pod1", 2251 []v1.Container{ 2252 { 2253 Name: "container1", 2254 Resources: v1.ResourceRequirements{ 2255 Limits: v1.ResourceList{ 2256 v1.ResourceCPU: resource.MustParse("1000Mi"), 2257 v1.ResourceMemory: resource.MustParse("4Gi"), 2258 hugepages1Gi: resource.MustParse("4Gi"), 2259 }, 2260 Requests: v1.ResourceList{ 2261 v1.ResourceCPU: resource.MustParse("1000Mi"), 2262 v1.ResourceMemory: resource.MustParse("4Gi"), 2263 hugepages1Gi: resource.MustParse("4Gi"), 2264 }, 2265 }, 2266 }, 2267 { 2268 Name: "container2", 2269 Resources: v1.ResourceRequirements{ 2270 Limits: v1.ResourceList{ 2271 v1.ResourceCPU: resource.MustParse("1000Mi"), 2272 v1.ResourceMemory: resource.MustParse("3Gi"), 2273 hugepages1Gi: resource.MustParse("3Gi"), 2274 }, 2275 Requests: v1.ResourceList{ 2276 v1.ResourceCPU: resource.MustParse("1000Mi"), 2277 v1.ResourceMemory: resource.MustParse("3Gi"), 2278 hugepages1Gi: resource.MustParse("3Gi"), 2279 }, 2280 }, 2281 }, 2282 }, 2283 []v1.Container{ 2284 { 2285 Name: "initContainer1", 2286 Resources: v1.ResourceRequirements{ 2287 Limits: v1.ResourceList{ 2288 v1.ResourceCPU: resource.MustParse("1000Mi"), 2289 v1.ResourceMemory: resource.MustParse("7Gi"), 2290 hugepages1Gi: resource.MustParse("7Gi"), 2291 }, 2292 Requests: v1.ResourceList{ 2293 v1.ResourceCPU: resource.MustParse("1000Mi"), 2294 v1.ResourceMemory: resource.MustParse("7Gi"), 2295 hugepages1Gi: resource.MustParse("7Gi"), 2296 }, 2297 }, 2298 }, 2299 { 2300 Name: "initContainer2", 2301 Resources: v1.ResourceRequirements{ 2302 Limits: v1.ResourceList{ 2303 v1.ResourceCPU: resource.MustParse("1000Mi"), 2304 v1.ResourceMemory: resource.MustParse("4Gi"), 2305 hugepages1Gi: resource.MustParse("4Gi"), 2306 }, 2307 Requests: v1.ResourceList{ 2308 v1.ResourceCPU: resource.MustParse("1000Mi"), 2309 v1.ResourceMemory: resource.MustParse("4Gi"), 2310 hugepages1Gi: resource.MustParse("4Gi"), 2311 }, 2312 }, 2313 }, 2314 }, 2315 ), 2316 topologyHint: &topologymanager.TopologyHint{}, 2317 }, 2318 { 2319 description: "should re-use init containers memory, init containers requests 7Gi and 4Gi, apps containers 5Gi and 2Gi", 2320 assignments: state.ContainerMemoryAssignments{}, 2321 initContainersReusableMemory: reusableMemory{"pod0": map[string]map[v1.ResourceName]uint64{}}, 2322 expectedAssignments: state.ContainerMemoryAssignments{ 2323 "pod1": map[string][]state.Block{ 2324 "initContainer1": { 2325 { 2326 NUMAAffinity: []int{0}, 2327 Type: v1.ResourceMemory, 2328 Size: 0, 2329 }, 2330 { 2331 NUMAAffinity: []int{0}, 2332 Type: hugepages1Gi, 2333 Size: 0, 2334 }, 2335 }, 2336 "initContainer2": { 2337 { 2338 NUMAAffinity: []int{0}, 2339 Type: v1.ResourceMemory, 2340 Size: 0, 2341 }, 2342 { 2343 NUMAAffinity: []int{0}, 2344 Type: hugepages1Gi, 2345 Size: 0, 2346 }, 2347 }, 2348 "container1": { 2349 { 2350 NUMAAffinity: []int{0}, 2351 Type: v1.ResourceMemory, 2352 Size: 5 * gb, 2353 }, 2354 { 2355 NUMAAffinity: []int{0}, 2356 Type: hugepages1Gi, 2357 Size: 5 * gb, 2358 }, 2359 }, 2360 "container2": { 2361 { 2362 NUMAAffinity: []int{0}, 2363 Type: v1.ResourceMemory, 2364 Size: 2 * gb, 2365 }, 2366 { 2367 NUMAAffinity: []int{0}, 2368 Type: hugepages1Gi, 2369 Size: 2 * gb, 2370 }, 2371 }, 2372 }, 2373 }, 2374 machineState: state.NUMANodeMap{ 2375 0: &state.NUMANodeState{ 2376 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2377 v1.ResourceMemory: { 2378 Allocatable: 10240 * mb, 2379 Free: 10240 * mb, 2380 Reserved: 0, 2381 SystemReserved: 512 * mb, 2382 TotalMemSize: 10 * gb, 2383 }, 2384 hugepages1Gi: { 2385 Allocatable: 10 * gb, 2386 Free: 10 * gb, 2387 Reserved: 0, 2388 SystemReserved: 0, 2389 TotalMemSize: 10 * gb, 2390 }, 2391 }, 2392 Cells: []int{0}, 2393 }, 2394 }, 2395 expectedMachineState: state.NUMANodeMap{ 2396 0: &state.NUMANodeState{ 2397 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2398 v1.ResourceMemory: { 2399 Allocatable: 10240 * mb, 2400 Free: 3072 * mb, 2401 Reserved: 7 * gb, 2402 SystemReserved: 512 * mb, 2403 TotalMemSize: 10 * gb, 2404 }, 2405 hugepages1Gi: { 2406 Allocatable: 10 * gb, 2407 Free: 3 * gb, 2408 Reserved: 7 * gb, 2409 SystemReserved: 0, 2410 TotalMemSize: 10 * gb, 2411 }, 2412 }, 2413 Cells: []int{0}, 2414 NumberOfAssignments: 8, 2415 }, 2416 }, 2417 systemReserved: systemReservedMemory{ 2418 0: map[v1.ResourceName]uint64{ 2419 v1.ResourceMemory: 512 * mb, 2420 }, 2421 }, 2422 pod: getPodWithInitContainers( 2423 "pod1", 2424 []v1.Container{ 2425 { 2426 Name: "container1", 2427 Resources: v1.ResourceRequirements{ 2428 Limits: v1.ResourceList{ 2429 v1.ResourceCPU: resource.MustParse("1000Mi"), 2430 v1.ResourceMemory: resource.MustParse("5Gi"), 2431 hugepages1Gi: resource.MustParse("5Gi"), 2432 }, 2433 Requests: v1.ResourceList{ 2434 v1.ResourceCPU: resource.MustParse("1000Mi"), 2435 v1.ResourceMemory: resource.MustParse("5Gi"), 2436 hugepages1Gi: resource.MustParse("5Gi"), 2437 }, 2438 }, 2439 }, 2440 { 2441 Name: "container2", 2442 Resources: v1.ResourceRequirements{ 2443 Limits: v1.ResourceList{ 2444 v1.ResourceCPU: resource.MustParse("1000Mi"), 2445 v1.ResourceMemory: resource.MustParse("2Gi"), 2446 hugepages1Gi: resource.MustParse("2Gi"), 2447 }, 2448 Requests: v1.ResourceList{ 2449 v1.ResourceCPU: resource.MustParse("1000Mi"), 2450 v1.ResourceMemory: resource.MustParse("2Gi"), 2451 hugepages1Gi: resource.MustParse("2Gi"), 2452 }, 2453 }, 2454 }, 2455 }, 2456 []v1.Container{ 2457 { 2458 Name: "initContainer1", 2459 Resources: v1.ResourceRequirements{ 2460 Limits: v1.ResourceList{ 2461 v1.ResourceCPU: resource.MustParse("1000Mi"), 2462 v1.ResourceMemory: resource.MustParse("7Gi"), 2463 hugepages1Gi: resource.MustParse("7Gi"), 2464 }, 2465 Requests: v1.ResourceList{ 2466 v1.ResourceCPU: resource.MustParse("1000Mi"), 2467 v1.ResourceMemory: resource.MustParse("7Gi"), 2468 hugepages1Gi: resource.MustParse("7Gi"), 2469 }, 2470 }, 2471 }, 2472 { 2473 Name: "initContainer2", 2474 Resources: v1.ResourceRequirements{ 2475 Limits: v1.ResourceList{ 2476 v1.ResourceCPU: resource.MustParse("1000Mi"), 2477 v1.ResourceMemory: resource.MustParse("4Gi"), 2478 hugepages1Gi: resource.MustParse("4Gi"), 2479 }, 2480 Requests: v1.ResourceList{ 2481 v1.ResourceCPU: resource.MustParse("1000Mi"), 2482 v1.ResourceMemory: resource.MustParse("4Gi"), 2483 hugepages1Gi: resource.MustParse("4Gi"), 2484 }, 2485 }, 2486 }, 2487 }, 2488 ), 2489 topologyHint: &topologymanager.TopologyHint{}, 2490 }, 2491 } 2492 2493 for _, testCase := range testCases { 2494 t.Run(testCase.description, func(t *testing.T) { 2495 klog.InfoS("TestStaticPolicyAllocateWithInitContainers", "name", testCase.description) 2496 p, s, err := initTests(t, &testCase, testCase.topologyHint, testCase.initContainersReusableMemory) 2497 if err != nil { 2498 t.Fatalf("Unexpected error: %v", err) 2499 } 2500 2501 for i := range testCase.pod.Spec.InitContainers { 2502 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.InitContainers[i]) 2503 if !reflect.DeepEqual(err, testCase.expectedError) { 2504 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError) 2505 } 2506 } 2507 2508 for i := range testCase.pod.Spec.Containers { 2509 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.Containers[i]) 2510 if !reflect.DeepEqual(err, testCase.expectedError) { 2511 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError) 2512 } 2513 } 2514 2515 assignments := s.GetMemoryAssignments() 2516 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) { 2517 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments) 2518 } 2519 2520 machineState := s.GetMachineState() 2521 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) { 2522 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState) 2523 } 2524 }) 2525 } 2526 } 2527 2528 func TestStaticPolicyAllocateWithRestartableInitContainers(t *testing.T) { 2529 testCases := []testStaticPolicy{ 2530 { 2531 description: "should do nothing once containers already exist under the state file", 2532 assignments: state.ContainerMemoryAssignments{ 2533 "pod1": map[string][]state.Block{ 2534 "initContainer1": { 2535 { 2536 NUMAAffinity: []int{0}, 2537 Type: v1.ResourceMemory, 2538 Size: gb, 2539 }, 2540 }, 2541 "container1": { 2542 { 2543 NUMAAffinity: []int{0}, 2544 Type: v1.ResourceMemory, 2545 Size: gb, 2546 }, 2547 }, 2548 }, 2549 }, 2550 expectedAssignments: state.ContainerMemoryAssignments{ 2551 "pod1": map[string][]state.Block{ 2552 "initContainer1": { 2553 { 2554 NUMAAffinity: []int{0}, 2555 Type: v1.ResourceMemory, 2556 Size: gb, 2557 }, 2558 }, 2559 "container1": { 2560 { 2561 NUMAAffinity: []int{0}, 2562 Type: v1.ResourceMemory, 2563 Size: gb, 2564 }, 2565 }, 2566 }, 2567 }, 2568 machineState: state.NUMANodeMap{ 2569 0: &state.NUMANodeState{ 2570 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2571 v1.ResourceMemory: { 2572 Allocatable: 2560 * mb, 2573 Free: 512 * mb, 2574 Reserved: 2048 * mb, 2575 SystemReserved: 512 * mb, 2576 TotalMemSize: 3 * gb, 2577 }, 2578 hugepages1Gi: { 2579 Allocatable: 2 * gb, 2580 Free: 2 * gb, 2581 Reserved: 0, 2582 SystemReserved: 0, 2583 TotalMemSize: 2 * gb, 2584 }, 2585 }, 2586 Cells: []int{}, 2587 }, 2588 }, 2589 expectedMachineState: state.NUMANodeMap{ 2590 0: &state.NUMANodeState{ 2591 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2592 v1.ResourceMemory: { 2593 Allocatable: 2560 * mb, 2594 Free: 512 * mb, 2595 Reserved: 2048 * mb, 2596 SystemReserved: 512 * mb, 2597 TotalMemSize: 3 * gb, 2598 }, 2599 hugepages1Gi: { 2600 Allocatable: 2 * gb, 2601 Free: 2 * gb, 2602 Reserved: 0, 2603 SystemReserved: 0, 2604 TotalMemSize: 2 * gb, 2605 }, 2606 }, 2607 Cells: []int{}, 2608 }, 2609 }, 2610 systemReserved: systemReservedMemory{ 2611 0: map[v1.ResourceName]uint64{ 2612 v1.ResourceMemory: 512 * mb, 2613 }, 2614 }, 2615 pod: getPodWithInitContainers( 2616 "pod1", 2617 []v1.Container{ 2618 { 2619 Name: "container1", 2620 Resources: *requirementsGuaranteed, 2621 }, 2622 }, 2623 []v1.Container{ 2624 { 2625 Name: "initContainer1", 2626 Resources: *requirementsGuaranteed, 2627 RestartPolicy: &containerRestartPolicyAlways, 2628 }, 2629 }, 2630 ), 2631 expectedTopologyHints: nil, 2632 topologyHint: &topologymanager.TopologyHint{}, 2633 }, 2634 { 2635 description: "should not re-use restartable init containers memory", 2636 assignments: state.ContainerMemoryAssignments{}, 2637 expectedAssignments: state.ContainerMemoryAssignments{ 2638 "pod1": map[string][]state.Block{ 2639 "initContainer1": { 2640 { 2641 NUMAAffinity: []int{0}, 2642 Type: v1.ResourceMemory, 2643 Size: 0, 2644 }, 2645 { 2646 NUMAAffinity: []int{0}, 2647 Type: hugepages1Gi, 2648 Size: 0, 2649 }, 2650 }, 2651 "restartableInitContainer2": { 2652 { 2653 NUMAAffinity: []int{0}, 2654 Type: v1.ResourceMemory, 2655 Size: 2 * gb, 2656 }, 2657 { 2658 NUMAAffinity: []int{0}, 2659 Type: hugepages1Gi, 2660 Size: 2 * gb, 2661 }, 2662 }, 2663 "initContainer3": { 2664 { 2665 NUMAAffinity: []int{0}, 2666 Type: v1.ResourceMemory, 2667 Size: 0, 2668 }, 2669 { 2670 NUMAAffinity: []int{0}, 2671 Type: hugepages1Gi, 2672 Size: 0, 2673 }, 2674 }, 2675 "restartableInitContainer4": { 2676 { 2677 NUMAAffinity: []int{0}, 2678 Type: v1.ResourceMemory, 2679 Size: 4 * gb, 2680 }, 2681 { 2682 NUMAAffinity: []int{0}, 2683 Type: hugepages1Gi, 2684 Size: 4 * gb, 2685 }, 2686 }, 2687 "container1": { 2688 { 2689 NUMAAffinity: []int{0}, 2690 Type: v1.ResourceMemory, 2691 Size: 1 * gb, 2692 }, 2693 { 2694 NUMAAffinity: []int{0}, 2695 Type: hugepages1Gi, 2696 Size: 1 * gb, 2697 }, 2698 }, 2699 }, 2700 }, 2701 machineState: state.NUMANodeMap{ 2702 0: &state.NUMANodeState{ 2703 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2704 v1.ResourceMemory: { 2705 Allocatable: 7 * gb, 2706 Free: 7 * gb, 2707 Reserved: 0, 2708 SystemReserved: 512 * mb, 2709 TotalMemSize: 7680 * mb, 2710 }, 2711 hugepages1Gi: { 2712 Allocatable: 7 * gb, 2713 Free: 7 * gb, 2714 Reserved: 0, 2715 SystemReserved: 0, 2716 TotalMemSize: 7 * gb, 2717 }, 2718 }, 2719 Cells: []int{0}, 2720 }, 2721 }, 2722 expectedMachineState: state.NUMANodeMap{ 2723 0: &state.NUMANodeState{ 2724 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2725 v1.ResourceMemory: { 2726 Allocatable: 7 * gb, 2727 Free: 0, 2728 Reserved: 7 * gb, 2729 SystemReserved: 512 * mb, 2730 TotalMemSize: 7680 * mb, 2731 }, 2732 hugepages1Gi: { 2733 Allocatable: 7 * gb, 2734 Free: 0, 2735 Reserved: 7 * gb, 2736 SystemReserved: 0, 2737 TotalMemSize: 7 * gb, 2738 }, 2739 }, 2740 Cells: []int{0}, 2741 NumberOfAssignments: 10, 2742 }, 2743 }, 2744 systemReserved: systemReservedMemory{ 2745 0: map[v1.ResourceName]uint64{ 2746 v1.ResourceMemory: 512 * mb, 2747 }, 2748 }, 2749 pod: getPodWithInitContainers( 2750 "pod1", 2751 []v1.Container{ 2752 { 2753 Name: "container1", 2754 Resources: *requirementsGuaranteed, 2755 }, 2756 }, 2757 []v1.Container{ 2758 { 2759 Name: "initContainer1", 2760 Resources: v1.ResourceRequirements{ 2761 Limits: v1.ResourceList{ 2762 v1.ResourceCPU: resource.MustParse("1000Mi"), 2763 v1.ResourceMemory: resource.MustParse("1Gi"), 2764 hugepages1Gi: resource.MustParse("1Gi"), 2765 }, 2766 Requests: v1.ResourceList{ 2767 v1.ResourceCPU: resource.MustParse("1000Mi"), 2768 v1.ResourceMemory: resource.MustParse("1Gi"), 2769 hugepages1Gi: resource.MustParse("1Gi"), 2770 }, 2771 }, 2772 }, 2773 { 2774 Name: "restartableInitContainer2", 2775 Resources: v1.ResourceRequirements{ 2776 Limits: v1.ResourceList{ 2777 v1.ResourceCPU: resource.MustParse("1000Mi"), 2778 v1.ResourceMemory: resource.MustParse("2Gi"), 2779 hugepages1Gi: resource.MustParse("2Gi"), 2780 }, 2781 Requests: v1.ResourceList{ 2782 v1.ResourceCPU: resource.MustParse("1000Mi"), 2783 v1.ResourceMemory: resource.MustParse("2Gi"), 2784 hugepages1Gi: resource.MustParse("2Gi"), 2785 }, 2786 }, 2787 RestartPolicy: &containerRestartPolicyAlways, 2788 }, 2789 { 2790 Name: "initContainer3", 2791 Resources: v1.ResourceRequirements{ 2792 Limits: v1.ResourceList{ 2793 v1.ResourceCPU: resource.MustParse("1000Mi"), 2794 v1.ResourceMemory: resource.MustParse("3Gi"), 2795 hugepages1Gi: resource.MustParse("3Gi"), 2796 }, 2797 Requests: v1.ResourceList{ 2798 v1.ResourceCPU: resource.MustParse("1000Mi"), 2799 v1.ResourceMemory: resource.MustParse("3Gi"), 2800 hugepages1Gi: resource.MustParse("3Gi"), 2801 }, 2802 }, 2803 }, 2804 { 2805 Name: "restartableInitContainer4", 2806 Resources: v1.ResourceRequirements{ 2807 Limits: v1.ResourceList{ 2808 v1.ResourceCPU: resource.MustParse("1000Mi"), 2809 v1.ResourceMemory: resource.MustParse("4Gi"), 2810 hugepages1Gi: resource.MustParse("4Gi"), 2811 }, 2812 Requests: v1.ResourceList{ 2813 v1.ResourceCPU: resource.MustParse("1000Mi"), 2814 v1.ResourceMemory: resource.MustParse("4Gi"), 2815 hugepages1Gi: resource.MustParse("4Gi"), 2816 }, 2817 }, 2818 RestartPolicy: &containerRestartPolicyAlways, 2819 }, 2820 }, 2821 ), 2822 topologyHint: &topologymanager.TopologyHint{}, 2823 }, 2824 } 2825 2826 for _, testCase := range testCases { 2827 t.Run(testCase.description, func(t *testing.T) { 2828 klog.InfoS("TestStaticPolicyAllocateWithRestartableInitContainers", "name", testCase.description) 2829 p, s, err := initTests(t, &testCase, testCase.topologyHint, testCase.initContainersReusableMemory) 2830 if err != nil { 2831 t.Fatalf("Unexpected error: %v", err) 2832 } 2833 2834 for i := range testCase.pod.Spec.InitContainers { 2835 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.InitContainers[i]) 2836 if !reflect.DeepEqual(err, testCase.expectedError) { 2837 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError) 2838 } 2839 } 2840 2841 if err != nil { 2842 return 2843 } 2844 2845 for i := range testCase.pod.Spec.Containers { 2846 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.Containers[i]) 2847 if err != nil { 2848 t.Fatalf("Unexpected error: %v", err) 2849 } 2850 } 2851 2852 assignments := s.GetMemoryAssignments() 2853 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) { 2854 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments) 2855 } 2856 2857 machineState := s.GetMachineState() 2858 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) { 2859 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState) 2860 } 2861 }) 2862 } 2863 } 2864 2865 func TestStaticPolicyRemoveContainer(t *testing.T) { 2866 testCases := []testStaticPolicy{ 2867 { 2868 description: "should do nothing when the container does not exist under the state", 2869 expectedAssignments: state.ContainerMemoryAssignments{}, 2870 machineState: state.NUMANodeMap{ 2871 0: &state.NUMANodeState{ 2872 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2873 v1.ResourceMemory: { 2874 Allocatable: 1536 * mb, 2875 Free: 1536 * mb, 2876 Reserved: 0, 2877 SystemReserved: 512 * mb, 2878 TotalMemSize: 2 * gb, 2879 }, 2880 hugepages1Gi: { 2881 Allocatable: gb, 2882 Free: gb, 2883 Reserved: 0, 2884 SystemReserved: 0, 2885 TotalMemSize: gb, 2886 }, 2887 }, 2888 Cells: []int{}, 2889 }, 2890 }, 2891 expectedMachineState: state.NUMANodeMap{ 2892 0: &state.NUMANodeState{ 2893 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2894 v1.ResourceMemory: { 2895 Allocatable: 1536 * mb, 2896 Free: 1536 * mb, 2897 Reserved: 0, 2898 SystemReserved: 512 * mb, 2899 TotalMemSize: 2 * gb, 2900 }, 2901 hugepages1Gi: { 2902 Allocatable: gb, 2903 Free: gb, 2904 Reserved: 0, 2905 SystemReserved: 0, 2906 TotalMemSize: gb, 2907 }, 2908 }, 2909 Cells: []int{}, 2910 }, 2911 }, 2912 systemReserved: systemReservedMemory{ 2913 0: map[v1.ResourceName]uint64{ 2914 v1.ResourceMemory: 512 * mb, 2915 }, 2916 }, 2917 }, 2918 { 2919 description: "should delete the container assignment and update the machine state", 2920 assignments: state.ContainerMemoryAssignments{ 2921 "pod1": map[string][]state.Block{ 2922 "container1": { 2923 { 2924 NUMAAffinity: []int{0}, 2925 Type: v1.ResourceMemory, 2926 Size: gb, 2927 }, 2928 { 2929 NUMAAffinity: []int{0}, 2930 Type: hugepages1Gi, 2931 Size: gb, 2932 }, 2933 }, 2934 }, 2935 }, 2936 expectedAssignments: state.ContainerMemoryAssignments{}, 2937 machineState: state.NUMANodeMap{ 2938 0: &state.NUMANodeState{ 2939 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2940 v1.ResourceMemory: { 2941 Allocatable: 1536 * mb, 2942 Free: 512 * mb, 2943 Reserved: 1024 * mb, 2944 SystemReserved: 512 * mb, 2945 TotalMemSize: 2 * gb, 2946 }, 2947 hugepages1Gi: { 2948 Allocatable: gb, 2949 Free: 0, 2950 Reserved: gb, 2951 SystemReserved: 0, 2952 TotalMemSize: gb, 2953 }, 2954 }, 2955 NumberOfAssignments: 2, 2956 Cells: []int{0}, 2957 }, 2958 }, 2959 expectedMachineState: state.NUMANodeMap{ 2960 0: &state.NUMANodeState{ 2961 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2962 v1.ResourceMemory: { 2963 Allocatable: 1536 * mb, 2964 Free: 1536 * mb, 2965 Reserved: 0, 2966 SystemReserved: 512 * mb, 2967 TotalMemSize: 2 * gb, 2968 }, 2969 hugepages1Gi: { 2970 Allocatable: gb, 2971 Free: gb, 2972 Reserved: 0, 2973 SystemReserved: 0, 2974 TotalMemSize: gb, 2975 }, 2976 }, 2977 Cells: []int{0}, 2978 NumberOfAssignments: 0, 2979 }, 2980 }, 2981 systemReserved: systemReservedMemory{ 2982 0: map[v1.ResourceName]uint64{ 2983 v1.ResourceMemory: 512 * mb, 2984 }, 2985 }, 2986 }, 2987 { 2988 description: "should delete the cross NUMA container assignment and update the machine state", 2989 assignments: state.ContainerMemoryAssignments{ 2990 "pod1": map[string][]state.Block{ 2991 "container1": { 2992 { 2993 NUMAAffinity: []int{0, 1}, 2994 Type: v1.ResourceMemory, 2995 Size: gb, 2996 }, 2997 { 2998 NUMAAffinity: []int{0, 1}, 2999 Type: hugepages1Gi, 3000 Size: gb, 3001 }, 3002 }, 3003 }, 3004 }, 3005 expectedAssignments: state.ContainerMemoryAssignments{}, 3006 machineState: state.NUMANodeMap{ 3007 0: &state.NUMANodeState{ 3008 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3009 v1.ResourceMemory: { 3010 Allocatable: 512 * mb, 3011 Free: 0, 3012 Reserved: 512 * mb, 3013 SystemReserved: 512 * mb, 3014 TotalMemSize: gb, 3015 }, 3016 hugepages1Gi: { 3017 Allocatable: gb, 3018 Free: 0, 3019 Reserved: gb, 3020 SystemReserved: 0, 3021 TotalMemSize: gb, 3022 }, 3023 }, 3024 NumberOfAssignments: 2, 3025 Cells: []int{0, 1}, 3026 }, 3027 1: &state.NUMANodeState{ 3028 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3029 v1.ResourceMemory: { 3030 Allocatable: 512 * mb, 3031 Free: 0, 3032 Reserved: 512 * mb, 3033 SystemReserved: 512 * mb, 3034 TotalMemSize: gb, 3035 }, 3036 hugepages1Gi: { 3037 Allocatable: gb, 3038 Free: gb, 3039 Reserved: 0, 3040 SystemReserved: 0, 3041 TotalMemSize: gb, 3042 }, 3043 }, 3044 NumberOfAssignments: 2, 3045 Cells: []int{0, 1}, 3046 }, 3047 }, 3048 expectedMachineState: state.NUMANodeMap{ 3049 0: &state.NUMANodeState{ 3050 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3051 v1.ResourceMemory: { 3052 Allocatable: 512 * mb, 3053 Free: 512 * mb, 3054 Reserved: 0, 3055 SystemReserved: 512 * mb, 3056 TotalMemSize: gb, 3057 }, 3058 hugepages1Gi: { 3059 Allocatable: gb, 3060 Free: gb, 3061 Reserved: 0, 3062 SystemReserved: 0, 3063 TotalMemSize: gb, 3064 }, 3065 }, 3066 NumberOfAssignments: 0, 3067 Cells: []int{0}, 3068 }, 3069 1: &state.NUMANodeState{ 3070 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3071 v1.ResourceMemory: { 3072 Allocatable: 512 * mb, 3073 Free: 512 * mb, 3074 Reserved: 0, 3075 SystemReserved: 512 * mb, 3076 TotalMemSize: gb, 3077 }, 3078 hugepages1Gi: { 3079 Allocatable: gb, 3080 Free: gb, 3081 Reserved: 0, 3082 SystemReserved: 0, 3083 TotalMemSize: gb, 3084 }, 3085 }, 3086 NumberOfAssignments: 0, 3087 Cells: []int{1}, 3088 }, 3089 }, 3090 systemReserved: systemReservedMemory{ 3091 0: map[v1.ResourceName]uint64{ 3092 v1.ResourceMemory: 512 * mb, 3093 }, 3094 1: map[v1.ResourceName]uint64{ 3095 v1.ResourceMemory: 512 * mb, 3096 }, 3097 }, 3098 }, 3099 } 3100 3101 for _, testCase := range testCases { 3102 t.Run(testCase.description, func(t *testing.T) { 3103 p, s, err := initTests(t, &testCase, nil, nil) 3104 if err != nil { 3105 t.Fatalf("Unexpected error: %v", err) 3106 } 3107 3108 p.RemoveContainer(s, "pod1", "container1") 3109 assignments := s.GetMemoryAssignments() 3110 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) { 3111 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments) 3112 } 3113 3114 machineState := s.GetMachineState() 3115 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) { 3116 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState) 3117 } 3118 }) 3119 } 3120 } 3121 3122 func TestStaticPolicyGetTopologyHints(t *testing.T) { 3123 testCases := []testStaticPolicy{ 3124 { 3125 description: "should not provide topology hints for non-guaranteed pods", 3126 pod: getPod("pod1", "container1", requirementsBurstable), 3127 systemReserved: systemReservedMemory{ 3128 0: map[v1.ResourceName]uint64{ 3129 v1.ResourceMemory: 512 * mb, 3130 }, 3131 }, 3132 expectedTopologyHints: nil, 3133 }, 3134 { 3135 description: "should provide topology hints based on the existent memory assignment", 3136 assignments: state.ContainerMemoryAssignments{ 3137 "pod1": map[string][]state.Block{ 3138 "container1": { 3139 { 3140 NUMAAffinity: []int{0}, 3141 Type: v1.ResourceMemory, 3142 Size: gb, 3143 }, 3144 { 3145 NUMAAffinity: []int{0}, 3146 Type: hugepages1Gi, 3147 Size: gb, 3148 }, 3149 }, 3150 }, 3151 }, 3152 pod: getPod("pod1", "container1", requirementsGuaranteed), 3153 systemReserved: systemReservedMemory{ 3154 0: map[v1.ResourceName]uint64{ 3155 v1.ResourceMemory: 512 * mb, 3156 }, 3157 }, 3158 expectedTopologyHints: map[string][]topologymanager.TopologyHint{ 3159 string(v1.ResourceMemory): { 3160 { 3161 NUMANodeAffinity: newNUMAAffinity(0), 3162 Preferred: true, 3163 }, 3164 }, 3165 string(hugepages1Gi): { 3166 { 3167 NUMANodeAffinity: newNUMAAffinity(0), 3168 Preferred: true, 3169 }, 3170 }, 3171 }, 3172 }, 3173 { 3174 description: "should calculate new topology hints, when the container does not exist under assignments", 3175 assignments: state.ContainerMemoryAssignments{ 3176 "pod1": map[string][]state.Block{ 3177 "container1": { 3178 { 3179 NUMAAffinity: []int{0, 1}, 3180 Type: v1.ResourceMemory, 3181 Size: 2 * gb, 3182 }, 3183 { 3184 NUMAAffinity: []int{0, 1}, 3185 Type: hugepages1Gi, 3186 Size: 2 * gb, 3187 }, 3188 }, 3189 }, 3190 }, 3191 machineState: state.NUMANodeMap{ 3192 0: &state.NUMANodeState{ 3193 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3194 v1.ResourceMemory: { 3195 Allocatable: 1536 * mb, 3196 Free: 0, 3197 Reserved: 1536 * mb, 3198 SystemReserved: 512 * mb, 3199 TotalMemSize: 2 * gb, 3200 }, 3201 hugepages1Gi: { 3202 Allocatable: gb, 3203 Free: 0, 3204 Reserved: gb, 3205 SystemReserved: 0, 3206 TotalMemSize: gb, 3207 }, 3208 }, 3209 Cells: []int{0, 1}, 3210 NumberOfAssignments: 2, 3211 }, 3212 1: &state.NUMANodeState{ 3213 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3214 v1.ResourceMemory: { 3215 Allocatable: 1536 * mb, 3216 Free: gb, 3217 Reserved: 512 * mb, 3218 SystemReserved: 512 * mb, 3219 TotalMemSize: 2 * gb, 3220 }, 3221 hugepages1Gi: { 3222 Allocatable: gb, 3223 Free: 0, 3224 Reserved: gb, 3225 SystemReserved: 0, 3226 TotalMemSize: gb, 3227 }, 3228 }, 3229 Cells: []int{0, 1}, 3230 NumberOfAssignments: 2, 3231 }, 3232 2: &state.NUMANodeState{ 3233 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3234 v1.ResourceMemory: { 3235 Allocatable: 1536 * mb, 3236 Free: 1536 * mb, 3237 Reserved: 0, 3238 SystemReserved: 512 * mb, 3239 TotalMemSize: 2 * gb, 3240 }, 3241 hugepages1Gi: { 3242 Allocatable: gb, 3243 Free: gb, 3244 Reserved: 0, 3245 SystemReserved: 0, 3246 TotalMemSize: gb, 3247 }, 3248 }, 3249 Cells: []int{2}, 3250 NumberOfAssignments: 0, 3251 }, 3252 3: &state.NUMANodeState{ 3253 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3254 v1.ResourceMemory: { 3255 Allocatable: 1536 * mb, 3256 Free: 1536 * mb, 3257 Reserved: 0, 3258 SystemReserved: 512 * mb, 3259 TotalMemSize: 2 * gb, 3260 }, 3261 hugepages1Gi: { 3262 Allocatable: gb, 3263 Free: gb, 3264 Reserved: 0, 3265 SystemReserved: 0, 3266 TotalMemSize: gb, 3267 }, 3268 }, 3269 Cells: []int{3}, 3270 NumberOfAssignments: 0, 3271 }, 3272 }, 3273 pod: getPod("pod2", "container2", requirementsGuaranteed), 3274 systemReserved: systemReservedMemory{ 3275 0: map[v1.ResourceName]uint64{ 3276 v1.ResourceMemory: 512 * mb, 3277 }, 3278 1: map[v1.ResourceName]uint64{ 3279 v1.ResourceMemory: 512 * mb, 3280 }, 3281 2: map[v1.ResourceName]uint64{ 3282 v1.ResourceMemory: 512 * mb, 3283 }, 3284 3: map[v1.ResourceName]uint64{ 3285 v1.ResourceMemory: 512 * mb, 3286 }, 3287 }, 3288 expectedTopologyHints: map[string][]topologymanager.TopologyHint{ 3289 string(v1.ResourceMemory): { 3290 { 3291 NUMANodeAffinity: newNUMAAffinity(2), 3292 Preferred: true, 3293 }, 3294 { 3295 NUMANodeAffinity: newNUMAAffinity(3), 3296 Preferred: true, 3297 }, 3298 { 3299 NUMANodeAffinity: newNUMAAffinity(2, 3), 3300 Preferred: false, 3301 }, 3302 }, 3303 string(hugepages1Gi): { 3304 { 3305 NUMANodeAffinity: newNUMAAffinity(2), 3306 Preferred: true, 3307 }, 3308 { 3309 NUMANodeAffinity: newNUMAAffinity(3), 3310 Preferred: true, 3311 }, 3312 { 3313 NUMANodeAffinity: newNUMAAffinity(2, 3), 3314 Preferred: false, 3315 }, 3316 }, 3317 }, 3318 }, 3319 { 3320 description: "should fail when number of existing memory assignment resources are different from resources requested by container", 3321 assignments: state.ContainerMemoryAssignments{ 3322 "pod1": map[string][]state.Block{ 3323 "container1": { 3324 { 3325 NUMAAffinity: []int{0}, 3326 Type: v1.ResourceMemory, 3327 Size: gb, 3328 }, 3329 }, 3330 }, 3331 }, 3332 pod: getPod("pod1", "container1", requirementsGuaranteed), 3333 systemReserved: systemReservedMemory{ 3334 0: map[v1.ResourceName]uint64{ 3335 v1.ResourceMemory: 512 * mb, 3336 }, 3337 }, 3338 expectedTopologyHints: nil, 3339 }, 3340 { 3341 description: "should fail when existing memory assignment resources are different from resources requested by container", 3342 assignments: state.ContainerMemoryAssignments{ 3343 "pod1": map[string][]state.Block{ 3344 "container1": { 3345 { 3346 NUMAAffinity: []int{0}, 3347 Type: v1.ResourceMemory, 3348 Size: gb, 3349 }, 3350 { 3351 NUMAAffinity: []int{0}, 3352 Type: hugepages2M, 3353 Size: gb, 3354 }, 3355 }, 3356 }, 3357 }, 3358 pod: getPod("pod1", "container1", requirementsGuaranteed), 3359 systemReserved: systemReservedMemory{ 3360 0: map[v1.ResourceName]uint64{ 3361 v1.ResourceMemory: 512 * mb, 3362 }, 3363 }, 3364 expectedTopologyHints: nil, 3365 }, 3366 { 3367 description: "should fail when existing memory assignment size is different from one requested by the container", 3368 assignments: state.ContainerMemoryAssignments{ 3369 "pod1": map[string][]state.Block{ 3370 "container1": { 3371 { 3372 NUMAAffinity: []int{0}, 3373 Type: v1.ResourceMemory, 3374 Size: 512 * mb, 3375 }, 3376 { 3377 NUMAAffinity: []int{0}, 3378 Type: hugepages1Gi, 3379 Size: gb, 3380 }, 3381 }, 3382 }, 3383 }, 3384 pod: getPod("pod1", "container1", requirementsGuaranteed), 3385 systemReserved: systemReservedMemory{ 3386 0: map[v1.ResourceName]uint64{ 3387 v1.ResourceMemory: 512 * mb, 3388 }, 3389 }, 3390 expectedTopologyHints: nil, 3391 }, 3392 { 3393 description: "should not return preferred hints with multiple NUMA nodes for the pod with resources satisfied by a single NUMA node", 3394 assignments: state.ContainerMemoryAssignments{ 3395 "pod1": map[string][]state.Block{ 3396 "container1": { 3397 { 3398 NUMAAffinity: []int{0, 1}, 3399 Type: v1.ResourceMemory, 3400 Size: 2 * gb, 3401 }, 3402 { 3403 NUMAAffinity: []int{0, 1}, 3404 Type: hugepages2M, 3405 Size: 24 * mb, 3406 }, 3407 }, 3408 }, 3409 }, 3410 machineState: state.NUMANodeMap{ 3411 0: &state.NUMANodeState{ 3412 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3413 v1.ResourceMemory: { 3414 Allocatable: 1536 * mb, 3415 Free: 0, 3416 Reserved: 1536 * mb, 3417 SystemReserved: 512 * mb, 3418 TotalMemSize: 2 * gb, 3419 }, 3420 hugepages2M: { 3421 Allocatable: 20 * mb, 3422 Free: 0, 3423 Reserved: 20 * mb, 3424 SystemReserved: 0, 3425 TotalMemSize: 20 * mb, 3426 }, 3427 }, 3428 Cells: []int{0, 1}, 3429 NumberOfAssignments: 2, 3430 }, 3431 1: &state.NUMANodeState{ 3432 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 3433 v1.ResourceMemory: { 3434 Allocatable: 1536 * mb, 3435 Free: gb, 3436 Reserved: 512 * mb, 3437 SystemReserved: 512 * mb, 3438 TotalMemSize: 2 * gb, 3439 }, 3440 hugepages2M: { 3441 Allocatable: 20 * mb, 3442 Free: 16 * mb, 3443 Reserved: 4 * mb, 3444 SystemReserved: 0, 3445 TotalMemSize: 20 * mb, 3446 }, 3447 }, 3448 Cells: []int{0, 1}, 3449 NumberOfAssignments: 2, 3450 }, 3451 }, 3452 pod: getPod("pod2", 3453 "container2", 3454 &v1.ResourceRequirements{ 3455 Limits: v1.ResourceList{ 3456 v1.ResourceCPU: resource.MustParse("1000Mi"), 3457 v1.ResourceMemory: resource.MustParse("1Gi"), 3458 hugepages2M: resource.MustParse("16Mi"), 3459 }, 3460 Requests: v1.ResourceList{ 3461 v1.ResourceCPU: resource.MustParse("1000Mi"), 3462 v1.ResourceMemory: resource.MustParse("1Gi"), 3463 hugepages2M: resource.MustParse("16Mi"), 3464 }, 3465 }, 3466 ), 3467 systemReserved: systemReservedMemory{ 3468 0: map[v1.ResourceName]uint64{ 3469 v1.ResourceMemory: 512 * mb, 3470 }, 3471 1: map[v1.ResourceName]uint64{ 3472 v1.ResourceMemory: 512 * mb, 3473 }, 3474 }, 3475 expectedTopologyHints: map[string][]topologymanager.TopologyHint{ 3476 string(v1.ResourceMemory): { 3477 { 3478 NUMANodeAffinity: newNUMAAffinity(0, 1), 3479 Preferred: false, 3480 }, 3481 }, 3482 hugepages2M: { 3483 { 3484 NUMANodeAffinity: newNUMAAffinity(0, 1), 3485 Preferred: false, 3486 }, 3487 }, 3488 }, 3489 }, 3490 } 3491 3492 for _, testCase := range testCases { 3493 t.Run(testCase.description, func(t *testing.T) { 3494 p, s, err := initTests(t, &testCase, nil, nil) 3495 if err != nil { 3496 t.Fatalf("Unexpected error: %v", err) 3497 } 3498 3499 topologyHints := p.GetTopologyHints(s, testCase.pod, &testCase.pod.Spec.Containers[0]) 3500 if !reflect.DeepEqual(topologyHints, testCase.expectedTopologyHints) { 3501 t.Fatalf("The actual topology hints: '%+v' are different from the expected one: '%+v'", topologyHints, testCase.expectedTopologyHints) 3502 } 3503 }) 3504 } 3505 } 3506 3507 func Test_getPodRequestedResources(t *testing.T) { 3508 testCases := []struct { 3509 description string 3510 pod *v1.Pod 3511 expected map[v1.ResourceName]uint64 3512 }{ 3513 { 3514 description: "maximum resources of init containers > total resources of containers", 3515 pod: getPodWithInitContainers( 3516 "", 3517 []v1.Container{ 3518 { 3519 Name: "container1", 3520 Resources: v1.ResourceRequirements{ 3521 Requests: v1.ResourceList{ 3522 v1.ResourceMemory: resource.MustParse("1Gi"), 3523 hugepages1Gi: resource.MustParse("1Gi"), 3524 }, 3525 }, 3526 }, 3527 { 3528 Name: "container2", 3529 Resources: v1.ResourceRequirements{ 3530 Requests: v1.ResourceList{ 3531 v1.ResourceMemory: resource.MustParse("2Gi"), 3532 hugepages1Gi: resource.MustParse("2Gi"), 3533 }, 3534 }, 3535 }, 3536 }, 3537 []v1.Container{ 3538 { 3539 Name: "initContainer1", 3540 Resources: v1.ResourceRequirements{ 3541 Requests: v1.ResourceList{ 3542 v1.ResourceMemory: resource.MustParse("1Gi"), 3543 hugepages1Gi: resource.MustParse("1Gi"), 3544 }, 3545 }, 3546 }, 3547 { 3548 Name: "initContainer2", 3549 Resources: v1.ResourceRequirements{ 3550 Requests: v1.ResourceList{ 3551 v1.ResourceMemory: resource.MustParse("4Gi"), 3552 hugepages1Gi: resource.MustParse("4Gi"), 3553 }, 3554 }, 3555 }, 3556 }, 3557 ), 3558 expected: map[v1.ResourceName]uint64{ 3559 v1.ResourceMemory: 4 * gb, 3560 hugepages1Gi: 4 * gb, 3561 }, 3562 }, 3563 { 3564 description: "maximum resources of init containers < total resources of containers", 3565 pod: getPodWithInitContainers( 3566 "", 3567 []v1.Container{ 3568 { 3569 Name: "container1", 3570 Resources: v1.ResourceRequirements{ 3571 Requests: v1.ResourceList{ 3572 v1.ResourceMemory: resource.MustParse("2Gi"), 3573 hugepages1Gi: resource.MustParse("2Gi"), 3574 }, 3575 }, 3576 }, 3577 { 3578 Name: "container2", 3579 Resources: v1.ResourceRequirements{ 3580 Requests: v1.ResourceList{ 3581 v1.ResourceMemory: resource.MustParse("3Gi"), 3582 hugepages1Gi: resource.MustParse("3Gi"), 3583 }, 3584 }, 3585 }, 3586 }, 3587 []v1.Container{ 3588 { 3589 Name: "initContainer1", 3590 Resources: v1.ResourceRequirements{ 3591 Requests: v1.ResourceList{ 3592 v1.ResourceMemory: resource.MustParse("1Gi"), 3593 hugepages1Gi: resource.MustParse("1Gi"), 3594 }, 3595 }, 3596 }, 3597 { 3598 Name: "initContainer2", 3599 Resources: v1.ResourceRequirements{ 3600 Requests: v1.ResourceList{ 3601 v1.ResourceMemory: resource.MustParse("3Gi"), 3602 hugepages1Gi: resource.MustParse("3Gi"), 3603 }, 3604 }, 3605 }, 3606 }, 3607 ), 3608 expected: map[v1.ResourceName]uint64{ 3609 v1.ResourceMemory: 5 * gb, 3610 hugepages1Gi: 5 * gb, 3611 }, 3612 }, 3613 { 3614 description: "calculate different resources independently", 3615 pod: getPodWithInitContainers( 3616 "", 3617 []v1.Container{ 3618 { 3619 Name: "container1", 3620 Resources: v1.ResourceRequirements{ 3621 Requests: v1.ResourceList{ 3622 v1.ResourceMemory: resource.MustParse("2Gi"), 3623 hugepages1Gi: resource.MustParse("1Gi"), 3624 }, 3625 }, 3626 }, 3627 { 3628 Name: "container2", 3629 Resources: v1.ResourceRequirements{ 3630 Requests: v1.ResourceList{ 3631 v1.ResourceMemory: resource.MustParse("3Gi"), 3632 hugepages1Gi: resource.MustParse("2Gi"), 3633 }, 3634 }, 3635 }, 3636 }, 3637 []v1.Container{ 3638 { 3639 Name: "initContainer1", 3640 Resources: v1.ResourceRequirements{ 3641 Requests: v1.ResourceList{ 3642 v1.ResourceMemory: resource.MustParse("1Gi"), 3643 hugepages1Gi: resource.MustParse("1Gi"), 3644 }, 3645 }, 3646 }, 3647 { 3648 Name: "initContainer2", 3649 Resources: v1.ResourceRequirements{ 3650 Requests: v1.ResourceList{ 3651 v1.ResourceMemory: resource.MustParse("3Gi"), 3652 hugepages1Gi: resource.MustParse("4Gi"), 3653 }, 3654 }, 3655 }, 3656 }, 3657 ), 3658 expected: map[v1.ResourceName]uint64{ 3659 v1.ResourceMemory: 5 * gb, 3660 hugepages1Gi: 4 * gb, 3661 }, 3662 }, 3663 { 3664 description: "maximum resources of init containers > total resources of long running containers, including restartable init containers", 3665 pod: getPodWithInitContainers( 3666 "", 3667 []v1.Container{ 3668 { 3669 Name: "container1", 3670 Resources: v1.ResourceRequirements{ 3671 Requests: v1.ResourceList{ 3672 v1.ResourceMemory: resource.MustParse("1Gi"), 3673 hugepages1Gi: resource.MustParse("1Gi"), 3674 }, 3675 }, 3676 }, 3677 { 3678 Name: "container2", 3679 Resources: v1.ResourceRequirements{ 3680 Requests: v1.ResourceList{ 3681 v1.ResourceMemory: resource.MustParse("2Gi"), 3682 hugepages1Gi: resource.MustParse("2Gi"), 3683 }, 3684 }, 3685 }, 3686 }, 3687 []v1.Container{ 3688 { 3689 Name: "restartableInit1", 3690 Resources: v1.ResourceRequirements{ 3691 Requests: v1.ResourceList{ 3692 v1.ResourceMemory: resource.MustParse("2Gi"), 3693 hugepages1Gi: resource.MustParse("2Gi"), 3694 }, 3695 }, 3696 RestartPolicy: &containerRestartPolicyAlways, 3697 }, 3698 { 3699 Name: "initContainer2", 3700 Resources: v1.ResourceRequirements{ 3701 Requests: v1.ResourceList{ 3702 v1.ResourceMemory: resource.MustParse("4Gi"), 3703 hugepages1Gi: resource.MustParse("4Gi"), 3704 }, 3705 }, 3706 }, 3707 }, 3708 ), 3709 expected: map[v1.ResourceName]uint64{ 3710 v1.ResourceMemory: 6 * gb, 3711 hugepages1Gi: 6 * gb, 3712 }, 3713 }, 3714 { 3715 description: "maximum resources of init containers < total resources of long running containers, including restartable init containers", 3716 pod: getPodWithInitContainers( 3717 "", 3718 []v1.Container{ 3719 { 3720 Name: "container1", 3721 Resources: v1.ResourceRequirements{ 3722 Requests: v1.ResourceList{ 3723 v1.ResourceMemory: resource.MustParse("2Gi"), 3724 hugepages1Gi: resource.MustParse("2Gi"), 3725 }, 3726 }, 3727 }, 3728 { 3729 Name: "container2", 3730 Resources: v1.ResourceRequirements{ 3731 Requests: v1.ResourceList{ 3732 v1.ResourceMemory: resource.MustParse("3Gi"), 3733 hugepages1Gi: resource.MustParse("3Gi"), 3734 }, 3735 }, 3736 }, 3737 }, 3738 []v1.Container{ 3739 { 3740 Name: "restartableInit1", 3741 Resources: v1.ResourceRequirements{ 3742 Requests: v1.ResourceList{ 3743 v1.ResourceMemory: resource.MustParse("2Gi"), 3744 hugepages1Gi: resource.MustParse("2Gi"), 3745 }, 3746 }, 3747 RestartPolicy: &containerRestartPolicyAlways, 3748 }, 3749 { 3750 Name: "initContainer2", 3751 Resources: v1.ResourceRequirements{ 3752 Requests: v1.ResourceList{ 3753 v1.ResourceMemory: resource.MustParse("4Gi"), 3754 hugepages1Gi: resource.MustParse("4Gi"), 3755 }, 3756 }, 3757 }, 3758 }, 3759 ), 3760 expected: map[v1.ResourceName]uint64{ 3761 v1.ResourceMemory: 7 * gb, 3762 hugepages1Gi: 7 * gb, 3763 }, 3764 }, 3765 } 3766 3767 for _, tc := range testCases { 3768 t.Run(tc.description, func(t *testing.T) { 3769 actual, err := getPodRequestedResources(tc.pod) 3770 if err != nil { 3771 t.Fatalf("Unexpected error: %v", err) 3772 } 3773 if diff := cmp.Diff(actual, tc.expected); diff != "" { 3774 t.Errorf("getPodRequestedResources() mismatch (-want +got):\n%s", diff) 3775 } 3776 }) 3777 } 3778 }