1/* 2Copyright 2020 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package memorymanager 18 19import ( 20 "fmt" 21 "reflect" 22 "testing" 23 24 "k8s.io/klog/v2" 25 26 cadvisorapi "github.com/google/cadvisor/info/v1" 27 28 v1 "k8s.io/api/core/v1" 29 "k8s.io/apimachinery/pkg/api/resource" 30 "k8s.io/kubernetes/pkg/kubelet/cm/memorymanager/state" 31 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager" 32 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask" 33) 34 35const ( 36 mb = 1024 * 1024 37 gb = mb * 1024 38 pageSize1Gb = 1048576 39 hugepages1Gi = v1.ResourceName(v1.ResourceHugePagesPrefix + "1Gi") 40) 41 42var ( 43 requirementsGuaranteed = &v1.ResourceRequirements{ 44 Limits: v1.ResourceList{ 45 v1.ResourceCPU: resource.MustParse("1000Mi"), 46 v1.ResourceMemory: resource.MustParse("1Gi"), 47 hugepages1Gi: resource.MustParse("1Gi"), 48 }, 49 Requests: v1.ResourceList{ 50 v1.ResourceCPU: resource.MustParse("1000Mi"), 51 v1.ResourceMemory: resource.MustParse("1Gi"), 52 hugepages1Gi: resource.MustParse("1Gi"), 53 }, 54 } 55 requirementsBurstable = &v1.ResourceRequirements{ 56 Limits: v1.ResourceList{ 57 v1.ResourceCPU: resource.MustParse("1000Mi"), 58 v1.ResourceMemory: resource.MustParse("2Gi"), 59 hugepages1Gi: resource.MustParse("2Gi"), 60 }, 61 Requests: v1.ResourceList{ 62 v1.ResourceCPU: resource.MustParse("1000Mi"), 63 v1.ResourceMemory: resource.MustParse("1Gi"), 64 hugepages1Gi: resource.MustParse("1Gi"), 65 }, 66 } 67) 68 69func areMemoryBlocksEqual(mb1, mb2 []state.Block) bool { 70 if len(mb1) != len(mb2) { 71 return false 72 } 73 74 copyMemoryBlocks := make([]state.Block, len(mb2)) 75 copy(copyMemoryBlocks, mb2) 76 for _, block := range mb1 { 77 for i, copyBlock := range copyMemoryBlocks { 78 if reflect.DeepEqual(block, copyBlock) { 79 // move the element that equals to the block to the end of the slice 80 copyMemoryBlocks[i] = copyMemoryBlocks[len(copyMemoryBlocks)-1] 81 82 // remove the last element from our slice 83 copyMemoryBlocks = copyMemoryBlocks[:len(copyMemoryBlocks)-1] 84 85 break 86 } 87 } 88 } 89 90 return len(copyMemoryBlocks) == 0 91} 92 93func areContainerMemoryAssignmentsEqual(t *testing.T, cma1, cma2 state.ContainerMemoryAssignments) bool { 94 if len(cma1) != len(cma2) { 95 return false 96 } 97 98 for podUID, container := range cma1 { 99 if _, ok := cma2[podUID]; !ok { 100 t.Logf("[memorymanager_tests] the assignment does not have pod UID %s", podUID) 101 return false 102 } 103 104 for containerName, memoryBlocks := range container { 105 if _, ok := cma2[podUID][containerName]; !ok { 106 t.Logf("[memorymanager_tests] the assignment does not have container name %s", containerName) 107 return false 108 } 109 110 if !areMemoryBlocksEqual(memoryBlocks, cma2[podUID][containerName]) { 111 t.Logf("[memorymanager_tests] assignments memory blocks are different: %v != %v", memoryBlocks, cma2[podUID][containerName]) 112 return false 113 } 114 } 115 } 116 return true 117} 118 119type testStaticPolicy struct { 120 description string 121 assignments state.ContainerMemoryAssignments 122 expectedAssignments state.ContainerMemoryAssignments 123 machineState state.NUMANodeMap 124 expectedMachineState state.NUMANodeMap 125 systemReserved systemReservedMemory 126 expectedError error 127 machineInfo *cadvisorapi.MachineInfo 128 pod *v1.Pod 129 topologyHint *topologymanager.TopologyHint 130 expectedTopologyHints map[string][]topologymanager.TopologyHint 131} 132 133func initTests(t *testing.T, testCase *testStaticPolicy, hint *topologymanager.TopologyHint) (Policy, state.State, error) { 134 manager := topologymanager.NewFakeManager() 135 if hint != nil { 136 manager = topologymanager.NewFakeManagerWithHint(hint) 137 } 138 139 p, err := NewPolicyStatic(testCase.machineInfo, testCase.systemReserved, manager) 140 if err != nil { 141 return nil, nil, err 142 } 143 s := state.NewMemoryState() 144 s.SetMachineState(testCase.machineState) 145 s.SetMemoryAssignments(testCase.assignments) 146 return p, s, nil 147} 148 149func newNUMAAffinity(bits ...int) bitmask.BitMask { 150 affinity, err := bitmask.NewBitMask(bits...) 151 if err != nil { 152 panic(err) 153 } 154 return affinity 155} 156 157func TestStaticPolicyNew(t *testing.T) { 158 testCases := []testStaticPolicy{ 159 { 160 description: "should fail, when machine does not have reserved memory for the system workloads", 161 expectedError: fmt.Errorf("[memorymanager] you should specify the system reserved memory"), 162 }, 163 { 164 description: "should succeed, when at least one NUMA node has reserved memory", 165 systemReserved: systemReservedMemory{ 166 0: map[v1.ResourceName]uint64{}, 167 1: map[v1.ResourceName]uint64{ 168 v1.ResourceMemory: 512 * mb, 169 }, 170 }, 171 }, 172 } 173 174 for _, testCase := range testCases { 175 t.Run(testCase.description, func(t *testing.T) { 176 _, _, err := initTests(t, &testCase, nil) 177 if !reflect.DeepEqual(err, testCase.expectedError) { 178 t.Fatalf("The actual error: %v is different from the expected one: %v", err, testCase.expectedError) 179 } 180 }) 181 } 182} 183 184func TestStaticPolicyName(t *testing.T) { 185 testCases := []testStaticPolicy{ 186 { 187 description: "should return the correct policy name", 188 systemReserved: systemReservedMemory{ 189 0: map[v1.ResourceName]uint64{ 190 v1.ResourceMemory: 512 * mb, 191 }, 192 }, 193 }, 194 } 195 for _, testCase := range testCases { 196 t.Run(testCase.description, func(t *testing.T) { 197 p, _, err := initTests(t, &testCase, nil) 198 if err != nil { 199 t.Fatalf("Unexpected error: %v", err) 200 } 201 if p.Name() != string(policyTypeStatic) { 202 t.Errorf("policy name is different, expected: %q, actual: %q", p.Name(), policyTypeStatic) 203 } 204 }) 205 } 206} 207 208func TestStaticPolicyStart(t *testing.T) { 209 testCases := []testStaticPolicy{ 210 { 211 description: "should fail, if machine state is empty, but it has memory assignments", 212 assignments: state.ContainerMemoryAssignments{ 213 "pod": map[string][]state.Block{ 214 "container1": { 215 { 216 NUMAAffinity: []int{0}, 217 Type: v1.ResourceMemory, 218 Size: 512 * mb, 219 }, 220 }, 221 }, 222 }, 223 systemReserved: systemReservedMemory{ 224 0: map[v1.ResourceName]uint64{ 225 v1.ResourceMemory: 512 * mb, 226 }, 227 }, 228 expectedError: fmt.Errorf("[memorymanager] machine state can not be empty when it has memory assignments"), 229 }, 230 { 231 description: "should fill the state with default values, when the state is empty", 232 expectedAssignments: state.ContainerMemoryAssignments{}, 233 expectedMachineState: state.NUMANodeMap{ 234 0: &state.NUMANodeState{ 235 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 236 v1.ResourceMemory: { 237 Allocatable: 1536 * mb, 238 Free: 1536 * mb, 239 Reserved: 0, 240 SystemReserved: 512 * mb, 241 TotalMemSize: 3 * gb, 242 }, 243 hugepages1Gi: { 244 Allocatable: gb, 245 Free: gb, 246 Reserved: 0, 247 SystemReserved: 0, 248 TotalMemSize: gb, 249 }, 250 }, 251 NumberOfAssignments: 0, 252 Cells: []int{0}, 253 }, 254 }, 255 systemReserved: systemReservedMemory{ 256 0: map[v1.ResourceName]uint64{ 257 v1.ResourceMemory: 512 * mb, 258 }, 259 }, 260 machineInfo: &cadvisorapi.MachineInfo{ 261 Topology: []cadvisorapi.Node{ 262 { 263 Id: 0, 264 Memory: 3 * gb, 265 HugePages: []cadvisorapi.HugePagesInfo{ 266 { 267 // size in KB 268 PageSize: pageSize1Gb, 269 NumPages: 1, 270 }, 271 }, 272 }, 273 }, 274 }, 275 }, 276 { 277 description: "should fail when machine state does not have all NUMA nodes", 278 machineState: state.NUMANodeMap{ 279 0: &state.NUMANodeState{ 280 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 281 v1.ResourceMemory: { 282 Allocatable: 1536 * mb, 283 Free: 1536 * mb, 284 Reserved: 0, 285 SystemReserved: 512 * mb, 286 TotalMemSize: 2 * gb, 287 }, 288 hugepages1Gi: { 289 Allocatable: gb, 290 Free: gb, 291 Reserved: 0, 292 SystemReserved: 0, 293 TotalMemSize: gb, 294 }, 295 }, 296 Cells: []int{0}, 297 NumberOfAssignments: 0, 298 }, 299 }, 300 systemReserved: systemReservedMemory{ 301 0: map[v1.ResourceName]uint64{ 302 v1.ResourceMemory: 512 * mb, 303 }, 304 }, 305 machineInfo: &cadvisorapi.MachineInfo{ 306 Topology: []cadvisorapi.Node{ 307 { 308 Id: 0, 309 Memory: 2 * gb, 310 HugePages: []cadvisorapi.HugePagesInfo{ 311 { 312 // size in KB 313 PageSize: pageSize1Gb, 314 NumPages: 1, 315 }, 316 }, 317 }, 318 { 319 Id: 1, 320 Memory: 2 * gb, 321 HugePages: []cadvisorapi.HugePagesInfo{ 322 { 323 // size in KB 324 PageSize: pageSize1Gb, 325 NumPages: 1, 326 }, 327 }, 328 }, 329 }, 330 }, 331 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 332 }, 333 { 334 description: "should fail when machine state does not have memory resource", 335 machineState: state.NUMANodeMap{ 336 0: &state.NUMANodeState{ 337 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 338 hugepages1Gi: { 339 Allocatable: gb, 340 Free: gb, 341 Reserved: 0, 342 SystemReserved: 0, 343 TotalMemSize: gb, 344 }, 345 }, 346 Cells: []int{0}, 347 NumberOfAssignments: 0, 348 }, 349 }, 350 machineInfo: &cadvisorapi.MachineInfo{ 351 Topology: []cadvisorapi.Node{ 352 { 353 Id: 0, 354 Memory: 2 * gb, 355 HugePages: []cadvisorapi.HugePagesInfo{ 356 { 357 // size in KB 358 PageSize: pageSize1Gb, 359 NumPages: 1, 360 }, 361 }, 362 }, 363 }, 364 }, 365 systemReserved: systemReservedMemory{ 366 0: map[v1.ResourceName]uint64{ 367 v1.ResourceMemory: 512 * mb, 368 }, 369 }, 370 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 371 }, 372 { 373 description: "should fail when machine state has wrong size of total memory", 374 machineState: state.NUMANodeMap{ 375 0: &state.NUMANodeState{ 376 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 377 v1.ResourceMemory: { 378 Allocatable: 1536 * mb, 379 Free: 1536 * mb, 380 Reserved: 0, 381 SystemReserved: 512 * mb, 382 TotalMemSize: 1536 * mb, 383 }, 384 }, 385 Cells: []int{0}, 386 NumberOfAssignments: 0, 387 }, 388 }, 389 systemReserved: systemReservedMemory{ 390 0: map[v1.ResourceName]uint64{ 391 v1.ResourceMemory: 512 * mb, 392 }, 393 }, 394 machineInfo: &cadvisorapi.MachineInfo{ 395 Topology: []cadvisorapi.Node{ 396 { 397 Id: 0, 398 Memory: 2 * gb, 399 HugePages: []cadvisorapi.HugePagesInfo{ 400 { 401 // size in KB 402 PageSize: pageSize1Gb, 403 NumPages: 1, 404 }, 405 }, 406 }, 407 }, 408 }, 409 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 410 }, 411 { 412 description: "should fail when machine state has wrong size of system reserved memory", 413 machineState: state.NUMANodeMap{ 414 0: &state.NUMANodeState{ 415 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 416 v1.ResourceMemory: { 417 Allocatable: 1536 * mb, 418 Free: 1536 * mb, 419 Reserved: 0, 420 SystemReserved: 1024, 421 TotalMemSize: 2 * gb, 422 }, 423 }, 424 Cells: []int{0}, 425 NumberOfAssignments: 0, 426 }, 427 }, 428 systemReserved: systemReservedMemory{ 429 0: map[v1.ResourceName]uint64{ 430 v1.ResourceMemory: 512 * mb, 431 }, 432 }, 433 machineInfo: &cadvisorapi.MachineInfo{ 434 Topology: []cadvisorapi.Node{ 435 { 436 Id: 0, 437 Memory: 2 * gb, 438 HugePages: []cadvisorapi.HugePagesInfo{ 439 { 440 // size in KB 441 PageSize: pageSize1Gb, 442 NumPages: 1, 443 }, 444 }, 445 }, 446 }, 447 }, 448 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 449 }, 450 { 451 description: "should fail when machine state reserved memory is different from the memory of all containers memory assignments", 452 assignments: state.ContainerMemoryAssignments{ 453 "pod": map[string][]state.Block{ 454 "container1": { 455 { 456 NUMAAffinity: []int{0}, 457 Type: v1.ResourceMemory, 458 Size: 512 * mb, 459 }, 460 }, 461 }, 462 }, 463 machineState: state.NUMANodeMap{ 464 0: &state.NUMANodeState{ 465 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 466 v1.ResourceMemory: { 467 Allocatable: 1536 * mb, 468 Free: 1536 * mb, 469 Reserved: 0, 470 SystemReserved: 512 * mb, 471 TotalMemSize: 2 * gb, 472 }, 473 }, 474 Cells: []int{0}, 475 NumberOfAssignments: 1, 476 }, 477 }, 478 systemReserved: systemReservedMemory{ 479 0: map[v1.ResourceName]uint64{ 480 v1.ResourceMemory: 512 * mb, 481 }, 482 }, 483 machineInfo: &cadvisorapi.MachineInfo{ 484 Topology: []cadvisorapi.Node{ 485 { 486 Id: 0, 487 Memory: 2 * gb, 488 HugePages: []cadvisorapi.HugePagesInfo{ 489 { 490 // size in KB 491 PageSize: pageSize1Gb, 492 NumPages: 1, 493 }, 494 }, 495 }, 496 }, 497 }, 498 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 499 }, 500 { 501 description: "should fail when machine state has wrong size of hugepages", 502 machineState: state.NUMANodeMap{ 503 0: &state.NUMANodeState{ 504 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 505 v1.ResourceMemory: { 506 Allocatable: 1536 * mb, 507 Free: 1536 * mb, 508 Reserved: 0, 509 SystemReserved: 512 * mb, 510 TotalMemSize: 2 * gb, 511 }, 512 hugepages1Gi: { 513 Allocatable: gb, 514 Free: gb, 515 Reserved: 0, 516 SystemReserved: 0, 517 TotalMemSize: gb, 518 }, 519 }, 520 Cells: []int{0}, 521 NumberOfAssignments: 0, 522 }, 523 }, 524 systemReserved: systemReservedMemory{ 525 0: map[v1.ResourceName]uint64{ 526 v1.ResourceMemory: 512 * mb, 527 }, 528 }, 529 machineInfo: &cadvisorapi.MachineInfo{ 530 Topology: []cadvisorapi.Node{ 531 { 532 Id: 0, 533 Memory: 2 * gb, 534 HugePages: []cadvisorapi.HugePagesInfo{ 535 { 536 // size in KB 537 PageSize: pageSize1Gb, 538 NumPages: 2, 539 }, 540 }, 541 }, 542 }, 543 }, 544 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 545 }, 546 { 547 description: "should fail when machine state has wrong size of system reserved hugepages", 548 machineState: state.NUMANodeMap{ 549 0: &state.NUMANodeState{ 550 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 551 v1.ResourceMemory: { 552 Allocatable: 1536 * mb, 553 Free: 1536 * mb, 554 Reserved: 0, 555 SystemReserved: 512 * mb, 556 TotalMemSize: 2 * gb, 557 }, 558 hugepages1Gi: { 559 Allocatable: gb, 560 Free: gb, 561 Reserved: 0, 562 SystemReserved: gb, 563 TotalMemSize: 2 * gb, 564 }, 565 }, 566 Cells: []int{0}, 567 NumberOfAssignments: 0, 568 }, 569 }, 570 systemReserved: systemReservedMemory{ 571 0: map[v1.ResourceName]uint64{ 572 v1.ResourceMemory: 512 * mb, 573 }, 574 }, 575 machineInfo: &cadvisorapi.MachineInfo{ 576 Topology: []cadvisorapi.Node{ 577 { 578 Id: 0, 579 Memory: 2 * gb, 580 HugePages: []cadvisorapi.HugePagesInfo{ 581 { 582 // size in KB 583 PageSize: pageSize1Gb, 584 NumPages: 2, 585 }, 586 }, 587 }, 588 }, 589 }, 590 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 591 }, 592 { 593 description: "should fail when the hugepages reserved machine state is different from the hugepages of all containers memory assignments", 594 assignments: state.ContainerMemoryAssignments{ 595 "pod1": map[string][]state.Block{ 596 "container1": { 597 { 598 NUMAAffinity: []int{0}, 599 Type: hugepages1Gi, 600 Size: gb, 601 }, 602 }, 603 }, 604 "pod2": map[string][]state.Block{ 605 "container2": { 606 { 607 NUMAAffinity: []int{0}, 608 Type: hugepages1Gi, 609 Size: gb, 610 }, 611 }, 612 }, 613 }, 614 machineState: state.NUMANodeMap{ 615 0: &state.NUMANodeState{ 616 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 617 v1.ResourceMemory: { 618 Allocatable: 1536 * mb, 619 Free: 1536 * mb, 620 Reserved: 0, 621 SystemReserved: 512 * mb, 622 TotalMemSize: 2 * gb, 623 }, 624 hugepages1Gi: { 625 Allocatable: 4 * gb, 626 Free: gb, 627 Reserved: 3 * gb, 628 SystemReserved: 0, 629 TotalMemSize: 4 * gb, 630 }, 631 }, 632 Cells: []int{0}, 633 NumberOfAssignments: 2, 634 }, 635 }, 636 systemReserved: systemReservedMemory{ 637 0: map[v1.ResourceName]uint64{ 638 v1.ResourceMemory: 512 * mb, 639 }, 640 }, 641 machineInfo: &cadvisorapi.MachineInfo{ 642 Topology: []cadvisorapi.Node{ 643 { 644 Id: 0, 645 Memory: 2 * gb, 646 HugePages: []cadvisorapi.HugePagesInfo{ 647 { 648 // size in KB 649 PageSize: pageSize1Gb, 650 NumPages: 4, 651 }, 652 }, 653 }, 654 }, 655 }, 656 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 657 }, 658 { 659 description: "should fail when machine state does not have NUMA node that used under the memory assignment", 660 assignments: state.ContainerMemoryAssignments{ 661 "pod1": map[string][]state.Block{ 662 "container1": { 663 { 664 NUMAAffinity: []int{1}, 665 Type: v1.ResourceMemory, 666 Size: gb, 667 }, 668 }, 669 }, 670 }, 671 machineState: state.NUMANodeMap{ 672 0: &state.NUMANodeState{ 673 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 674 v1.ResourceMemory: { 675 Allocatable: 1536 * mb, 676 Free: 1536 * mb, 677 Reserved: 0, 678 SystemReserved: 512 * mb, 679 TotalMemSize: 2 * gb, 680 }, 681 hugepages1Gi: { 682 Allocatable: gb, 683 Free: gb, 684 Reserved: 0, 685 SystemReserved: 0, 686 TotalMemSize: gb, 687 }, 688 }, 689 Cells: []int{0}, 690 NumberOfAssignments: 0, 691 }, 692 }, 693 systemReserved: systemReservedMemory{ 694 0: map[v1.ResourceName]uint64{ 695 v1.ResourceMemory: 512 * mb, 696 }, 697 }, 698 machineInfo: &cadvisorapi.MachineInfo{ 699 Topology: []cadvisorapi.Node{ 700 { 701 Id: 0, 702 Memory: 2 * gb, 703 HugePages: []cadvisorapi.HugePagesInfo{ 704 { 705 // size in KB 706 PageSize: pageSize1Gb, 707 NumPages: 1, 708 }, 709 }, 710 }, 711 }, 712 }, 713 expectedError: fmt.Errorf("[memorymanager] (pod: pod1, container: container1) the memory assignment uses the NUMA that does not exist"), 714 }, 715 { 716 description: "should fail when machine state does not have resource that used under the memory assignment", 717 assignments: state.ContainerMemoryAssignments{ 718 "pod1": map[string][]state.Block{ 719 "container1": { 720 { 721 NUMAAffinity: []int{0}, 722 Type: v1.ResourceMemory, 723 Size: gb, 724 }, 725 { 726 NUMAAffinity: []int{0}, 727 Type: hugepages2M, 728 Size: gb, 729 }, 730 }, 731 }, 732 }, 733 machineState: state.NUMANodeMap{ 734 0: &state.NUMANodeState{ 735 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 736 v1.ResourceMemory: { 737 Allocatable: 1536 * mb, 738 Free: 1536 * mb, 739 Reserved: 0, 740 SystemReserved: 512 * mb, 741 TotalMemSize: 2 * gb, 742 }, 743 hugepages1Gi: { 744 Allocatable: gb, 745 Free: gb, 746 Reserved: 0, 747 SystemReserved: 0, 748 TotalMemSize: gb, 749 }, 750 }, 751 Cells: []int{0}, 752 NumberOfAssignments: 2, 753 }, 754 }, 755 systemReserved: systemReservedMemory{ 756 0: map[v1.ResourceName]uint64{ 757 v1.ResourceMemory: 512 * mb, 758 }, 759 }, 760 machineInfo: &cadvisorapi.MachineInfo{ 761 Topology: []cadvisorapi.Node{ 762 { 763 Id: 0, 764 Memory: 2 * gb, 765 HugePages: []cadvisorapi.HugePagesInfo{ 766 { 767 // size in KB 768 PageSize: pageSize1Gb, 769 NumPages: 1, 770 }, 771 }, 772 }, 773 }, 774 }, 775 expectedError: fmt.Errorf("[memorymanager] (pod: pod1, container: container1) the memory assignment uses memory resource that does not exist"), 776 }, 777 { 778 description: "should fail when machine state number of assignments is different from the expected one", 779 assignments: state.ContainerMemoryAssignments{ 780 "pod1": map[string][]state.Block{ 781 "container1": { 782 { 783 NUMAAffinity: []int{0}, 784 Type: v1.ResourceMemory, 785 Size: gb, 786 }, 787 { 788 NUMAAffinity: []int{0}, 789 Type: hugepages1Gi, 790 Size: gb, 791 }, 792 }, 793 }, 794 }, 795 machineState: state.NUMANodeMap{ 796 0: &state.NUMANodeState{ 797 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 798 v1.ResourceMemory: { 799 Allocatable: 1536 * mb, 800 Free: 1536 * mb, 801 Reserved: 0, 802 SystemReserved: 512 * mb, 803 TotalMemSize: 2 * gb, 804 }, 805 hugepages1Gi: { 806 Allocatable: gb, 807 Free: gb, 808 Reserved: 0, 809 SystemReserved: 0, 810 TotalMemSize: gb, 811 }, 812 }, 813 Cells: []int{0}, 814 NumberOfAssignments: 1, 815 }, 816 }, 817 systemReserved: systemReservedMemory{ 818 0: map[v1.ResourceName]uint64{ 819 v1.ResourceMemory: 512 * mb, 820 }, 821 }, 822 machineInfo: &cadvisorapi.MachineInfo{ 823 Topology: []cadvisorapi.Node{ 824 { 825 Id: 0, 826 Memory: 2 * gb, 827 HugePages: []cadvisorapi.HugePagesInfo{ 828 { 829 // size in KB 830 PageSize: pageSize1Gb, 831 NumPages: 1, 832 }, 833 }, 834 }, 835 }, 836 }, 837 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"), 838 }, 839 { 840 description: "should validate cross NUMA reserved memory vs container assignments", 841 assignments: state.ContainerMemoryAssignments{ 842 "pod1": map[string][]state.Block{ 843 "container1": { 844 { 845 NUMAAffinity: []int{0, 1}, 846 Type: v1.ResourceMemory, 847 Size: 768 * mb, 848 }, 849 { 850 NUMAAffinity: []int{0, 1}, 851 Type: hugepages1Gi, 852 Size: gb, 853 }, 854 }, 855 }, 856 "pod2": map[string][]state.Block{ 857 "container2": { 858 { 859 NUMAAffinity: []int{0, 1}, 860 Type: v1.ResourceMemory, 861 Size: 256 * mb, 862 }, 863 { 864 NUMAAffinity: []int{0, 1}, 865 Type: hugepages1Gi, 866 Size: gb, 867 }, 868 }, 869 }, 870 }, 871 expectedAssignments: state.ContainerMemoryAssignments{ 872 "pod1": map[string][]state.Block{ 873 "container1": { 874 { 875 NUMAAffinity: []int{0, 1}, 876 Type: v1.ResourceMemory, 877 Size: 768 * mb, 878 }, 879 { 880 NUMAAffinity: []int{0, 1}, 881 Type: hugepages1Gi, 882 Size: gb, 883 }, 884 }, 885 }, 886 "pod2": map[string][]state.Block{ 887 "container2": { 888 { 889 NUMAAffinity: []int{0, 1}, 890 Type: v1.ResourceMemory, 891 Size: 256 * mb, 892 }, 893 { 894 NUMAAffinity: []int{0, 1}, 895 Type: hugepages1Gi, 896 Size: gb, 897 }, 898 }, 899 }, 900 }, 901 machineState: state.NUMANodeMap{ 902 0: &state.NUMANodeState{ 903 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 904 v1.ResourceMemory: { 905 Allocatable: 640 * mb, 906 Free: 0, 907 Reserved: 640 * mb, 908 SystemReserved: 512 * mb, 909 TotalMemSize: 2176 * mb, 910 }, 911 hugepages1Gi: { 912 Allocatable: gb, 913 Free: 0, 914 Reserved: gb, 915 SystemReserved: 0, 916 TotalMemSize: gb, 917 }, 918 }, 919 Cells: []int{0, 1}, 920 NumberOfAssignments: 4, 921 }, 922 1: &state.NUMANodeState{ 923 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 924 v1.ResourceMemory: { 925 Allocatable: 640 * mb, 926 Free: 256 * mb, 927 Reserved: 384 * mb, 928 SystemReserved: 512 * mb, 929 TotalMemSize: 2176 * mb, 930 }, 931 hugepages1Gi: { 932 Allocatable: gb, 933 Free: 0, 934 Reserved: gb, 935 SystemReserved: 0, 936 TotalMemSize: gb, 937 }, 938 }, 939 Cells: []int{0, 1}, 940 NumberOfAssignments: 4, 941 }, 942 }, 943 expectedMachineState: state.NUMANodeMap{ 944 0: &state.NUMANodeState{ 945 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 946 v1.ResourceMemory: { 947 Allocatable: 640 * mb, 948 Free: 0, 949 Reserved: 640 * mb, 950 SystemReserved: 512 * mb, 951 TotalMemSize: 2176 * mb, 952 }, 953 hugepages1Gi: { 954 Allocatable: gb, 955 Free: 0, 956 Reserved: gb, 957 SystemReserved: 0, 958 TotalMemSize: gb, 959 }, 960 }, 961 Cells: []int{0, 1}, 962 NumberOfAssignments: 4, 963 }, 964 1: &state.NUMANodeState{ 965 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 966 v1.ResourceMemory: { 967 Allocatable: 640 * mb, 968 Free: 256 * mb, 969 Reserved: 384 * mb, 970 SystemReserved: 512 * mb, 971 TotalMemSize: 2176 * mb, 972 }, 973 hugepages1Gi: { 974 Allocatable: gb, 975 Free: 0, 976 Reserved: gb, 977 SystemReserved: 0, 978 TotalMemSize: gb, 979 }, 980 }, 981 Cells: []int{0, 1}, 982 NumberOfAssignments: 4, 983 }, 984 }, 985 systemReserved: systemReservedMemory{ 986 0: map[v1.ResourceName]uint64{ 987 v1.ResourceMemory: 512 * mb, 988 }, 989 1: map[v1.ResourceName]uint64{ 990 v1.ResourceMemory: 512 * mb, 991 }, 992 }, 993 machineInfo: &cadvisorapi.MachineInfo{ 994 Topology: []cadvisorapi.Node{ 995 { 996 Id: 0, 997 Memory: 2176 * mb, 998 HugePages: []cadvisorapi.HugePagesInfo{ 999 { 1000 // size in KB 1001 PageSize: pageSize1Gb, 1002 NumPages: 1, 1003 }, 1004 }, 1005 }, 1006 { 1007 Id: 1, 1008 Memory: 2176 * mb, 1009 HugePages: []cadvisorapi.HugePagesInfo{ 1010 { 1011 // size in KB 1012 PageSize: pageSize1Gb, 1013 NumPages: 1, 1014 }, 1015 }, 1016 }, 1017 }, 1018 }, 1019 }, 1020 } 1021 1022 for _, testCase := range testCases { 1023 t.Run(testCase.description, func(t *testing.T) { 1024 t.Logf("[Start] %s", testCase.description) 1025 p, s, err := initTests(t, &testCase, nil) 1026 if err != nil { 1027 t.Fatalf("Unexpected error: %v", err) 1028 } 1029 1030 err = p.Start(s) 1031 if !reflect.DeepEqual(err, testCase.expectedError) { 1032 t.Fatalf("The actual error: %v is different from the expected one: %v", err, testCase.expectedError) 1033 } 1034 1035 if err != nil { 1036 return 1037 } 1038 1039 assignments := s.GetMemoryAssignments() 1040 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) { 1041 t.Fatalf("Actual assignments: %v is different from the expected one: %v", assignments, testCase.expectedAssignments) 1042 } 1043 1044 machineState := s.GetMachineState() 1045 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) { 1046 t.Fatalf("The actual machine state: %v is different from the expected one: %v", machineState, testCase.expectedMachineState) 1047 } 1048 }) 1049 } 1050} 1051 1052func TestStaticPolicyAllocate(t *testing.T) { 1053 testCases := []testStaticPolicy{ 1054 { 1055 description: "should do nothing for non-guaranteed pods", 1056 expectedAssignments: state.ContainerMemoryAssignments{}, 1057 machineState: state.NUMANodeMap{ 1058 0: &state.NUMANodeState{ 1059 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1060 v1.ResourceMemory: { 1061 Allocatable: 1536 * mb, 1062 Free: 1536 * mb, 1063 Reserved: 0, 1064 SystemReserved: 512 * mb, 1065 TotalMemSize: 2 * gb, 1066 }, 1067 hugepages1Gi: { 1068 Allocatable: gb, 1069 Free: gb, 1070 Reserved: 0, 1071 SystemReserved: 0, 1072 TotalMemSize: gb, 1073 }, 1074 }, 1075 Cells: []int{}, 1076 }, 1077 }, 1078 expectedMachineState: state.NUMANodeMap{ 1079 0: &state.NUMANodeState{ 1080 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1081 v1.ResourceMemory: { 1082 Allocatable: 1536 * mb, 1083 Free: 1536 * mb, 1084 Reserved: 0, 1085 SystemReserved: 512 * mb, 1086 TotalMemSize: 2 * gb, 1087 }, 1088 hugepages1Gi: { 1089 Allocatable: gb, 1090 Free: gb, 1091 Reserved: 0, 1092 SystemReserved: 0, 1093 TotalMemSize: gb, 1094 }, 1095 }, 1096 Cells: []int{}, 1097 }, 1098 }, 1099 systemReserved: systemReservedMemory{ 1100 0: map[v1.ResourceName]uint64{ 1101 v1.ResourceMemory: 512 * mb, 1102 }, 1103 }, 1104 pod: getPod("pod1", "container1", requirementsBurstable), 1105 expectedTopologyHints: nil, 1106 topologyHint: &topologymanager.TopologyHint{}, 1107 }, 1108 { 1109 description: "should do nothing once container already exists under the state file", 1110 assignments: state.ContainerMemoryAssignments{ 1111 "pod1": map[string][]state.Block{ 1112 "container1": { 1113 { 1114 NUMAAffinity: []int{0}, 1115 Type: v1.ResourceMemory, 1116 Size: gb, 1117 }, 1118 }, 1119 }, 1120 }, 1121 expectedAssignments: state.ContainerMemoryAssignments{ 1122 "pod1": map[string][]state.Block{ 1123 "container1": { 1124 { 1125 NUMAAffinity: []int{0}, 1126 Type: v1.ResourceMemory, 1127 Size: gb, 1128 }, 1129 }, 1130 }, 1131 }, 1132 machineState: state.NUMANodeMap{ 1133 0: &state.NUMANodeState{ 1134 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1135 v1.ResourceMemory: { 1136 Allocatable: 1536 * mb, 1137 Free: 512 * mb, 1138 Reserved: 1024 * mb, 1139 SystemReserved: 512 * mb, 1140 TotalMemSize: 2 * gb, 1141 }, 1142 hugepages1Gi: { 1143 Allocatable: gb, 1144 Free: gb, 1145 Reserved: 0, 1146 SystemReserved: 0, 1147 TotalMemSize: gb, 1148 }, 1149 }, 1150 Cells: []int{}, 1151 }, 1152 }, 1153 expectedMachineState: state.NUMANodeMap{ 1154 0: &state.NUMANodeState{ 1155 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1156 v1.ResourceMemory: { 1157 Allocatable: 1536 * mb, 1158 Free: 512 * mb, 1159 Reserved: 1024 * mb, 1160 SystemReserved: 512 * mb, 1161 TotalMemSize: 2 * gb, 1162 }, 1163 hugepages1Gi: { 1164 Allocatable: gb, 1165 Free: gb, 1166 Reserved: 0, 1167 SystemReserved: 0, 1168 TotalMemSize: gb, 1169 }, 1170 }, 1171 Cells: []int{}, 1172 }, 1173 }, 1174 systemReserved: systemReservedMemory{ 1175 0: map[v1.ResourceName]uint64{ 1176 v1.ResourceMemory: 512 * mb, 1177 }, 1178 }, 1179 pod: getPod("pod1", "container1", requirementsGuaranteed), 1180 expectedTopologyHints: nil, 1181 topologyHint: &topologymanager.TopologyHint{}, 1182 }, 1183 { 1184 description: "should calculate a default topology hint when no NUMA affinity was provided by the topology manager hint", 1185 assignments: state.ContainerMemoryAssignments{}, 1186 expectedAssignments: state.ContainerMemoryAssignments{ 1187 "pod1": map[string][]state.Block{ 1188 "container1": { 1189 { 1190 NUMAAffinity: []int{0}, 1191 Type: v1.ResourceMemory, 1192 Size: gb, 1193 }, 1194 { 1195 NUMAAffinity: []int{0}, 1196 Type: hugepages1Gi, 1197 Size: gb, 1198 }, 1199 }, 1200 }, 1201 }, 1202 machineState: state.NUMANodeMap{ 1203 0: &state.NUMANodeState{ 1204 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1205 v1.ResourceMemory: { 1206 Allocatable: 1536 * mb, 1207 Free: 1536 * mb, 1208 Reserved: 0, 1209 SystemReserved: 512 * mb, 1210 TotalMemSize: 2 * gb, 1211 }, 1212 hugepages1Gi: { 1213 Allocatable: gb, 1214 Free: gb, 1215 Reserved: 0, 1216 SystemReserved: 0, 1217 TotalMemSize: gb, 1218 }, 1219 }, 1220 Cells: []int{0}, 1221 }, 1222 }, 1223 expectedMachineState: state.NUMANodeMap{ 1224 0: &state.NUMANodeState{ 1225 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1226 v1.ResourceMemory: { 1227 Allocatable: 1536 * mb, 1228 Free: 512 * mb, 1229 Reserved: 1024 * mb, 1230 SystemReserved: 512 * mb, 1231 TotalMemSize: 2 * gb, 1232 }, 1233 hugepages1Gi: { 1234 Allocatable: gb, 1235 Free: 0, 1236 Reserved: gb, 1237 SystemReserved: 0, 1238 TotalMemSize: gb, 1239 }, 1240 }, 1241 Cells: []int{0}, 1242 NumberOfAssignments: 2, 1243 }, 1244 }, 1245 systemReserved: systemReservedMemory{ 1246 0: map[v1.ResourceName]uint64{ 1247 v1.ResourceMemory: 512 * mb, 1248 }, 1249 }, 1250 pod: getPod("pod1", "container1", requirementsGuaranteed), 1251 topologyHint: &topologymanager.TopologyHint{}, 1252 }, 1253 { 1254 description: "should fail when no NUMA affinity was provided under the topology manager hint and calculation of the default hint failed", 1255 assignments: state.ContainerMemoryAssignments{ 1256 "pod1": map[string][]state.Block{ 1257 "container1": { 1258 { 1259 NUMAAffinity: []int{0}, 1260 Type: v1.ResourceMemory, 1261 Size: gb, 1262 }, 1263 { 1264 NUMAAffinity: []int{0}, 1265 Type: hugepages1Gi, 1266 Size: gb, 1267 }, 1268 }, 1269 }, 1270 }, 1271 machineState: state.NUMANodeMap{ 1272 0: &state.NUMANodeState{ 1273 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1274 v1.ResourceMemory: { 1275 Allocatable: 1536 * mb, 1276 Free: 512 * mb, 1277 Reserved: 1024 * mb, 1278 SystemReserved: 512 * mb, 1279 TotalMemSize: 2 * gb, 1280 }, 1281 hugepages1Gi: { 1282 Allocatable: gb, 1283 Free: 0, 1284 Reserved: gb, 1285 SystemReserved: 0, 1286 TotalMemSize: gb, 1287 }, 1288 }, 1289 Cells: []int{0}, 1290 NumberOfAssignments: 2, 1291 }, 1292 }, 1293 systemReserved: systemReservedMemory{ 1294 0: map[v1.ResourceName]uint64{ 1295 v1.ResourceMemory: 512 * mb, 1296 }, 1297 }, 1298 pod: getPod("pod2", "container2", requirementsGuaranteed), 1299 expectedError: fmt.Errorf("[memorymanager] failed to get the default NUMA affinity, no NUMA nodes with enough memory is available"), 1300 topologyHint: &topologymanager.TopologyHint{}, 1301 }, 1302 { 1303 description: "should fail when no NUMA affinity was provided under the topology manager preferred hint and default hint has preferred false", 1304 assignments: state.ContainerMemoryAssignments{ 1305 "pod1": map[string][]state.Block{ 1306 "container1": { 1307 { 1308 NUMAAffinity: []int{0}, 1309 Type: v1.ResourceMemory, 1310 Size: 512 * mb, 1311 }, 1312 }, 1313 }, 1314 }, 1315 machineState: state.NUMANodeMap{ 1316 0: &state.NUMANodeState{ 1317 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1318 v1.ResourceMemory: { 1319 Allocatable: gb, 1320 Free: 512 * mb, 1321 Reserved: 512 * mb, 1322 SystemReserved: 512 * mb, 1323 TotalMemSize: 1536 * mb, 1324 }, 1325 hugepages1Gi: { 1326 Allocatable: gb, 1327 Free: gb, 1328 Reserved: 0, 1329 SystemReserved: 0, 1330 TotalMemSize: gb, 1331 }, 1332 }, 1333 Cells: []int{0}, 1334 NumberOfAssignments: 1, 1335 }, 1336 1: &state.NUMANodeState{ 1337 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1338 v1.ResourceMemory: { 1339 Allocatable: 512 * mb, 1340 Free: 512 * mb, 1341 Reserved: 0, 1342 SystemReserved: 512 * mb, 1343 TotalMemSize: 1536 * mb, 1344 }, 1345 hugepages1Gi: { 1346 Allocatable: gb, 1347 Free: gb, 1348 Reserved: 0, 1349 SystemReserved: 0, 1350 TotalMemSize: gb, 1351 }, 1352 }, 1353 Cells: []int{1}, 1354 NumberOfAssignments: 0, 1355 }, 1356 2: &state.NUMANodeState{ 1357 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1358 v1.ResourceMemory: { 1359 Allocatable: 512 * mb, 1360 Free: 512 * mb, 1361 Reserved: 0, 1362 SystemReserved: 512 * mb, 1363 TotalMemSize: 1536 * mb, 1364 }, 1365 hugepages1Gi: { 1366 Allocatable: gb, 1367 Free: gb, 1368 Reserved: 0, 1369 SystemReserved: 0, 1370 TotalMemSize: gb, 1371 }, 1372 }, 1373 Cells: []int{2}, 1374 NumberOfAssignments: 0, 1375 }, 1376 }, 1377 systemReserved: systemReservedMemory{ 1378 0: map[v1.ResourceName]uint64{ 1379 v1.ResourceMemory: 512 * mb, 1380 }, 1381 1: map[v1.ResourceName]uint64{ 1382 v1.ResourceMemory: 512 * mb, 1383 }, 1384 2: map[v1.ResourceName]uint64{ 1385 v1.ResourceMemory: 512 * mb, 1386 }, 1387 }, 1388 pod: getPod("pod2", "container2", requirementsGuaranteed), 1389 expectedError: fmt.Errorf("[memorymanager] failed to find the default preferred hint"), 1390 topologyHint: &topologymanager.TopologyHint{Preferred: true}, 1391 }, 1392 { 1393 description: "should fail when NUMA affinity provided under the topology manager hint did not satisfy container requirements and extended hint generation failed", 1394 machineState: state.NUMANodeMap{ 1395 0: &state.NUMANodeState{ 1396 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1397 v1.ResourceMemory: { 1398 Allocatable: 512 * mb, 1399 Free: 512 * mb, 1400 Reserved: 0, 1401 SystemReserved: 512 * mb, 1402 TotalMemSize: gb, 1403 }, 1404 hugepages1Gi: { 1405 Allocatable: gb, 1406 Free: gb, 1407 Reserved: 0, 1408 SystemReserved: 0, 1409 TotalMemSize: gb, 1410 }, 1411 }, 1412 Cells: []int{0}, 1413 NumberOfAssignments: 0, 1414 }, 1415 1: &state.NUMANodeState{ 1416 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1417 v1.ResourceMemory: { 1418 Allocatable: 1536 * mb, 1419 Free: 512 * mb, 1420 Reserved: gb, 1421 SystemReserved: 512 * mb, 1422 TotalMemSize: 2 * gb, 1423 }, 1424 hugepages1Gi: { 1425 Allocatable: gb, 1426 Free: gb, 1427 Reserved: 0, 1428 SystemReserved: 0, 1429 TotalMemSize: gb, 1430 }, 1431 }, 1432 Cells: []int{1, 2}, 1433 NumberOfAssignments: 1, 1434 }, 1435 2: &state.NUMANodeState{ 1436 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1437 v1.ResourceMemory: { 1438 Allocatable: 1536 * mb, 1439 Free: 512 * mb, 1440 Reserved: gb, 1441 SystemReserved: 512 * mb, 1442 TotalMemSize: 2 * gb, 1443 }, 1444 hugepages1Gi: { 1445 Allocatable: gb, 1446 Free: gb, 1447 Reserved: 0, 1448 SystemReserved: 0, 1449 TotalMemSize: gb, 1450 }, 1451 }, 1452 Cells: []int{1, 2}, 1453 NumberOfAssignments: 1, 1454 }, 1455 }, 1456 systemReserved: systemReservedMemory{ 1457 0: map[v1.ResourceName]uint64{ 1458 v1.ResourceMemory: 512 * mb, 1459 }, 1460 1: map[v1.ResourceName]uint64{ 1461 v1.ResourceMemory: 512 * mb, 1462 }, 1463 2: map[v1.ResourceName]uint64{ 1464 v1.ResourceMemory: 512 * mb, 1465 }, 1466 }, 1467 pod: getPod("pod1", "container1", requirementsGuaranteed), 1468 expectedError: fmt.Errorf("[memorymanager] failed to find NUMA nodes to extend the current topology hint"), 1469 topologyHint: &topologymanager.TopologyHint{NUMANodeAffinity: newNUMAAffinity(0), Preferred: false}, 1470 }, 1471 { 1472 description: "should fail when the topology manager provided the preferred hint and extended hint has preferred false", 1473 assignments: state.ContainerMemoryAssignments{ 1474 "pod1": map[string][]state.Block{ 1475 "container1": { 1476 { 1477 NUMAAffinity: []int{0}, 1478 Type: v1.ResourceMemory, 1479 Size: 512 * mb, 1480 }, 1481 }, 1482 }, 1483 }, 1484 machineState: state.NUMANodeMap{ 1485 0: &state.NUMANodeState{ 1486 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1487 v1.ResourceMemory: { 1488 Allocatable: gb, 1489 Free: 512 * mb, 1490 Reserved: 512 * mb, 1491 SystemReserved: 512 * mb, 1492 TotalMemSize: 1536 * mb, 1493 }, 1494 hugepages1Gi: { 1495 Allocatable: gb, 1496 Free: gb, 1497 Reserved: 0, 1498 SystemReserved: 0, 1499 TotalMemSize: gb, 1500 }, 1501 }, 1502 Cells: []int{0}, 1503 NumberOfAssignments: 1, 1504 }, 1505 1: &state.NUMANodeState{ 1506 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1507 v1.ResourceMemory: { 1508 Allocatable: 512 * mb, 1509 Free: 512 * mb, 1510 Reserved: 0, 1511 SystemReserved: 512 * mb, 1512 TotalMemSize: 1536 * mb, 1513 }, 1514 hugepages1Gi: { 1515 Allocatable: gb, 1516 Free: gb, 1517 Reserved: 0, 1518 SystemReserved: 0, 1519 TotalMemSize: gb, 1520 }, 1521 }, 1522 Cells: []int{1}, 1523 NumberOfAssignments: 0, 1524 }, 1525 2: &state.NUMANodeState{ 1526 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1527 v1.ResourceMemory: { 1528 Allocatable: 512 * mb, 1529 Free: 512 * mb, 1530 Reserved: 0, 1531 SystemReserved: 512 * mb, 1532 TotalMemSize: 1536 * mb, 1533 }, 1534 hugepages1Gi: { 1535 Allocatable: gb, 1536 Free: gb, 1537 Reserved: 0, 1538 SystemReserved: 0, 1539 TotalMemSize: gb, 1540 }, 1541 }, 1542 Cells: []int{2}, 1543 NumberOfAssignments: 0, 1544 }, 1545 }, 1546 systemReserved: systemReservedMemory{ 1547 0: map[v1.ResourceName]uint64{ 1548 v1.ResourceMemory: 512 * mb, 1549 }, 1550 1: map[v1.ResourceName]uint64{ 1551 v1.ResourceMemory: 512 * mb, 1552 }, 1553 2: map[v1.ResourceName]uint64{ 1554 v1.ResourceMemory: 512 * mb, 1555 }, 1556 }, 1557 pod: getPod("pod2", "container2", requirementsGuaranteed), 1558 expectedError: fmt.Errorf("[memorymanager] failed to find the extended preferred hint"), 1559 topologyHint: &topologymanager.TopologyHint{NUMANodeAffinity: newNUMAAffinity(1), Preferred: true}, 1560 }, 1561 { 1562 description: "should succeed to allocate memory from multiple NUMA nodes", 1563 assignments: state.ContainerMemoryAssignments{}, 1564 expectedAssignments: state.ContainerMemoryAssignments{ 1565 "pod1": map[string][]state.Block{ 1566 "container1": { 1567 { 1568 NUMAAffinity: []int{0, 1}, 1569 Type: v1.ResourceMemory, 1570 Size: gb, 1571 }, 1572 { 1573 NUMAAffinity: []int{0, 1}, 1574 Type: hugepages1Gi, 1575 Size: gb, 1576 }, 1577 }, 1578 }, 1579 }, 1580 machineState: state.NUMANodeMap{ 1581 0: &state.NUMANodeState{ 1582 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1583 v1.ResourceMemory: { 1584 Allocatable: 512 * mb, 1585 Free: 512 * mb, 1586 Reserved: 0, 1587 SystemReserved: 512 * mb, 1588 TotalMemSize: gb, 1589 }, 1590 hugepages1Gi: { 1591 Allocatable: gb, 1592 Free: gb, 1593 Reserved: 0, 1594 SystemReserved: 0, 1595 TotalMemSize: gb, 1596 }, 1597 }, 1598 Cells: []int{0}, 1599 NumberOfAssignments: 0, 1600 }, 1601 1: &state.NUMANodeState{ 1602 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1603 v1.ResourceMemory: { 1604 Allocatable: 512 * mb, 1605 Free: 512 * mb, 1606 Reserved: 0, 1607 SystemReserved: 512 * mb, 1608 TotalMemSize: gb, 1609 }, 1610 hugepages1Gi: { 1611 Allocatable: gb, 1612 Free: gb, 1613 Reserved: 0, 1614 SystemReserved: 0, 1615 TotalMemSize: gb, 1616 }, 1617 }, 1618 Cells: []int{1}, 1619 NumberOfAssignments: 0, 1620 }, 1621 2: &state.NUMANodeState{ 1622 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1623 v1.ResourceMemory: { 1624 Allocatable: 512 * mb, 1625 Free: 512 * mb, 1626 Reserved: 0, 1627 SystemReserved: 512 * mb, 1628 TotalMemSize: gb, 1629 }, 1630 hugepages1Gi: { 1631 Allocatable: gb, 1632 Free: gb, 1633 Reserved: 0, 1634 SystemReserved: 0, 1635 TotalMemSize: gb, 1636 }, 1637 }, 1638 Cells: []int{2}, 1639 NumberOfAssignments: 0, 1640 }, 1641 3: &state.NUMANodeState{ 1642 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1643 v1.ResourceMemory: { 1644 Allocatable: 512 * mb, 1645 Free: 512 * mb, 1646 Reserved: 0, 1647 SystemReserved: 512 * mb, 1648 TotalMemSize: gb, 1649 }, 1650 hugepages1Gi: { 1651 Allocatable: gb, 1652 Free: gb, 1653 Reserved: 0, 1654 SystemReserved: 0, 1655 TotalMemSize: gb, 1656 }, 1657 }, 1658 Cells: []int{3}, 1659 NumberOfAssignments: 0, 1660 }, 1661 }, 1662 expectedMachineState: state.NUMANodeMap{ 1663 0: &state.NUMANodeState{ 1664 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1665 v1.ResourceMemory: { 1666 Allocatable: 512 * mb, 1667 Free: 0, 1668 Reserved: 512 * mb, 1669 SystemReserved: 512 * mb, 1670 TotalMemSize: gb, 1671 }, 1672 hugepages1Gi: { 1673 Allocatable: gb, 1674 Free: 0, 1675 Reserved: gb, 1676 SystemReserved: 0, 1677 TotalMemSize: gb, 1678 }, 1679 }, 1680 Cells: []int{0, 1}, 1681 NumberOfAssignments: 2, 1682 }, 1683 1: &state.NUMANodeState{ 1684 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1685 v1.ResourceMemory: { 1686 Allocatable: 512 * mb, 1687 Free: 0, 1688 Reserved: 512 * mb, 1689 SystemReserved: 512 * mb, 1690 TotalMemSize: gb, 1691 }, 1692 hugepages1Gi: { 1693 Allocatable: gb, 1694 Free: gb, 1695 Reserved: 0, 1696 SystemReserved: 0, 1697 TotalMemSize: gb, 1698 }, 1699 }, 1700 Cells: []int{0, 1}, 1701 NumberOfAssignments: 2, 1702 }, 1703 2: &state.NUMANodeState{ 1704 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1705 v1.ResourceMemory: { 1706 Allocatable: 512 * mb, 1707 Free: 512 * mb, 1708 Reserved: 0, 1709 SystemReserved: 512 * mb, 1710 TotalMemSize: gb, 1711 }, 1712 hugepages1Gi: { 1713 Allocatable: gb, 1714 Free: gb, 1715 Reserved: 0, 1716 SystemReserved: 0, 1717 TotalMemSize: gb, 1718 }, 1719 }, 1720 Cells: []int{2}, 1721 NumberOfAssignments: 0, 1722 }, 1723 3: &state.NUMANodeState{ 1724 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1725 v1.ResourceMemory: { 1726 Allocatable: 512 * mb, 1727 Free: 512 * mb, 1728 Reserved: 0, 1729 SystemReserved: 512 * mb, 1730 TotalMemSize: gb, 1731 }, 1732 hugepages1Gi: { 1733 Allocatable: gb, 1734 Free: gb, 1735 Reserved: 0, 1736 SystemReserved: 0, 1737 TotalMemSize: gb, 1738 }, 1739 }, 1740 Cells: []int{3}, 1741 NumberOfAssignments: 0, 1742 }, 1743 }, 1744 systemReserved: systemReservedMemory{ 1745 0: map[v1.ResourceName]uint64{ 1746 v1.ResourceMemory: 512 * mb, 1747 }, 1748 1: map[v1.ResourceName]uint64{ 1749 v1.ResourceMemory: 512 * mb, 1750 }, 1751 2: map[v1.ResourceName]uint64{ 1752 v1.ResourceMemory: 512 * mb, 1753 }, 1754 3: map[v1.ResourceName]uint64{ 1755 v1.ResourceMemory: 512 * mb, 1756 }, 1757 }, 1758 pod: getPod("pod1", "container1", requirementsGuaranteed), 1759 topologyHint: &topologymanager.TopologyHint{Preferred: true}, 1760 }, 1761 } 1762 1763 for _, testCase := range testCases { 1764 t.Run(testCase.description, func(t *testing.T) { 1765 t.Logf("TestStaticPolicyAllocate %s", testCase.description) 1766 p, s, err := initTests(t, &testCase, testCase.topologyHint) 1767 if err != nil { 1768 t.Fatalf("Unexpected error: %v", err) 1769 } 1770 1771 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.Containers[0]) 1772 if !reflect.DeepEqual(err, testCase.expectedError) { 1773 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError) 1774 } 1775 1776 if err != nil { 1777 return 1778 } 1779 1780 assignments := s.GetMemoryAssignments() 1781 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) { 1782 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments) 1783 } 1784 1785 machineState := s.GetMachineState() 1786 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) { 1787 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState) 1788 } 1789 }) 1790 } 1791} 1792 1793func TestStaticPolicyAllocateWithInitContainers(t *testing.T) { 1794 testCases := []testStaticPolicy{ 1795 { 1796 description: "should re-use init containers memory, init containers requests 1Gi and 2Gi, apps containers 3Gi and 4Gi", 1797 assignments: state.ContainerMemoryAssignments{}, 1798 expectedAssignments: state.ContainerMemoryAssignments{ 1799 "pod1": map[string][]state.Block{ 1800 "initContainer1": { 1801 { 1802 NUMAAffinity: []int{0}, 1803 Type: v1.ResourceMemory, 1804 Size: 0, 1805 }, 1806 { 1807 NUMAAffinity: []int{0}, 1808 Type: hugepages1Gi, 1809 Size: 0, 1810 }, 1811 }, 1812 "initContainer2": { 1813 { 1814 NUMAAffinity: []int{0}, 1815 Type: v1.ResourceMemory, 1816 Size: 0, 1817 }, 1818 { 1819 NUMAAffinity: []int{0}, 1820 Type: hugepages1Gi, 1821 Size: 0, 1822 }, 1823 }, 1824 "container1": { 1825 { 1826 NUMAAffinity: []int{0}, 1827 Type: v1.ResourceMemory, 1828 Size: 3 * gb, 1829 }, 1830 { 1831 NUMAAffinity: []int{0}, 1832 Type: hugepages1Gi, 1833 Size: 3 * gb, 1834 }, 1835 }, 1836 "container2": { 1837 { 1838 NUMAAffinity: []int{0}, 1839 Type: v1.ResourceMemory, 1840 Size: 4 * gb, 1841 }, 1842 { 1843 NUMAAffinity: []int{0}, 1844 Type: hugepages1Gi, 1845 Size: 4 * gb, 1846 }, 1847 }, 1848 }, 1849 }, 1850 machineState: state.NUMANodeMap{ 1851 0: &state.NUMANodeState{ 1852 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1853 v1.ResourceMemory: { 1854 Allocatable: 7680 * mb, 1855 Free: 7680 * mb, 1856 Reserved: 0, 1857 SystemReserved: 512 * mb, 1858 TotalMemSize: 8 * gb, 1859 }, 1860 hugepages1Gi: { 1861 Allocatable: 8 * gb, 1862 Free: 8 * gb, 1863 Reserved: 0, 1864 SystemReserved: 0, 1865 TotalMemSize: 8 * gb, 1866 }, 1867 }, 1868 Cells: []int{0}, 1869 }, 1870 }, 1871 expectedMachineState: state.NUMANodeMap{ 1872 0: &state.NUMANodeState{ 1873 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 1874 v1.ResourceMemory: { 1875 Allocatable: 7680 * mb, 1876 Free: 512 * mb, 1877 Reserved: 7 * gb, 1878 SystemReserved: 512 * mb, 1879 TotalMemSize: 8 * gb, 1880 }, 1881 hugepages1Gi: { 1882 Allocatable: 8 * gb, 1883 Free: 1 * gb, 1884 Reserved: 7 * gb, 1885 SystemReserved: 0, 1886 TotalMemSize: 8 * gb, 1887 }, 1888 }, 1889 Cells: []int{0}, 1890 NumberOfAssignments: 8, 1891 }, 1892 }, 1893 systemReserved: systemReservedMemory{ 1894 0: map[v1.ResourceName]uint64{ 1895 v1.ResourceMemory: 512 * mb, 1896 }, 1897 }, 1898 pod: getPodWithInitContainers( 1899 "pod1", 1900 []v1.Container{ 1901 { 1902 Name: "container1", 1903 Resources: v1.ResourceRequirements{ 1904 Limits: v1.ResourceList{ 1905 v1.ResourceCPU: resource.MustParse("1000Mi"), 1906 v1.ResourceMemory: resource.MustParse("3Gi"), 1907 hugepages1Gi: resource.MustParse("3Gi"), 1908 }, 1909 Requests: v1.ResourceList{ 1910 v1.ResourceCPU: resource.MustParse("1000Mi"), 1911 v1.ResourceMemory: resource.MustParse("3Gi"), 1912 hugepages1Gi: resource.MustParse("3Gi"), 1913 }, 1914 }, 1915 }, 1916 { 1917 Name: "container2", 1918 Resources: v1.ResourceRequirements{ 1919 Limits: v1.ResourceList{ 1920 v1.ResourceCPU: resource.MustParse("1000Mi"), 1921 v1.ResourceMemory: resource.MustParse("4Gi"), 1922 hugepages1Gi: resource.MustParse("4Gi"), 1923 }, 1924 Requests: v1.ResourceList{ 1925 v1.ResourceCPU: resource.MustParse("1000Mi"), 1926 v1.ResourceMemory: resource.MustParse("4Gi"), 1927 hugepages1Gi: resource.MustParse("4Gi"), 1928 }, 1929 }, 1930 }, 1931 }, 1932 []v1.Container{ 1933 { 1934 Name: "initContainer1", 1935 Resources: v1.ResourceRequirements{ 1936 Limits: v1.ResourceList{ 1937 v1.ResourceCPU: resource.MustParse("1000Mi"), 1938 v1.ResourceMemory: resource.MustParse("1Gi"), 1939 hugepages1Gi: resource.MustParse("1Gi"), 1940 }, 1941 Requests: v1.ResourceList{ 1942 v1.ResourceCPU: resource.MustParse("1000Mi"), 1943 v1.ResourceMemory: resource.MustParse("1Gi"), 1944 hugepages1Gi: resource.MustParse("1Gi"), 1945 }, 1946 }, 1947 }, 1948 { 1949 Name: "initContainer2", 1950 Resources: v1.ResourceRequirements{ 1951 Limits: v1.ResourceList{ 1952 v1.ResourceCPU: resource.MustParse("1000Mi"), 1953 v1.ResourceMemory: resource.MustParse("2Gi"), 1954 hugepages1Gi: resource.MustParse("2Gi"), 1955 }, 1956 Requests: v1.ResourceList{ 1957 v1.ResourceCPU: resource.MustParse("1000Mi"), 1958 v1.ResourceMemory: resource.MustParse("2Gi"), 1959 hugepages1Gi: resource.MustParse("2Gi"), 1960 }, 1961 }, 1962 }, 1963 }, 1964 ), 1965 topologyHint: &topologymanager.TopologyHint{}, 1966 }, 1967 { 1968 description: "should re-use init containers memory, init containers requests 4Gi and 3Gi, apps containers 2Gi and 1Gi", 1969 assignments: state.ContainerMemoryAssignments{}, 1970 expectedAssignments: state.ContainerMemoryAssignments{ 1971 "pod1": map[string][]state.Block{ 1972 "initContainer1": { 1973 { 1974 NUMAAffinity: []int{0}, 1975 Type: v1.ResourceMemory, 1976 Size: 0, 1977 }, 1978 { 1979 NUMAAffinity: []int{0}, 1980 Type: hugepages1Gi, 1981 Size: 0, 1982 }, 1983 }, 1984 "initContainer2": { 1985 { 1986 NUMAAffinity: []int{0}, 1987 Type: v1.ResourceMemory, 1988 Size: gb, 1989 }, 1990 { 1991 NUMAAffinity: []int{0}, 1992 Type: hugepages1Gi, 1993 Size: gb, 1994 }, 1995 }, 1996 "container1": { 1997 { 1998 NUMAAffinity: []int{0}, 1999 Type: v1.ResourceMemory, 2000 Size: 2 * gb, 2001 }, 2002 { 2003 NUMAAffinity: []int{0}, 2004 Type: hugepages1Gi, 2005 Size: 2 * gb, 2006 }, 2007 }, 2008 "container2": { 2009 { 2010 NUMAAffinity: []int{0}, 2011 Type: v1.ResourceMemory, 2012 Size: gb, 2013 }, 2014 { 2015 NUMAAffinity: []int{0}, 2016 Type: hugepages1Gi, 2017 Size: gb, 2018 }, 2019 }, 2020 }, 2021 }, 2022 machineState: state.NUMANodeMap{ 2023 0: &state.NUMANodeState{ 2024 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2025 v1.ResourceMemory: { 2026 Allocatable: 7680 * mb, 2027 Free: 7680 * mb, 2028 Reserved: 0, 2029 SystemReserved: 512 * mb, 2030 TotalMemSize: 8 * gb, 2031 }, 2032 hugepages1Gi: { 2033 Allocatable: 8 * gb, 2034 Free: 8 * gb, 2035 Reserved: 0, 2036 SystemReserved: 0, 2037 TotalMemSize: 8 * gb, 2038 }, 2039 }, 2040 Cells: []int{0}, 2041 }, 2042 }, 2043 expectedMachineState: state.NUMANodeMap{ 2044 0: &state.NUMANodeState{ 2045 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2046 v1.ResourceMemory: { 2047 Allocatable: 7680 * mb, 2048 Free: 3584 * mb, 2049 Reserved: 4 * gb, 2050 SystemReserved: 512 * mb, 2051 TotalMemSize: 8 * gb, 2052 }, 2053 hugepages1Gi: { 2054 Allocatable: 8 * gb, 2055 Free: 4 * gb, 2056 Reserved: 4 * gb, 2057 SystemReserved: 0, 2058 TotalMemSize: 8 * gb, 2059 }, 2060 }, 2061 Cells: []int{0}, 2062 NumberOfAssignments: 8, 2063 }, 2064 }, 2065 systemReserved: systemReservedMemory{ 2066 0: map[v1.ResourceName]uint64{ 2067 v1.ResourceMemory: 512 * mb, 2068 }, 2069 }, 2070 pod: getPodWithInitContainers( 2071 "pod1", 2072 []v1.Container{ 2073 { 2074 Name: "container1", 2075 Resources: v1.ResourceRequirements{ 2076 Limits: v1.ResourceList{ 2077 v1.ResourceCPU: resource.MustParse("1000Mi"), 2078 v1.ResourceMemory: resource.MustParse("2Gi"), 2079 hugepages1Gi: resource.MustParse("2Gi"), 2080 }, 2081 Requests: v1.ResourceList{ 2082 v1.ResourceCPU: resource.MustParse("1000Mi"), 2083 v1.ResourceMemory: resource.MustParse("2Gi"), 2084 hugepages1Gi: resource.MustParse("2Gi"), 2085 }, 2086 }, 2087 }, 2088 { 2089 Name: "container2", 2090 Resources: v1.ResourceRequirements{ 2091 Limits: v1.ResourceList{ 2092 v1.ResourceCPU: resource.MustParse("1000Mi"), 2093 v1.ResourceMemory: resource.MustParse("1Gi"), 2094 hugepages1Gi: resource.MustParse("1Gi"), 2095 }, 2096 Requests: v1.ResourceList{ 2097 v1.ResourceCPU: resource.MustParse("1000Mi"), 2098 v1.ResourceMemory: resource.MustParse("1Gi"), 2099 hugepages1Gi: resource.MustParse("1Gi"), 2100 }, 2101 }, 2102 }, 2103 }, 2104 []v1.Container{ 2105 { 2106 Name: "initContainer1", 2107 Resources: v1.ResourceRequirements{ 2108 Limits: v1.ResourceList{ 2109 v1.ResourceCPU: resource.MustParse("1000Mi"), 2110 v1.ResourceMemory: resource.MustParse("4Gi"), 2111 hugepages1Gi: resource.MustParse("4Gi"), 2112 }, 2113 Requests: v1.ResourceList{ 2114 v1.ResourceCPU: resource.MustParse("1000Mi"), 2115 v1.ResourceMemory: resource.MustParse("4Gi"), 2116 hugepages1Gi: resource.MustParse("4Gi"), 2117 }, 2118 }, 2119 }, 2120 { 2121 Name: "initContainer2", 2122 Resources: v1.ResourceRequirements{ 2123 Limits: v1.ResourceList{ 2124 v1.ResourceCPU: resource.MustParse("1000Mi"), 2125 v1.ResourceMemory: resource.MustParse("3Gi"), 2126 hugepages1Gi: resource.MustParse("3Gi"), 2127 }, 2128 Requests: v1.ResourceList{ 2129 v1.ResourceCPU: resource.MustParse("1000Mi"), 2130 v1.ResourceMemory: resource.MustParse("3Gi"), 2131 hugepages1Gi: resource.MustParse("3Gi"), 2132 }, 2133 }, 2134 }, 2135 }, 2136 ), 2137 topologyHint: &topologymanager.TopologyHint{}, 2138 }, 2139 { 2140 description: "should re-use init containers memory, init containers requests 7Gi and 4Gi, apps containers 4Gi and 3Gi", 2141 assignments: state.ContainerMemoryAssignments{}, 2142 expectedAssignments: state.ContainerMemoryAssignments{ 2143 "pod1": map[string][]state.Block{ 2144 "initContainer1": { 2145 { 2146 NUMAAffinity: []int{0}, 2147 Type: v1.ResourceMemory, 2148 Size: 0, 2149 }, 2150 { 2151 NUMAAffinity: []int{0}, 2152 Type: hugepages1Gi, 2153 Size: 0, 2154 }, 2155 }, 2156 "initContainer2": { 2157 { 2158 NUMAAffinity: []int{0}, 2159 Type: v1.ResourceMemory, 2160 Size: 0, 2161 }, 2162 { 2163 NUMAAffinity: []int{0}, 2164 Type: hugepages1Gi, 2165 Size: 0, 2166 }, 2167 }, 2168 "container1": { 2169 { 2170 NUMAAffinity: []int{0}, 2171 Type: v1.ResourceMemory, 2172 Size: 4 * gb, 2173 }, 2174 { 2175 NUMAAffinity: []int{0}, 2176 Type: hugepages1Gi, 2177 Size: 4 * gb, 2178 }, 2179 }, 2180 "container2": { 2181 { 2182 NUMAAffinity: []int{0}, 2183 Type: v1.ResourceMemory, 2184 Size: 3 * gb, 2185 }, 2186 { 2187 NUMAAffinity: []int{0}, 2188 Type: hugepages1Gi, 2189 Size: 3 * gb, 2190 }, 2191 }, 2192 }, 2193 }, 2194 machineState: state.NUMANodeMap{ 2195 0: &state.NUMANodeState{ 2196 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2197 v1.ResourceMemory: { 2198 Allocatable: 7680 * mb, 2199 Free: 7680 * mb, 2200 Reserved: 0, 2201 SystemReserved: 512 * mb, 2202 TotalMemSize: 8 * gb, 2203 }, 2204 hugepages1Gi: { 2205 Allocatable: 8 * gb, 2206 Free: 8 * gb, 2207 Reserved: 0, 2208 SystemReserved: 0, 2209 TotalMemSize: 8 * gb, 2210 }, 2211 }, 2212 Cells: []int{0}, 2213 }, 2214 }, 2215 expectedMachineState: state.NUMANodeMap{ 2216 0: &state.NUMANodeState{ 2217 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2218 v1.ResourceMemory: { 2219 Allocatable: 7680 * mb, 2220 Free: 512 * mb, 2221 Reserved: 7 * gb, 2222 SystemReserved: 512 * mb, 2223 TotalMemSize: 8 * gb, 2224 }, 2225 hugepages1Gi: { 2226 Allocatable: 8 * gb, 2227 Free: 1 * gb, 2228 Reserved: 7 * gb, 2229 SystemReserved: 0, 2230 TotalMemSize: 8 * gb, 2231 }, 2232 }, 2233 Cells: []int{0}, 2234 NumberOfAssignments: 8, 2235 }, 2236 }, 2237 systemReserved: systemReservedMemory{ 2238 0: map[v1.ResourceName]uint64{ 2239 v1.ResourceMemory: 512 * mb, 2240 }, 2241 }, 2242 pod: getPodWithInitContainers( 2243 "pod1", 2244 []v1.Container{ 2245 { 2246 Name: "container1", 2247 Resources: v1.ResourceRequirements{ 2248 Limits: v1.ResourceList{ 2249 v1.ResourceCPU: resource.MustParse("1000Mi"), 2250 v1.ResourceMemory: resource.MustParse("4Gi"), 2251 hugepages1Gi: resource.MustParse("4Gi"), 2252 }, 2253 Requests: v1.ResourceList{ 2254 v1.ResourceCPU: resource.MustParse("1000Mi"), 2255 v1.ResourceMemory: resource.MustParse("4Gi"), 2256 hugepages1Gi: resource.MustParse("4Gi"), 2257 }, 2258 }, 2259 }, 2260 { 2261 Name: "container2", 2262 Resources: v1.ResourceRequirements{ 2263 Limits: v1.ResourceList{ 2264 v1.ResourceCPU: resource.MustParse("1000Mi"), 2265 v1.ResourceMemory: resource.MustParse("3Gi"), 2266 hugepages1Gi: resource.MustParse("3Gi"), 2267 }, 2268 Requests: v1.ResourceList{ 2269 v1.ResourceCPU: resource.MustParse("1000Mi"), 2270 v1.ResourceMemory: resource.MustParse("3Gi"), 2271 hugepages1Gi: resource.MustParse("3Gi"), 2272 }, 2273 }, 2274 }, 2275 }, 2276 []v1.Container{ 2277 { 2278 Name: "initContainer1", 2279 Resources: v1.ResourceRequirements{ 2280 Limits: v1.ResourceList{ 2281 v1.ResourceCPU: resource.MustParse("1000Mi"), 2282 v1.ResourceMemory: resource.MustParse("7Gi"), 2283 hugepages1Gi: resource.MustParse("7Gi"), 2284 }, 2285 Requests: v1.ResourceList{ 2286 v1.ResourceCPU: resource.MustParse("1000Mi"), 2287 v1.ResourceMemory: resource.MustParse("7Gi"), 2288 hugepages1Gi: resource.MustParse("7Gi"), 2289 }, 2290 }, 2291 }, 2292 { 2293 Name: "initContainer2", 2294 Resources: v1.ResourceRequirements{ 2295 Limits: v1.ResourceList{ 2296 v1.ResourceCPU: resource.MustParse("1000Mi"), 2297 v1.ResourceMemory: resource.MustParse("4Gi"), 2298 hugepages1Gi: resource.MustParse("4Gi"), 2299 }, 2300 Requests: v1.ResourceList{ 2301 v1.ResourceCPU: resource.MustParse("1000Mi"), 2302 v1.ResourceMemory: resource.MustParse("4Gi"), 2303 hugepages1Gi: resource.MustParse("4Gi"), 2304 }, 2305 }, 2306 }, 2307 }, 2308 ), 2309 topologyHint: &topologymanager.TopologyHint{}, 2310 }, 2311 } 2312 2313 for _, testCase := range testCases { 2314 t.Run(testCase.description, func(t *testing.T) { 2315 klog.InfoS("TestStaticPolicyAllocateWithInitContainers", "test name", testCase.description) 2316 p, s, err := initTests(t, &testCase, testCase.topologyHint) 2317 if err != nil { 2318 t.Fatalf("Unexpected error: %v", err) 2319 } 2320 2321 for i := range testCase.pod.Spec.InitContainers { 2322 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.InitContainers[i]) 2323 if !reflect.DeepEqual(err, testCase.expectedError) { 2324 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError) 2325 } 2326 } 2327 2328 for i := range testCase.pod.Spec.Containers { 2329 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.Containers[i]) 2330 if !reflect.DeepEqual(err, testCase.expectedError) { 2331 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError) 2332 } 2333 } 2334 2335 assignments := s.GetMemoryAssignments() 2336 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) { 2337 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments) 2338 } 2339 2340 machineState := s.GetMachineState() 2341 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) { 2342 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState) 2343 } 2344 }) 2345 } 2346} 2347 2348func TestStaticPolicyRemoveContainer(t *testing.T) { 2349 testCases := []testStaticPolicy{ 2350 { 2351 description: "should do nothing when the container does not exist under the state", 2352 expectedAssignments: state.ContainerMemoryAssignments{}, 2353 machineState: state.NUMANodeMap{ 2354 0: &state.NUMANodeState{ 2355 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2356 v1.ResourceMemory: { 2357 Allocatable: 1536 * mb, 2358 Free: 1536 * mb, 2359 Reserved: 0, 2360 SystemReserved: 512 * mb, 2361 TotalMemSize: 2 * gb, 2362 }, 2363 hugepages1Gi: { 2364 Allocatable: gb, 2365 Free: gb, 2366 Reserved: 0, 2367 SystemReserved: 0, 2368 TotalMemSize: gb, 2369 }, 2370 }, 2371 Cells: []int{}, 2372 }, 2373 }, 2374 expectedMachineState: state.NUMANodeMap{ 2375 0: &state.NUMANodeState{ 2376 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2377 v1.ResourceMemory: { 2378 Allocatable: 1536 * mb, 2379 Free: 1536 * mb, 2380 Reserved: 0, 2381 SystemReserved: 512 * mb, 2382 TotalMemSize: 2 * gb, 2383 }, 2384 hugepages1Gi: { 2385 Allocatable: gb, 2386 Free: gb, 2387 Reserved: 0, 2388 SystemReserved: 0, 2389 TotalMemSize: gb, 2390 }, 2391 }, 2392 Cells: []int{}, 2393 }, 2394 }, 2395 systemReserved: systemReservedMemory{ 2396 0: map[v1.ResourceName]uint64{ 2397 v1.ResourceMemory: 512 * mb, 2398 }, 2399 }, 2400 }, 2401 { 2402 description: "should delete the container assignment and update the machine state", 2403 assignments: state.ContainerMemoryAssignments{ 2404 "pod1": map[string][]state.Block{ 2405 "container1": { 2406 { 2407 NUMAAffinity: []int{0}, 2408 Type: v1.ResourceMemory, 2409 Size: gb, 2410 }, 2411 { 2412 NUMAAffinity: []int{0}, 2413 Type: hugepages1Gi, 2414 Size: gb, 2415 }, 2416 }, 2417 }, 2418 }, 2419 expectedAssignments: state.ContainerMemoryAssignments{}, 2420 machineState: state.NUMANodeMap{ 2421 0: &state.NUMANodeState{ 2422 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2423 v1.ResourceMemory: { 2424 Allocatable: 1536 * mb, 2425 Free: 512 * mb, 2426 Reserved: 1024 * mb, 2427 SystemReserved: 512 * mb, 2428 TotalMemSize: 2 * gb, 2429 }, 2430 hugepages1Gi: { 2431 Allocatable: gb, 2432 Free: 0, 2433 Reserved: gb, 2434 SystemReserved: 0, 2435 TotalMemSize: gb, 2436 }, 2437 }, 2438 NumberOfAssignments: 2, 2439 Cells: []int{0}, 2440 }, 2441 }, 2442 expectedMachineState: state.NUMANodeMap{ 2443 0: &state.NUMANodeState{ 2444 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2445 v1.ResourceMemory: { 2446 Allocatable: 1536 * mb, 2447 Free: 1536 * mb, 2448 Reserved: 0, 2449 SystemReserved: 512 * mb, 2450 TotalMemSize: 2 * gb, 2451 }, 2452 hugepages1Gi: { 2453 Allocatable: gb, 2454 Free: gb, 2455 Reserved: 0, 2456 SystemReserved: 0, 2457 TotalMemSize: gb, 2458 }, 2459 }, 2460 Cells: []int{0}, 2461 NumberOfAssignments: 0, 2462 }, 2463 }, 2464 systemReserved: systemReservedMemory{ 2465 0: map[v1.ResourceName]uint64{ 2466 v1.ResourceMemory: 512 * mb, 2467 }, 2468 }, 2469 }, 2470 { 2471 description: "should delete the cross NUMA container assignment and update the machine state", 2472 assignments: state.ContainerMemoryAssignments{ 2473 "pod1": map[string][]state.Block{ 2474 "container1": { 2475 { 2476 NUMAAffinity: []int{0, 1}, 2477 Type: v1.ResourceMemory, 2478 Size: gb, 2479 }, 2480 { 2481 NUMAAffinity: []int{0, 1}, 2482 Type: hugepages1Gi, 2483 Size: gb, 2484 }, 2485 }, 2486 }, 2487 }, 2488 expectedAssignments: state.ContainerMemoryAssignments{}, 2489 machineState: state.NUMANodeMap{ 2490 0: &state.NUMANodeState{ 2491 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2492 v1.ResourceMemory: { 2493 Allocatable: 512 * mb, 2494 Free: 0, 2495 Reserved: 512 * mb, 2496 SystemReserved: 512 * mb, 2497 TotalMemSize: gb, 2498 }, 2499 hugepages1Gi: { 2500 Allocatable: gb, 2501 Free: 0, 2502 Reserved: gb, 2503 SystemReserved: 0, 2504 TotalMemSize: gb, 2505 }, 2506 }, 2507 NumberOfAssignments: 2, 2508 Cells: []int{0, 1}, 2509 }, 2510 1: &state.NUMANodeState{ 2511 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2512 v1.ResourceMemory: { 2513 Allocatable: 512 * mb, 2514 Free: 0, 2515 Reserved: 512 * mb, 2516 SystemReserved: 512 * mb, 2517 TotalMemSize: gb, 2518 }, 2519 hugepages1Gi: { 2520 Allocatable: gb, 2521 Free: gb, 2522 Reserved: 0, 2523 SystemReserved: 0, 2524 TotalMemSize: gb, 2525 }, 2526 }, 2527 NumberOfAssignments: 2, 2528 Cells: []int{0, 1}, 2529 }, 2530 }, 2531 expectedMachineState: state.NUMANodeMap{ 2532 0: &state.NUMANodeState{ 2533 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2534 v1.ResourceMemory: { 2535 Allocatable: 512 * mb, 2536 Free: 512 * mb, 2537 Reserved: 0, 2538 SystemReserved: 512 * mb, 2539 TotalMemSize: gb, 2540 }, 2541 hugepages1Gi: { 2542 Allocatable: gb, 2543 Free: gb, 2544 Reserved: 0, 2545 SystemReserved: 0, 2546 TotalMemSize: gb, 2547 }, 2548 }, 2549 NumberOfAssignments: 0, 2550 Cells: []int{0}, 2551 }, 2552 1: &state.NUMANodeState{ 2553 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2554 v1.ResourceMemory: { 2555 Allocatable: 512 * mb, 2556 Free: 512 * mb, 2557 Reserved: 0, 2558 SystemReserved: 512 * mb, 2559 TotalMemSize: gb, 2560 }, 2561 hugepages1Gi: { 2562 Allocatable: gb, 2563 Free: gb, 2564 Reserved: 0, 2565 SystemReserved: 0, 2566 TotalMemSize: gb, 2567 }, 2568 }, 2569 NumberOfAssignments: 0, 2570 Cells: []int{1}, 2571 }, 2572 }, 2573 systemReserved: systemReservedMemory{ 2574 0: map[v1.ResourceName]uint64{ 2575 v1.ResourceMemory: 512 * mb, 2576 }, 2577 1: map[v1.ResourceName]uint64{ 2578 v1.ResourceMemory: 512 * mb, 2579 }, 2580 }, 2581 }, 2582 } 2583 2584 for _, testCase := range testCases { 2585 t.Run(testCase.description, func(t *testing.T) { 2586 p, s, err := initTests(t, &testCase, nil) 2587 if err != nil { 2588 t.Fatalf("Unexpected error: %v", err) 2589 } 2590 2591 p.RemoveContainer(s, "pod1", "container1") 2592 assignments := s.GetMemoryAssignments() 2593 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) { 2594 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments) 2595 } 2596 2597 machineState := s.GetMachineState() 2598 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) { 2599 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState) 2600 } 2601 }) 2602 } 2603} 2604 2605func TestStaticPolicyGetTopologyHints(t *testing.T) { 2606 testCases := []testStaticPolicy{ 2607 { 2608 description: "should not provide topology hints for non-guaranteed pods", 2609 pod: getPod("pod1", "container1", requirementsBurstable), 2610 systemReserved: systemReservedMemory{ 2611 0: map[v1.ResourceName]uint64{ 2612 v1.ResourceMemory: 512 * mb, 2613 }, 2614 }, 2615 expectedTopologyHints: nil, 2616 }, 2617 { 2618 description: "should provide topology hints based on the existent memory assignment", 2619 assignments: state.ContainerMemoryAssignments{ 2620 "pod1": map[string][]state.Block{ 2621 "container1": { 2622 { 2623 NUMAAffinity: []int{0}, 2624 Type: v1.ResourceMemory, 2625 Size: gb, 2626 }, 2627 { 2628 NUMAAffinity: []int{0}, 2629 Type: hugepages1Gi, 2630 Size: gb, 2631 }, 2632 }, 2633 }, 2634 }, 2635 pod: getPod("pod1", "container1", requirementsGuaranteed), 2636 systemReserved: systemReservedMemory{ 2637 0: map[v1.ResourceName]uint64{ 2638 v1.ResourceMemory: 512 * mb, 2639 }, 2640 }, 2641 expectedTopologyHints: map[string][]topologymanager.TopologyHint{ 2642 string(v1.ResourceMemory): { 2643 { 2644 NUMANodeAffinity: newNUMAAffinity(0), 2645 Preferred: true, 2646 }, 2647 }, 2648 string(hugepages1Gi): { 2649 { 2650 NUMANodeAffinity: newNUMAAffinity(0), 2651 Preferred: true, 2652 }, 2653 }, 2654 }, 2655 }, 2656 { 2657 description: "should calculate new topology hints, when the container does not exist under assignments", 2658 assignments: state.ContainerMemoryAssignments{ 2659 "pod1": map[string][]state.Block{ 2660 "container1": { 2661 { 2662 NUMAAffinity: []int{0, 1}, 2663 Type: v1.ResourceMemory, 2664 Size: 2 * gb, 2665 }, 2666 { 2667 NUMAAffinity: []int{0, 1}, 2668 Type: hugepages1Gi, 2669 Size: 2 * gb, 2670 }, 2671 }, 2672 }, 2673 }, 2674 machineState: state.NUMANodeMap{ 2675 0: &state.NUMANodeState{ 2676 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2677 v1.ResourceMemory: { 2678 Allocatable: 1536 * mb, 2679 Free: 0, 2680 Reserved: 1536 * mb, 2681 SystemReserved: 512 * mb, 2682 TotalMemSize: 2 * gb, 2683 }, 2684 hugepages1Gi: { 2685 Allocatable: gb, 2686 Free: 0, 2687 Reserved: gb, 2688 SystemReserved: 0, 2689 TotalMemSize: gb, 2690 }, 2691 }, 2692 Cells: []int{0, 1}, 2693 NumberOfAssignments: 2, 2694 }, 2695 1: &state.NUMANodeState{ 2696 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2697 v1.ResourceMemory: { 2698 Allocatable: 1536 * mb, 2699 Free: gb, 2700 Reserved: 512 * mb, 2701 SystemReserved: 512 * mb, 2702 TotalMemSize: 2 * gb, 2703 }, 2704 hugepages1Gi: { 2705 Allocatable: gb, 2706 Free: 0, 2707 Reserved: gb, 2708 SystemReserved: 0, 2709 TotalMemSize: gb, 2710 }, 2711 }, 2712 Cells: []int{0, 1}, 2713 NumberOfAssignments: 2, 2714 }, 2715 2: &state.NUMANodeState{ 2716 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2717 v1.ResourceMemory: { 2718 Allocatable: 1536 * mb, 2719 Free: 1536 * mb, 2720 Reserved: 0, 2721 SystemReserved: 512 * mb, 2722 TotalMemSize: 2 * gb, 2723 }, 2724 hugepages1Gi: { 2725 Allocatable: gb, 2726 Free: gb, 2727 Reserved: 0, 2728 SystemReserved: 0, 2729 TotalMemSize: gb, 2730 }, 2731 }, 2732 Cells: []int{2}, 2733 NumberOfAssignments: 0, 2734 }, 2735 3: &state.NUMANodeState{ 2736 MemoryMap: map[v1.ResourceName]*state.MemoryTable{ 2737 v1.ResourceMemory: { 2738 Allocatable: 1536 * mb, 2739 Free: 1536 * mb, 2740 Reserved: 0, 2741 SystemReserved: 512 * mb, 2742 TotalMemSize: 2 * gb, 2743 }, 2744 hugepages1Gi: { 2745 Allocatable: gb, 2746 Free: gb, 2747 Reserved: 0, 2748 SystemReserved: 0, 2749 TotalMemSize: gb, 2750 }, 2751 }, 2752 Cells: []int{3}, 2753 NumberOfAssignments: 0, 2754 }, 2755 }, 2756 pod: getPod("pod2", "container2", requirementsGuaranteed), 2757 systemReserved: systemReservedMemory{ 2758 0: map[v1.ResourceName]uint64{ 2759 v1.ResourceMemory: 512 * mb, 2760 }, 2761 1: map[v1.ResourceName]uint64{ 2762 v1.ResourceMemory: 512 * mb, 2763 }, 2764 2: map[v1.ResourceName]uint64{ 2765 v1.ResourceMemory: 512 * mb, 2766 }, 2767 3: map[v1.ResourceName]uint64{ 2768 v1.ResourceMemory: 512 * mb, 2769 }, 2770 }, 2771 expectedTopologyHints: map[string][]topologymanager.TopologyHint{ 2772 string(v1.ResourceMemory): { 2773 { 2774 NUMANodeAffinity: newNUMAAffinity(2), 2775 Preferred: true, 2776 }, 2777 { 2778 NUMANodeAffinity: newNUMAAffinity(3), 2779 Preferred: true, 2780 }, 2781 { 2782 NUMANodeAffinity: newNUMAAffinity(2, 3), 2783 Preferred: false, 2784 }, 2785 }, 2786 string(hugepages1Gi): { 2787 { 2788 NUMANodeAffinity: newNUMAAffinity(2), 2789 Preferred: true, 2790 }, 2791 { 2792 NUMANodeAffinity: newNUMAAffinity(3), 2793 Preferred: true, 2794 }, 2795 { 2796 NUMANodeAffinity: newNUMAAffinity(2, 3), 2797 Preferred: false, 2798 }, 2799 }, 2800 }, 2801 }, 2802 { 2803 description: "should fail when number of existing memory assignment resources are different from resources requested by container", 2804 assignments: state.ContainerMemoryAssignments{ 2805 "pod1": map[string][]state.Block{ 2806 "container1": { 2807 { 2808 NUMAAffinity: []int{0}, 2809 Type: v1.ResourceMemory, 2810 Size: gb, 2811 }, 2812 }, 2813 }, 2814 }, 2815 pod: getPod("pod1", "container1", requirementsGuaranteed), 2816 systemReserved: systemReservedMemory{ 2817 0: map[v1.ResourceName]uint64{ 2818 v1.ResourceMemory: 512 * mb, 2819 }, 2820 }, 2821 expectedTopologyHints: nil, 2822 }, 2823 { 2824 description: "should fail when existing memory assignment resources are different from resources requested by container", 2825 assignments: state.ContainerMemoryAssignments{ 2826 "pod1": map[string][]state.Block{ 2827 "container1": { 2828 { 2829 NUMAAffinity: []int{0}, 2830 Type: v1.ResourceMemory, 2831 Size: gb, 2832 }, 2833 { 2834 NUMAAffinity: []int{0}, 2835 Type: hugepages2M, 2836 Size: gb, 2837 }, 2838 }, 2839 }, 2840 }, 2841 pod: getPod("pod1", "container1", requirementsGuaranteed), 2842 systemReserved: systemReservedMemory{ 2843 0: map[v1.ResourceName]uint64{ 2844 v1.ResourceMemory: 512 * mb, 2845 }, 2846 }, 2847 expectedTopologyHints: nil, 2848 }, 2849 { 2850 description: "should fail when existing memory assignment size is different from one requested by the container", 2851 assignments: state.ContainerMemoryAssignments{ 2852 "pod1": map[string][]state.Block{ 2853 "container1": { 2854 { 2855 NUMAAffinity: []int{0}, 2856 Type: v1.ResourceMemory, 2857 Size: 512 * mb, 2858 }, 2859 { 2860 NUMAAffinity: []int{0}, 2861 Type: hugepages1Gi, 2862 Size: gb, 2863 }, 2864 }, 2865 }, 2866 }, 2867 pod: getPod("pod1", "container1", requirementsGuaranteed), 2868 systemReserved: systemReservedMemory{ 2869 0: map[v1.ResourceName]uint64{ 2870 v1.ResourceMemory: 512 * mb, 2871 }, 2872 }, 2873 expectedTopologyHints: nil, 2874 }, 2875 } 2876 2877 for _, testCase := range testCases { 2878 t.Run(testCase.description, func(t *testing.T) { 2879 p, s, err := initTests(t, &testCase, nil) 2880 if err != nil { 2881 t.Fatalf("Unexpected error: %v", err) 2882 } 2883 2884 topologyHints := p.GetTopologyHints(s, testCase.pod, &testCase.pod.Spec.Containers[0]) 2885 if !reflect.DeepEqual(topologyHints, testCase.expectedTopologyHints) { 2886 t.Fatalf("The actual topology hints: '%+v' are different from the expected one: '%+v'", topologyHints, testCase.expectedTopologyHints) 2887 } 2888 }) 2889 } 2890} 2891