github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/orm/topology/policy_numeric_test.go (about) 1 /* 2 Copyright 2022 The Katalyst 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 topology 18 19 import "testing" 20 21 func TestPolicyNumericMerge(t *testing.T) { 22 t.Parallel() 23 24 policy := NewNumericPolicy(defaultAlignResourceNames) 25 26 tcases := []policyMergeTestCase{ 27 { 28 name: "Two providers, 1 hint each, same mask, both preferred 1/2", 29 hp: []HintProvider{ 30 &mockHintProvider{ 31 map[string][]TopologyHint{ 32 "resource1": { 33 { 34 NUMANodeAffinity: NewTestBitMask(0), 35 Preferred: true, 36 }, 37 }, 38 }, 39 }, 40 &mockHintProvider{ 41 map[string][]TopologyHint{ 42 "resource2": { 43 { 44 NUMANodeAffinity: NewTestBitMask(0), 45 Preferred: true, 46 }, 47 }, 48 }, 49 }, 50 }, 51 expected: map[string]TopologyHint{ 52 "resource1": { 53 NUMANodeAffinity: NewTestBitMask(0), 54 Preferred: true, 55 }, 56 "resource2": { 57 NUMANodeAffinity: NewTestBitMask(0), 58 Preferred: true, 59 }, 60 }, 61 }, 62 { 63 name: "Two providers, 1 hint each, same mask, both preferred 2/2", 64 hp: []HintProvider{ 65 &mockHintProvider{ 66 map[string][]TopologyHint{ 67 "resource1": { 68 { 69 NUMANodeAffinity: NewTestBitMask(1), 70 Preferred: true, 71 }, 72 }, 73 }, 74 }, 75 &mockHintProvider{ 76 map[string][]TopologyHint{ 77 "resource2": { 78 { 79 NUMANodeAffinity: NewTestBitMask(1), 80 Preferred: true, 81 }, 82 }, 83 }, 84 }, 85 }, 86 expected: map[string]TopologyHint{ 87 "resource1": { 88 NUMANodeAffinity: NewTestBitMask(1), 89 Preferred: true, 90 }, 91 "resource2": { 92 NUMANodeAffinity: NewTestBitMask(1), 93 Preferred: true, 94 }, 95 }, 96 }, 97 { 98 name: "Two providers, 1 no hints, 1 single hint preferred 1/2", 99 hp: []HintProvider{ 100 &mockHintProvider{}, 101 &mockHintProvider{ 102 map[string][]TopologyHint{ 103 "resource": { 104 { 105 NUMANodeAffinity: NewTestBitMask(0), 106 Preferred: true, 107 }, 108 }, 109 }, 110 }, 111 }, 112 expected: map[string]TopologyHint{ 113 "resource": { 114 NUMANodeAffinity: NewTestBitMask(0), 115 Preferred: true, 116 }, 117 defaultResourceKey: { 118 NUMANodeAffinity: nil, 119 Preferred: true, 120 }, 121 }, 122 }, 123 { 124 name: "Two providers, 1 no hints, 1 single hint preferred 2/2", 125 hp: []HintProvider{ 126 &mockHintProvider{}, 127 &mockHintProvider{ 128 map[string][]TopologyHint{ 129 "resource": { 130 { 131 NUMANodeAffinity: NewTestBitMask(1), 132 Preferred: true, 133 }, 134 }, 135 }, 136 }, 137 }, 138 expected: map[string]TopologyHint{ 139 "resource": { 140 NUMANodeAffinity: NewTestBitMask(1), 141 Preferred: true, 142 }, 143 defaultResourceKey: { 144 NUMANodeAffinity: nil, 145 Preferred: true, 146 }, 147 }, 148 }, 149 { 150 name: "Two providers, 1 with 2 hints, 1 with single hint matching 1/2", 151 hp: []HintProvider{ 152 &mockHintProvider{ 153 map[string][]TopologyHint{ 154 "resource1": { 155 { 156 NUMANodeAffinity: NewTestBitMask(0), 157 Preferred: true, 158 }, 159 { 160 NUMANodeAffinity: NewTestBitMask(1), 161 Preferred: true, 162 }, 163 }, 164 }, 165 }, 166 &mockHintProvider{ 167 map[string][]TopologyHint{ 168 "resource2": { 169 { 170 NUMANodeAffinity: NewTestBitMask(0), 171 Preferred: true, 172 }, 173 }, 174 }, 175 }, 176 }, 177 expected: map[string]TopologyHint{ 178 "resource1": { 179 NUMANodeAffinity: NewTestBitMask(0), 180 Preferred: true, 181 }, 182 "resource2": { 183 NUMANodeAffinity: NewTestBitMask(0), 184 Preferred: true, 185 }, 186 }, 187 }, 188 189 { 190 name: "Two providers, 1 with 2 hints, 1 with single hint matching 2/2", 191 hp: []HintProvider{ 192 &mockHintProvider{ 193 map[string][]TopologyHint{ 194 "resource1": { 195 { 196 NUMANodeAffinity: NewTestBitMask(0), 197 Preferred: true, 198 }, 199 { 200 NUMANodeAffinity: NewTestBitMask(1), 201 Preferred: true, 202 }, 203 }, 204 }, 205 }, 206 &mockHintProvider{ 207 map[string][]TopologyHint{ 208 "resource2": { 209 { 210 NUMANodeAffinity: NewTestBitMask(1), 211 Preferred: true, 212 }, 213 }, 214 }, 215 }, 216 }, 217 expected: map[string]TopologyHint{ 218 "resource1": { 219 NUMANodeAffinity: NewTestBitMask(1), 220 Preferred: true, 221 }, 222 "resource2": { 223 NUMANodeAffinity: NewTestBitMask(1), 224 Preferred: true, 225 }, 226 }, 227 }, 228 { 229 name: "Two providers, both with 2 hints, matching narrower preferred hint from both", 230 hp: []HintProvider{ 231 &mockHintProvider{ 232 map[string][]TopologyHint{ 233 "resource1": { 234 { 235 NUMANodeAffinity: NewTestBitMask(0), 236 Preferred: true, 237 }, 238 { 239 NUMANodeAffinity: NewTestBitMask(1), 240 Preferred: true, 241 }, 242 }, 243 }, 244 }, 245 &mockHintProvider{ 246 map[string][]TopologyHint{ 247 "resource2": { 248 { 249 NUMANodeAffinity: NewTestBitMask(0), 250 Preferred: true, 251 }, 252 { 253 NUMANodeAffinity: NewTestBitMask(0, 1), 254 Preferred: false, 255 }, 256 }, 257 }, 258 }, 259 }, 260 expected: map[string]TopologyHint{ 261 "resource1": { 262 NUMANodeAffinity: NewTestBitMask(0), 263 Preferred: true, 264 }, 265 "resource2": { 266 NUMANodeAffinity: NewTestBitMask(0), 267 Preferred: true, 268 }, 269 }, 270 }, 271 { 272 name: "Ensure less narrow preferred hints are chosen over narrower non-preferred hints", 273 hp: []HintProvider{ 274 &mockHintProvider{ 275 map[string][]TopologyHint{ 276 "resource1": { 277 { 278 NUMANodeAffinity: NewTestBitMask(1), 279 Preferred: true, 280 }, 281 { 282 NUMANodeAffinity: NewTestBitMask(0, 1), 283 Preferred: false, 284 }, 285 }, 286 }, 287 }, 288 &mockHintProvider{ 289 map[string][]TopologyHint{ 290 "resource2": { 291 { 292 NUMANodeAffinity: NewTestBitMask(0), 293 Preferred: true, 294 }, 295 { 296 NUMANodeAffinity: NewTestBitMask(1), 297 Preferred: true, 298 }, 299 { 300 NUMANodeAffinity: NewTestBitMask(0, 1), 301 Preferred: false, 302 }, 303 }, 304 }, 305 }, 306 }, 307 expected: map[string]TopologyHint{ 308 "resource1": { 309 NUMANodeAffinity: NewTestBitMask(1), 310 Preferred: true, 311 }, 312 "resource2": { 313 NUMANodeAffinity: NewTestBitMask(1), 314 Preferred: true, 315 }, 316 }, 317 }, 318 { 319 name: "Multiple resources, same provider", 320 hp: []HintProvider{ 321 &mockHintProvider{ 322 map[string][]TopologyHint{ 323 "resource1": { 324 { 325 NUMANodeAffinity: NewTestBitMask(1), 326 Preferred: true, 327 }, 328 { 329 NUMANodeAffinity: NewTestBitMask(0, 1), 330 Preferred: false, 331 }, 332 }, 333 "resource2": { 334 { 335 NUMANodeAffinity: NewTestBitMask(0), 336 Preferred: true, 337 }, 338 { 339 NUMANodeAffinity: NewTestBitMask(1), 340 Preferred: true, 341 }, 342 { 343 NUMANodeAffinity: NewTestBitMask(0, 1), 344 Preferred: false, 345 }, 346 }, 347 }, 348 }, 349 }, 350 expected: map[string]TopologyHint{ 351 "resource1": { 352 NUMANodeAffinity: NewTestBitMask(1), 353 Preferred: true, 354 }, 355 "resource2": { 356 NUMANodeAffinity: NewTestBitMask(1), 357 Preferred: true, 358 }, 359 }, 360 }, 361 { 362 name: "TopologyHint not set", 363 hp: []HintProvider{}, 364 expected: map[string]TopologyHint{ 365 defaultResourceKey: { 366 NUMANodeAffinity: nil, 367 Preferred: true, 368 }, 369 }, 370 }, 371 { 372 name: "HintProvider returns empty non-nil map[string][]TopologyHint", 373 hp: []HintProvider{ 374 &mockHintProvider{ 375 map[string][]TopologyHint{}, 376 }, 377 }, 378 expected: map[string]TopologyHint{ 379 defaultResourceKey: { 380 NUMANodeAffinity: nil, 381 Preferred: true, 382 }, 383 }, 384 }, 385 { 386 name: "HintProvider returns -nil map[string][]TopologyHint from provider", 387 hp: []HintProvider{ 388 &mockHintProvider{ 389 map[string][]TopologyHint{ 390 "resource": nil, 391 }, 392 }, 393 }, 394 expected: map[string]TopologyHint{ 395 "resource": { 396 NUMANodeAffinity: nil, 397 Preferred: true, 398 }, 399 }, 400 }, 401 { 402 name: "HintProvider returns empty non-nil map[string][]TopologyHint from provider", 403 hp: []HintProvider{ 404 &mockHintProvider{ 405 map[string][]TopologyHint{ 406 "resource": {}, 407 }, 408 }, 409 }, 410 expected: nil, 411 }, 412 { 413 name: "Single TopologyHint with Preferred as true and NUMANodeAffinity as nil", 414 hp: []HintProvider{ 415 &mockHintProvider{ 416 map[string][]TopologyHint{ 417 "resource": { 418 { 419 NUMANodeAffinity: nil, 420 Preferred: true, 421 }, 422 }, 423 }, 424 }, 425 }, 426 expected: map[string]TopologyHint{ 427 "resource": { 428 NUMANodeAffinity: nil, 429 Preferred: true, 430 }, 431 }, 432 }, 433 { 434 name: "Two providers, 1 hint each, no common mask", 435 hp: []HintProvider{ 436 &mockHintProvider{ 437 map[string][]TopologyHint{ 438 "resource1": { 439 { 440 NUMANodeAffinity: NewTestBitMask(0), 441 Preferred: true, 442 }, 443 }, 444 }, 445 }, 446 &mockHintProvider{ 447 map[string][]TopologyHint{ 448 "resource2": { 449 { 450 NUMANodeAffinity: NewTestBitMask(1), 451 Preferred: true, 452 }, 453 }, 454 }, 455 }, 456 }, 457 expected: nil, 458 }, 459 { 460 name: "Two providers, 1 hint each, same mask, 1 preferred, 1 not 1/2", 461 hp: []HintProvider{ 462 &mockHintProvider{ 463 map[string][]TopologyHint{ 464 "resource1": { 465 { 466 NUMANodeAffinity: NewTestBitMask(0), 467 Preferred: true, 468 }, 469 }, 470 }, 471 }, 472 &mockHintProvider{ 473 map[string][]TopologyHint{ 474 "resource2": { 475 { 476 NUMANodeAffinity: NewTestBitMask(0), 477 Preferred: false, 478 }, 479 }, 480 }, 481 }, 482 }, 483 expected: map[string]TopologyHint{ 484 "resource1": { 485 NUMANodeAffinity: NewTestBitMask(0), 486 Preferred: true, 487 }, 488 "resource2": { 489 NUMANodeAffinity: NewTestBitMask(0), 490 Preferred: false, 491 }, 492 }, 493 }, 494 { 495 name: "Two providers, 1 hint each, same mask, 1 preferred, 1 not 2/2", 496 hp: []HintProvider{ 497 &mockHintProvider{ 498 map[string][]TopologyHint{ 499 "resource1": { 500 { 501 NUMANodeAffinity: NewTestBitMask(1), 502 Preferred: true, 503 }, 504 }, 505 }, 506 }, 507 &mockHintProvider{ 508 map[string][]TopologyHint{ 509 "resource2": { 510 { 511 NUMANodeAffinity: NewTestBitMask(1), 512 Preferred: false, 513 }, 514 }, 515 }, 516 }, 517 }, 518 expected: map[string]TopologyHint{ 519 "resource1": { 520 NUMANodeAffinity: NewTestBitMask(1), 521 Preferred: true, 522 }, 523 "resource2": { 524 NUMANodeAffinity: NewTestBitMask(1), 525 Preferred: false, 526 }, 527 }, 528 }, 529 { 530 name: "Two providers, 1 with 2 hints, 1 with single non-preferred hint matching", 531 hp: []HintProvider{ 532 &mockHintProvider{ 533 map[string][]TopologyHint{ 534 "resource1": { 535 { 536 NUMANodeAffinity: NewTestBitMask(0), 537 Preferred: true, 538 }, 539 { 540 NUMANodeAffinity: NewTestBitMask(1), 541 Preferred: true, 542 }, 543 }, 544 }, 545 }, 546 &mockHintProvider{ 547 map[string][]TopologyHint{ 548 "resource2": { 549 { 550 NUMANodeAffinity: NewTestBitMask(0, 1), 551 Preferred: false, 552 }, 553 }, 554 }, 555 }, 556 }, 557 expected: map[string]TopologyHint{ 558 "resource1": { 559 NUMANodeAffinity: NewTestBitMask(0), 560 Preferred: true, 561 }, 562 "resource2": { 563 NUMANodeAffinity: NewTestBitMask(0, 1), 564 Preferred: false, 565 }, 566 }, 567 }, 568 { 569 name: "Numeric hint generation, two resource", 570 hp: []HintProvider{ 571 &mockHintProvider{ 572 map[string][]TopologyHint{ 573 "resource1": { 574 { 575 NUMANodeAffinity: NewTestBitMask(0, 1), 576 Preferred: true, 577 }, 578 }, 579 "resource2": { 580 { 581 NUMANodeAffinity: NewTestBitMask(0), 582 Preferred: true, 583 }, 584 { 585 NUMANodeAffinity: NewTestBitMask(1), 586 Preferred: true, 587 }, 588 { 589 NUMANodeAffinity: NewTestBitMask(0, 1), 590 Preferred: false, 591 }, 592 }, 593 }, 594 }, 595 }, 596 expected: map[string]TopologyHint{ 597 "resource1": { 598 NUMANodeAffinity: NewTestBitMask(0, 1), 599 Preferred: true, 600 }, 601 "resource2": { 602 NUMANodeAffinity: NewTestBitMask(0), 603 Preferred: true, 604 }, 605 }, 606 }, 607 { 608 name: "Align cpu, memory, cpu with 2/2 hit, memory with 1/2, 2/2 hint", 609 hp: []HintProvider{ 610 &mockHintProvider{ 611 map[string][]TopologyHint{ 612 "cpu": { 613 { 614 NUMANodeAffinity: NewTestBitMask(0, 1), 615 Preferred: true, 616 }, 617 }, 618 "memory": { 619 { 620 NUMANodeAffinity: NewTestBitMask(0), 621 Preferred: true, 622 }, 623 { 624 NUMANodeAffinity: NewTestBitMask(1), 625 Preferred: true, 626 }, 627 { 628 NUMANodeAffinity: NewTestBitMask(0, 1), 629 Preferred: false, 630 }, 631 }, 632 "gpu": { 633 { 634 NUMANodeAffinity: NewTestBitMask(0), 635 Preferred: true, 636 }, 637 }, 638 }, 639 }, 640 }, 641 expected: map[string]TopologyHint{ 642 "cpu": { 643 NUMANodeAffinity: NewTestBitMask(0, 1), 644 Preferred: true, 645 }, 646 "memory": { 647 NUMANodeAffinity: NewTestBitMask(0, 1), 648 Preferred: false, 649 }, 650 "gpu": { 651 NUMANodeAffinity: NewTestBitMask(0), 652 Preferred: true, 653 }, 654 }, 655 }, 656 { 657 name: "Align cpu, memory, cpu with 2/2 hit, memory with 1/2, 2/2 hint", 658 hp: []HintProvider{ 659 &mockHintProvider{ 660 map[string][]TopologyHint{ 661 "cpu": { 662 { 663 NUMANodeAffinity: NewTestBitMask(0, 1), 664 Preferred: true, 665 }, 666 }, 667 "memory": { 668 { 669 NUMANodeAffinity: NewTestBitMask(0), 670 Preferred: true, 671 }, 672 { 673 NUMANodeAffinity: NewTestBitMask(1), 674 Preferred: true, 675 }, 676 }, 677 "gpu": { 678 { 679 NUMANodeAffinity: NewTestBitMask(0), 680 Preferred: true, 681 }, 682 }, 683 }, 684 }, 685 }, 686 expected: nil, 687 }, 688 { 689 name: "Align cpu, cpu with 2/2 hit", 690 hp: []HintProvider{ 691 &mockHintProvider{ 692 map[string][]TopologyHint{ 693 "cpu": { 694 { 695 NUMANodeAffinity: NewTestBitMask(0, 1), 696 Preferred: false, 697 }, 698 }, 699 "gpu": { 700 { 701 NUMANodeAffinity: NewTestBitMask(0), 702 Preferred: true, 703 }, 704 }, 705 }, 706 }, 707 }, 708 expected: nil, 709 }, 710 { 711 name: "Align cpu, cpu with 1/2, 2/2 hit", 712 hp: []HintProvider{ 713 &mockHintProvider{ 714 map[string][]TopologyHint{ 715 "cpu": { 716 { 717 NUMANodeAffinity: NewTestBitMask(0, 1), 718 Preferred: false, 719 }, 720 { 721 NUMANodeAffinity: NewTestBitMask(0), 722 Preferred: true, 723 }, 724 }, 725 "gpu": { 726 { 727 NUMANodeAffinity: NewTestBitMask(0), 728 Preferred: false, 729 }, 730 }, 731 }, 732 }, 733 }, 734 expected: map[string]TopologyHint{ 735 "cpu": { 736 NUMANodeAffinity: NewTestBitMask(0), 737 Preferred: true, 738 }, 739 "gpu": { 740 NUMANodeAffinity: NewTestBitMask(0), 741 Preferred: false, 742 }, 743 }, 744 }, 745 { 746 name: "Align cpu, cpu with 1/2 hit, gpu with 1/2, 2/2 hint", 747 hp: []HintProvider{ 748 &mockHintProvider{ 749 map[string][]TopologyHint{ 750 "cpu": { 751 { 752 NUMANodeAffinity: NewTestBitMask(0), 753 Preferred: true, 754 }, 755 }, 756 "gpu": { 757 { 758 NUMANodeAffinity: NewTestBitMask(0, 1), 759 Preferred: false, 760 }, 761 { 762 NUMANodeAffinity: NewTestBitMask(0), 763 Preferred: true, 764 }, 765 }, 766 }, 767 }, 768 }, 769 expected: map[string]TopologyHint{ 770 "cpu": { 771 NUMANodeAffinity: NewTestBitMask(0), 772 Preferred: true, 773 }, 774 "gpu": { 775 NUMANodeAffinity: NewTestBitMask(0), 776 Preferred: true, 777 }, 778 }, 779 }, 780 { 781 name: "Align cpu, memory, cpu with 2/2 hit, memory with 1/2, 2/2 hint", 782 hp: []HintProvider{ 783 &mockHintProvider{ 784 map[string][]TopologyHint{ 785 "gpu": { 786 { 787 NUMANodeAffinity: NewTestBitMask(0, 1), 788 Preferred: false, 789 }, 790 { 791 NUMANodeAffinity: NewTestBitMask(0), 792 Preferred: true, 793 }, 794 }, 795 "cpu": { 796 { 797 NUMANodeAffinity: NewTestBitMask(0, 1), 798 Preferred: true, 799 }, 800 }, 801 "memory": { 802 { 803 NUMANodeAffinity: NewTestBitMask(0), 804 Preferred: true, 805 }, 806 { 807 NUMANodeAffinity: NewTestBitMask(1), 808 Preferred: true, 809 }, 810 { 811 NUMANodeAffinity: NewTestBitMask(0, 1), 812 Preferred: false, 813 }, 814 }, 815 }, 816 }, 817 }, 818 expected: map[string]TopologyHint{ 819 "cpu": { 820 NUMANodeAffinity: NewTestBitMask(0, 1), 821 Preferred: true, 822 }, 823 "memory": { 824 NUMANodeAffinity: NewTestBitMask(0, 1), 825 Preferred: false, 826 }, 827 "gpu": { 828 NUMANodeAffinity: NewTestBitMask(0), 829 Preferred: true, 830 }, 831 }, 832 }, 833 { 834 name: "Align cpu, memory, nil, nil provider to test append bug", 835 hp: []HintProvider{ 836 &mockHintProvider{}, 837 &mockHintProvider{}, 838 &mockHintProvider{ 839 map[string][]TopologyHint{ 840 "cpu": { 841 { 842 NUMANodeAffinity: NewTestBitMask(0), 843 Preferred: true, 844 }, 845 { 846 NUMANodeAffinity: NewTestBitMask(1), 847 Preferred: true, 848 }, 849 }, 850 "memory": { 851 { 852 NUMANodeAffinity: NewTestBitMask(0), 853 Preferred: true, 854 }, 855 { 856 NUMANodeAffinity: NewTestBitMask(1), 857 Preferred: true, 858 }, 859 }, 860 }, 861 }, 862 }, 863 expected: map[string]TopologyHint{ 864 defaultResourceKey: { 865 NUMANodeAffinity: nil, 866 Preferred: true, 867 }, 868 "cpu": { 869 NUMANodeAffinity: NewTestBitMask(0), 870 Preferred: true, 871 }, 872 "memory": { 873 NUMANodeAffinity: NewTestBitMask(0), 874 Preferred: true, 875 }, 876 }, 877 }, 878 { 879 name: "Align cpu, memory. cpu nil preferred nil hint, memory with 2/2 hint", 880 hp: []HintProvider{ 881 &mockHintProvider{ 882 map[string][]TopologyHint{ 883 "memory": { 884 { 885 NUMANodeAffinity: NewTestBitMask(0, 1), 886 Preferred: true, 887 }, 888 }, 889 "cpu": { 890 { 891 NUMANodeAffinity: nil, 892 Preferred: true, 893 }, 894 }, 895 }, 896 }, 897 }, 898 expected: map[string]TopologyHint{ 899 "memory": { 900 NUMANodeAffinity: NewTestBitMask(0, 1), 901 Preferred: true, 902 }, 903 "cpu": { 904 NUMANodeAffinity: nil, 905 Preferred: true, 906 }, 907 }, 908 }, 909 } 910 testPolicyMerge(policy, tcases, t) 911 }