1
16
17 package topologymanager
18
19 import (
20 "reflect"
21 "testing"
22
23 "k8s.io/api/core/v1"
24 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
25 )
26
27 type policyMergeTestCase struct {
28 name string
29 hp []HintProvider
30 expected TopologyHint
31 }
32
33 func commonPolicyMergeTestCases(numaNodes []int) []policyMergeTestCase {
34 return []policyMergeTestCase{
35 {
36 name: "Two providers, 1 hint each, same mask, both preferred 1/2",
37 hp: []HintProvider{
38 &mockHintProvider{
39 map[string][]TopologyHint{
40 "resource1": {
41 {
42 NUMANodeAffinity: NewTestBitMask(0),
43 Preferred: true,
44 },
45 },
46 },
47 },
48 &mockHintProvider{
49 map[string][]TopologyHint{
50 "resource2": {
51 {
52 NUMANodeAffinity: NewTestBitMask(0),
53 Preferred: true,
54 },
55 },
56 },
57 },
58 },
59 expected: TopologyHint{
60 NUMANodeAffinity: NewTestBitMask(0),
61 Preferred: true,
62 },
63 },
64 {
65 name: "Two providers, 1 hint each, same mask, both preferred 2/2",
66 hp: []HintProvider{
67 &mockHintProvider{
68 map[string][]TopologyHint{
69 "resource1": {
70 {
71 NUMANodeAffinity: NewTestBitMask(1),
72 Preferred: true,
73 },
74 },
75 },
76 },
77 &mockHintProvider{
78 map[string][]TopologyHint{
79 "resource2": {
80 {
81 NUMANodeAffinity: NewTestBitMask(1),
82 Preferred: true,
83 },
84 },
85 },
86 },
87 },
88 expected: TopologyHint{
89 NUMANodeAffinity: NewTestBitMask(1),
90 Preferred: true,
91 },
92 },
93 {
94 name: "Two providers, 1 no hints, 1 single hint preferred 1/2",
95 hp: []HintProvider{
96 &mockHintProvider{},
97 &mockHintProvider{
98 map[string][]TopologyHint{
99 "resource": {
100 {
101 NUMANodeAffinity: NewTestBitMask(0),
102 Preferred: true,
103 },
104 },
105 },
106 },
107 },
108 expected: TopologyHint{
109 NUMANodeAffinity: NewTestBitMask(0),
110 Preferred: true,
111 },
112 },
113 {
114 name: "Two providers, 1 no hints, 1 single hint preferred 2/2",
115 hp: []HintProvider{
116 &mockHintProvider{},
117 &mockHintProvider{
118 map[string][]TopologyHint{
119 "resource": {
120 {
121 NUMANodeAffinity: NewTestBitMask(1),
122 Preferred: true,
123 },
124 },
125 },
126 },
127 },
128 expected: TopologyHint{
129 NUMANodeAffinity: NewTestBitMask(1),
130 Preferred: true,
131 },
132 },
133 {
134 name: "Two providers, 1 with 2 hints, 1 with single hint matching 1/2",
135 hp: []HintProvider{
136 &mockHintProvider{
137 map[string][]TopologyHint{
138 "resource1": {
139 {
140 NUMANodeAffinity: NewTestBitMask(0),
141 Preferred: true,
142 },
143 {
144 NUMANodeAffinity: NewTestBitMask(1),
145 Preferred: true,
146 },
147 },
148 },
149 },
150 &mockHintProvider{
151 map[string][]TopologyHint{
152 "resource2": {
153 {
154 NUMANodeAffinity: NewTestBitMask(0),
155 Preferred: true,
156 },
157 },
158 },
159 },
160 },
161 expected: TopologyHint{
162 NUMANodeAffinity: NewTestBitMask(0),
163 Preferred: true,
164 },
165 },
166 {
167 name: "Two providers, 1 with 2 hints, 1 with single hint matching 2/2",
168 hp: []HintProvider{
169 &mockHintProvider{
170 map[string][]TopologyHint{
171 "resource1": {
172 {
173 NUMANodeAffinity: NewTestBitMask(0),
174 Preferred: true,
175 },
176 {
177 NUMANodeAffinity: NewTestBitMask(1),
178 Preferred: true,
179 },
180 },
181 },
182 },
183 &mockHintProvider{
184 map[string][]TopologyHint{
185 "resource2": {
186 {
187 NUMANodeAffinity: NewTestBitMask(1),
188 Preferred: true,
189 },
190 },
191 },
192 },
193 },
194 expected: TopologyHint{
195 NUMANodeAffinity: NewTestBitMask(1),
196 Preferred: true,
197 },
198 },
199 {
200 name: "Two providers, both with 2 hints, matching narrower preferred hint from both",
201 hp: []HintProvider{
202 &mockHintProvider{
203 map[string][]TopologyHint{
204 "resource1": {
205 {
206 NUMANodeAffinity: NewTestBitMask(0),
207 Preferred: true,
208 },
209 {
210 NUMANodeAffinity: NewTestBitMask(1),
211 Preferred: true,
212 },
213 },
214 },
215 },
216 &mockHintProvider{
217 map[string][]TopologyHint{
218 "resource2": {
219 {
220 NUMANodeAffinity: NewTestBitMask(0),
221 Preferred: true,
222 },
223 {
224 NUMANodeAffinity: NewTestBitMask(0, 1),
225 Preferred: false,
226 },
227 },
228 },
229 },
230 },
231 expected: TopologyHint{
232 NUMANodeAffinity: NewTestBitMask(0),
233 Preferred: true,
234 },
235 },
236 {
237 name: "Ensure less narrow preferred hints are chosen over narrower non-preferred hints",
238 hp: []HintProvider{
239 &mockHintProvider{
240 map[string][]TopologyHint{
241 "resource1": {
242 {
243 NUMANodeAffinity: NewTestBitMask(1),
244 Preferred: true,
245 },
246 {
247 NUMANodeAffinity: NewTestBitMask(0, 1),
248 Preferred: false,
249 },
250 },
251 },
252 },
253 &mockHintProvider{
254 map[string][]TopologyHint{
255 "resource2": {
256 {
257 NUMANodeAffinity: NewTestBitMask(0),
258 Preferred: true,
259 },
260 {
261 NUMANodeAffinity: NewTestBitMask(1),
262 Preferred: true,
263 },
264 {
265 NUMANodeAffinity: NewTestBitMask(0, 1),
266 Preferred: false,
267 },
268 },
269 },
270 },
271 },
272 expected: TopologyHint{
273 NUMANodeAffinity: NewTestBitMask(1),
274 Preferred: true,
275 },
276 },
277 {
278 name: "Multiple resources, same provider",
279 hp: []HintProvider{
280 &mockHintProvider{
281 map[string][]TopologyHint{
282 "resource1": {
283 {
284 NUMANodeAffinity: NewTestBitMask(1),
285 Preferred: true,
286 },
287 {
288 NUMANodeAffinity: NewTestBitMask(0, 1),
289 Preferred: false,
290 },
291 },
292 "resource2": {
293 {
294 NUMANodeAffinity: NewTestBitMask(0),
295 Preferred: true,
296 },
297 {
298 NUMANodeAffinity: NewTestBitMask(1),
299 Preferred: true,
300 },
301 {
302 NUMANodeAffinity: NewTestBitMask(0, 1),
303 Preferred: false,
304 },
305 },
306 },
307 },
308 },
309 expected: TopologyHint{
310 NUMANodeAffinity: NewTestBitMask(1),
311 Preferred: true,
312 },
313 },
314 }
315 }
316
317 func (p *bestEffortPolicy) mergeTestCases(numaNodes []int) []policyMergeTestCase {
318 return []policyMergeTestCase{
319 {
320 name: "Two providers, 2 hints each, same mask (some with different bits), same preferred",
321 hp: []HintProvider{
322 &mockHintProvider{
323 map[string][]TopologyHint{
324 "resource1": {
325 {
326 NUMANodeAffinity: NewTestBitMask(0, 1),
327 Preferred: true,
328 },
329 {
330 NUMANodeAffinity: NewTestBitMask(0, 2),
331 Preferred: true,
332 },
333 },
334 },
335 },
336 &mockHintProvider{
337 map[string][]TopologyHint{
338 "resource2": {
339 {
340 NUMANodeAffinity: NewTestBitMask(0, 1),
341 Preferred: true,
342 },
343 {
344 NUMANodeAffinity: NewTestBitMask(0, 2),
345 Preferred: true,
346 },
347 },
348 },
349 },
350 },
351 expected: TopologyHint{
352 NUMANodeAffinity: NewTestBitMask(0, 1),
353 Preferred: true,
354 },
355 },
356 {
357 name: "TopologyHint not set",
358 hp: []HintProvider{},
359 expected: TopologyHint{
360 NUMANodeAffinity: NewTestBitMask(numaNodes...),
361 Preferred: true,
362 },
363 },
364 {
365 name: "HintProvider returns empty non-nil map[string][]TopologyHint",
366 hp: []HintProvider{
367 &mockHintProvider{
368 map[string][]TopologyHint{},
369 },
370 },
371 expected: TopologyHint{
372 NUMANodeAffinity: NewTestBitMask(numaNodes...),
373 Preferred: true,
374 },
375 },
376 {
377 name: "HintProvider returns -nil map[string][]TopologyHint from provider",
378 hp: []HintProvider{
379 &mockHintProvider{
380 map[string][]TopologyHint{
381 "resource": nil,
382 },
383 },
384 },
385 expected: TopologyHint{
386 NUMANodeAffinity: NewTestBitMask(numaNodes...),
387 Preferred: true,
388 },
389 },
390 {
391 name: "HintProvider returns empty non-nil map[string][]TopologyHint from provider", hp: []HintProvider{
392 &mockHintProvider{
393 map[string][]TopologyHint{
394 "resource": {},
395 },
396 },
397 },
398 expected: TopologyHint{
399 NUMANodeAffinity: NewTestBitMask(numaNodes...),
400 Preferred: false,
401 },
402 },
403 {
404 name: "Single TopologyHint with Preferred as true and NUMANodeAffinity as nil",
405 hp: []HintProvider{
406 &mockHintProvider{
407 map[string][]TopologyHint{
408 "resource": {
409 {
410 NUMANodeAffinity: nil,
411 Preferred: true,
412 },
413 },
414 },
415 },
416 },
417 expected: TopologyHint{
418 NUMANodeAffinity: NewTestBitMask(numaNodes...),
419 Preferred: true,
420 },
421 },
422 {
423 name: "Single TopologyHint with Preferred as false and NUMANodeAffinity as nil",
424 hp: []HintProvider{
425 &mockHintProvider{
426 map[string][]TopologyHint{
427 "resource": {
428 {
429 NUMANodeAffinity: nil,
430 Preferred: false,
431 },
432 },
433 },
434 },
435 },
436 expected: TopologyHint{
437 NUMANodeAffinity: NewTestBitMask(numaNodes...),
438 Preferred: false,
439 },
440 },
441 {
442 name: "Two providers, 1 hint each, no common mask",
443 hp: []HintProvider{
444 &mockHintProvider{
445 map[string][]TopologyHint{
446 "resource1": {
447 {
448 NUMANodeAffinity: NewTestBitMask(0),
449 Preferred: true,
450 },
451 },
452 },
453 },
454 &mockHintProvider{
455 map[string][]TopologyHint{
456 "resource2": {
457 {
458 NUMANodeAffinity: NewTestBitMask(1),
459 Preferred: true,
460 },
461 },
462 },
463 },
464 },
465 expected: TopologyHint{
466 NUMANodeAffinity: NewTestBitMask(numaNodes...),
467 Preferred: false,
468 },
469 },
470 {
471 name: "Two providers, 1 hint each, same mask, 1 preferred, 1 not 1/2",
472 hp: []HintProvider{
473 &mockHintProvider{
474 map[string][]TopologyHint{
475 "resource1": {
476 {
477 NUMANodeAffinity: NewTestBitMask(0),
478 Preferred: true,
479 },
480 },
481 },
482 },
483 &mockHintProvider{
484 map[string][]TopologyHint{
485 "resource2": {
486 {
487 NUMANodeAffinity: NewTestBitMask(0),
488 Preferred: false,
489 },
490 },
491 },
492 },
493 },
494 expected: TopologyHint{
495 NUMANodeAffinity: NewTestBitMask(0),
496 Preferred: false,
497 },
498 },
499 {
500 name: "Two providers, 1 hint each, same mask, 1 preferred, 1 not 2/2",
501 hp: []HintProvider{
502 &mockHintProvider{
503 map[string][]TopologyHint{
504 "resource1": {
505 {
506 NUMANodeAffinity: NewTestBitMask(1),
507 Preferred: true,
508 },
509 },
510 },
511 },
512 &mockHintProvider{
513 map[string][]TopologyHint{
514 "resource2": {
515 {
516 NUMANodeAffinity: NewTestBitMask(1),
517 Preferred: false,
518 },
519 },
520 },
521 },
522 },
523 expected: TopologyHint{
524 NUMANodeAffinity: NewTestBitMask(1),
525 Preferred: false,
526 },
527 },
528 {
529 name: "Two providers, 1 hint each, 1 wider mask, both preferred 1/2",
530 hp: []HintProvider{
531 &mockHintProvider{
532 map[string][]TopologyHint{
533 "resource1": {
534 {
535 NUMANodeAffinity: NewTestBitMask(0),
536 Preferred: true,
537 },
538 },
539 },
540 },
541 &mockHintProvider{
542 map[string][]TopologyHint{
543 "resource2": {
544 {
545 NUMANodeAffinity: NewTestBitMask(0, 1),
546 Preferred: true,
547 },
548 },
549 },
550 },
551 },
552 expected: TopologyHint{
553 NUMANodeAffinity: NewTestBitMask(0),
554 Preferred: false,
555 },
556 },
557 {
558 name: "Two providers, 1 with 2 hints, 1 with single non-preferred hint matching",
559 hp: []HintProvider{
560 &mockHintProvider{
561 map[string][]TopologyHint{
562 "resource1": {
563 {
564 NUMANodeAffinity: NewTestBitMask(0),
565 Preferred: true,
566 },
567 {
568 NUMANodeAffinity: NewTestBitMask(1),
569 Preferred: true,
570 },
571 },
572 },
573 },
574 &mockHintProvider{
575 map[string][]TopologyHint{
576 "resource2": {
577 {
578 NUMANodeAffinity: NewTestBitMask(0, 1),
579 Preferred: false,
580 },
581 },
582 },
583 },
584 },
585 expected: TopologyHint{
586 NUMANodeAffinity: NewTestBitMask(0),
587 Preferred: false,
588 },
589 },
590 {
591 name: "Two providers, 1 hint each, 1 wider mask, both preferred 2/2",
592 hp: []HintProvider{
593 &mockHintProvider{
594 map[string][]TopologyHint{
595 "resource1": {
596 {
597 NUMANodeAffinity: NewTestBitMask(1),
598 Preferred: true,
599 },
600 },
601 },
602 },
603 &mockHintProvider{
604 map[string][]TopologyHint{
605 "resource2": {
606 {
607 NUMANodeAffinity: NewTestBitMask(0, 1),
608 Preferred: true,
609 },
610 },
611 },
612 },
613 },
614 expected: TopologyHint{
615 NUMANodeAffinity: NewTestBitMask(1),
616 Preferred: false,
617 },
618 },
619 {
620 name: "bestNonPreferredAffinityCount (1)",
621 hp: []HintProvider{
622 &mockHintProvider{
623 map[string][]TopologyHint{
624 "resource1": {
625 {
626 NUMANodeAffinity: NewTestBitMask(0, 1, 2, 3),
627 Preferred: false,
628 },
629 {
630 NUMANodeAffinity: NewTestBitMask(0, 1),
631 Preferred: false,
632 },
633 },
634 },
635 },
636 &mockHintProvider{
637 map[string][]TopologyHint{
638 "resource2": {
639 {
640 NUMANodeAffinity: NewTestBitMask(0, 1),
641 Preferred: false,
642 },
643 },
644 },
645 },
646 },
647 expected: TopologyHint{
648 NUMANodeAffinity: NewTestBitMask(0, 1),
649 Preferred: false,
650 },
651 },
652 {
653 name: "bestNonPreferredAffinityCount (2)",
654 hp: []HintProvider{
655 &mockHintProvider{
656 map[string][]TopologyHint{
657 "resource1": {
658 {
659 NUMANodeAffinity: NewTestBitMask(0, 1, 2, 3),
660 Preferred: false,
661 },
662 {
663 NUMANodeAffinity: NewTestBitMask(0, 1),
664 Preferred: false,
665 },
666 },
667 },
668 },
669 &mockHintProvider{
670 map[string][]TopologyHint{
671 "resource2": {
672 {
673 NUMANodeAffinity: NewTestBitMask(0, 3),
674 Preferred: false,
675 },
676 },
677 },
678 },
679 },
680 expected: TopologyHint{
681 NUMANodeAffinity: NewTestBitMask(0, 3),
682 Preferred: false,
683 },
684 },
685 {
686 name: "bestNonPreferredAffinityCount (3)",
687 hp: []HintProvider{
688 &mockHintProvider{
689 map[string][]TopologyHint{
690 "resource1": {
691 {
692 NUMANodeAffinity: NewTestBitMask(0, 1, 2, 3),
693 Preferred: false,
694 },
695 {
696 NUMANodeAffinity: NewTestBitMask(0, 1),
697 Preferred: false,
698 },
699 },
700 },
701 },
702 &mockHintProvider{
703 map[string][]TopologyHint{
704 "resource2": {
705 {
706 NUMANodeAffinity: NewTestBitMask(1, 2),
707 Preferred: false,
708 },
709 },
710 },
711 },
712 },
713 expected: TopologyHint{
714 NUMANodeAffinity: NewTestBitMask(1, 2),
715 Preferred: false,
716 },
717 },
718 {
719 name: "bestNonPreferredAffinityCount (4)",
720 hp: []HintProvider{
721 &mockHintProvider{
722 map[string][]TopologyHint{
723 "resource1": {
724 {
725 NUMANodeAffinity: NewTestBitMask(0, 1, 2, 3),
726 Preferred: false,
727 },
728 {
729 NUMANodeAffinity: NewTestBitMask(0, 1),
730 Preferred: false,
731 },
732 },
733 },
734 },
735 &mockHintProvider{
736 map[string][]TopologyHint{
737 "resource2": {
738 {
739 NUMANodeAffinity: NewTestBitMask(2, 3),
740 Preferred: false,
741 },
742 },
743 },
744 },
745 },
746 expected: TopologyHint{
747 NUMANodeAffinity: NewTestBitMask(2, 3),
748 Preferred: false,
749 },
750 },
751 }
752 }
753
754 func (p *bestEffortPolicy) mergeTestCasesNoPolicies(numaNodes []int) []policyMergeTestCase {
755 return []policyMergeTestCase{
756 {
757 name: "bestNonPreferredAffinityCount (5)",
758 hp: []HintProvider{
759 &mockHintProvider{
760 map[string][]TopologyHint{
761 "resource1": {
762 {
763 NUMANodeAffinity: NewTestBitMask(0, 1, 2, 3),
764 Preferred: false,
765 },
766 {
767 NUMANodeAffinity: NewTestBitMask(0, 1),
768 Preferred: false,
769 },
770 },
771 },
772 },
773 &mockHintProvider{
774 map[string][]TopologyHint{
775 "resource2": {
776 {
777 NUMANodeAffinity: NewTestBitMask(1, 2),
778 Preferred: false,
779 },
780 {
781 NUMANodeAffinity: NewTestBitMask(2, 3),
782 Preferred: false,
783 },
784 },
785 },
786 },
787 },
788 expected: TopologyHint{
789 NUMANodeAffinity: NewTestBitMask(1, 2),
790 Preferred: false,
791 },
792 },
793 {
794 name: "bestNonPreferredAffinityCount (6)",
795 hp: []HintProvider{
796 &mockHintProvider{
797 map[string][]TopologyHint{
798 "resource1": {
799 {
800 NUMANodeAffinity: NewTestBitMask(0, 1, 2, 3),
801 Preferred: false,
802 },
803 {
804 NUMANodeAffinity: NewTestBitMask(0, 1),
805 Preferred: false,
806 },
807 },
808 },
809 },
810 &mockHintProvider{
811 map[string][]TopologyHint{
812 "resource2": {
813 {
814 NUMANodeAffinity: NewTestBitMask(1, 2, 3),
815 Preferred: false,
816 },
817 {
818 NUMANodeAffinity: NewTestBitMask(1, 2),
819 Preferred: false,
820 },
821 {
822 NUMANodeAffinity: NewTestBitMask(1, 3),
823 Preferred: false,
824 },
825 {
826 NUMANodeAffinity: NewTestBitMask(2, 3),
827 Preferred: false,
828 },
829 },
830 },
831 },
832 },
833 expected: TopologyHint{
834 NUMANodeAffinity: NewTestBitMask(1, 2),
835 Preferred: false,
836 },
837 },
838 }
839 }
840
841 func (p *bestEffortPolicy) mergeTestCasesClosestNUMA(numaNodes []int) []policyMergeTestCase {
842 return []policyMergeTestCase{
843 {
844 name: "Two providers, 2 hints each, same mask (some with different bits), same preferred",
845 hp: []HintProvider{
846 &mockHintProvider{
847 map[string][]TopologyHint{
848 "resource1": {
849 {
850 NUMANodeAffinity: NewTestBitMask(0, 4),
851 Preferred: true,
852 },
853 {
854 NUMANodeAffinity: NewTestBitMask(0, 2),
855 Preferred: true,
856 },
857 },
858 },
859 },
860 &mockHintProvider{
861 map[string][]TopologyHint{
862 "resource2": {
863 {
864 NUMANodeAffinity: NewTestBitMask(0, 4),
865 Preferred: true,
866 },
867 {
868 NUMANodeAffinity: NewTestBitMask(0, 2),
869 Preferred: true,
870 },
871 },
872 },
873 },
874 },
875 expected: TopologyHint{
876 NUMANodeAffinity: NewTestBitMask(0, 2),
877 Preferred: true,
878 },
879 },
880 {
881 name: "Two providers, 2 hints each, different mask",
882 hp: []HintProvider{
883 &mockHintProvider{
884 map[string][]TopologyHint{
885 "resource1": {
886 {
887 NUMANodeAffinity: NewTestBitMask(4),
888 Preferred: true,
889 },
890 {
891 NUMANodeAffinity: NewTestBitMask(0, 2),
892 Preferred: true,
893 },
894 },
895 },
896 },
897 &mockHintProvider{
898 map[string][]TopologyHint{
899 "resource2": {
900 {
901 NUMANodeAffinity: NewTestBitMask(4),
902 Preferred: true,
903 },
904 {
905 NUMANodeAffinity: NewTestBitMask(0, 2),
906 Preferred: true,
907 },
908 },
909 },
910 },
911 },
912 expected: TopologyHint{
913 NUMANodeAffinity: NewTestBitMask(4),
914 Preferred: true,
915 },
916 },
917 {
918 name: "bestNonPreferredAffinityCount (5)",
919 hp: []HintProvider{
920 &mockHintProvider{
921 map[string][]TopologyHint{
922 "resource1": {
923 {
924 NUMANodeAffinity: NewTestBitMask(0, 1, 2, 3),
925 Preferred: false,
926 },
927 {
928 NUMANodeAffinity: NewTestBitMask(0, 1),
929 Preferred: false,
930 },
931 },
932 },
933 },
934 &mockHintProvider{
935 map[string][]TopologyHint{
936 "resource2": {
937 {
938 NUMANodeAffinity: NewTestBitMask(1, 2),
939 Preferred: false,
940 },
941 {
942 NUMANodeAffinity: NewTestBitMask(2, 3),
943 Preferred: false,
944 },
945 },
946 },
947 },
948 },
949 expected: TopologyHint{
950 NUMANodeAffinity: NewTestBitMask(2, 3),
951 Preferred: false,
952 },
953 },
954 {
955 name: "bestNonPreferredAffinityCount (6)",
956 hp: []HintProvider{
957 &mockHintProvider{
958 map[string][]TopologyHint{
959 "resource1": {
960 {
961 NUMANodeAffinity: NewTestBitMask(0, 1, 2, 3),
962 Preferred: false,
963 },
964 {
965 NUMANodeAffinity: NewTestBitMask(0, 1),
966 Preferred: false,
967 },
968 },
969 },
970 },
971 &mockHintProvider{
972 map[string][]TopologyHint{
973 "resource2": {
974 {
975 NUMANodeAffinity: NewTestBitMask(1, 2, 3),
976 Preferred: false,
977 },
978 {
979 NUMANodeAffinity: NewTestBitMask(1, 2),
980 Preferred: false,
981 },
982 {
983 NUMANodeAffinity: NewTestBitMask(1, 3),
984 Preferred: false,
985 },
986 {
987 NUMANodeAffinity: NewTestBitMask(2, 3),
988 Preferred: false,
989 },
990 },
991 },
992 },
993 },
994 expected: TopologyHint{
995 NUMANodeAffinity: NewTestBitMask(2, 3),
996 Preferred: false,
997 },
998 },
999 }
1000 }
1001
1002 func (p *singleNumaNodePolicy) mergeTestCases(numaNodes []int) []policyMergeTestCase {
1003 return []policyMergeTestCase{
1004 {
1005 name: "TopologyHint not set",
1006 hp: []HintProvider{},
1007 expected: TopologyHint{
1008 NUMANodeAffinity: nil,
1009 Preferred: true,
1010 },
1011 },
1012 {
1013 name: "HintProvider returns empty non-nil map[string][]TopologyHint",
1014 hp: []HintProvider{
1015 &mockHintProvider{
1016 map[string][]TopologyHint{},
1017 },
1018 },
1019 expected: TopologyHint{
1020 NUMANodeAffinity: nil,
1021 Preferred: true,
1022 },
1023 },
1024 {
1025 name: "HintProvider returns -nil map[string][]TopologyHint from provider",
1026 hp: []HintProvider{
1027 &mockHintProvider{
1028 map[string][]TopologyHint{
1029 "resource": nil,
1030 },
1031 },
1032 },
1033 expected: TopologyHint{
1034 NUMANodeAffinity: nil,
1035 Preferred: true,
1036 },
1037 },
1038 {
1039 name: "HintProvider returns empty non-nil map[string][]TopologyHint from provider", hp: []HintProvider{
1040 &mockHintProvider{
1041 map[string][]TopologyHint{
1042 "resource": {},
1043 },
1044 },
1045 },
1046 expected: TopologyHint{
1047 NUMANodeAffinity: nil,
1048 Preferred: false,
1049 },
1050 },
1051 {
1052 name: "Single TopologyHint with Preferred as true and NUMANodeAffinity as nil",
1053 hp: []HintProvider{
1054 &mockHintProvider{
1055 map[string][]TopologyHint{
1056 "resource": {
1057 {
1058 NUMANodeAffinity: nil,
1059 Preferred: true,
1060 },
1061 },
1062 },
1063 },
1064 },
1065 expected: TopologyHint{
1066 NUMANodeAffinity: nil,
1067 Preferred: true,
1068 },
1069 },
1070 {
1071 name: "Single TopologyHint with Preferred as false and NUMANodeAffinity as nil",
1072 hp: []HintProvider{
1073 &mockHintProvider{
1074 map[string][]TopologyHint{
1075 "resource": {
1076 {
1077 NUMANodeAffinity: nil,
1078 Preferred: false,
1079 },
1080 },
1081 },
1082 },
1083 },
1084 expected: TopologyHint{
1085 NUMANodeAffinity: nil,
1086 Preferred: false,
1087 },
1088 },
1089 {
1090 name: "Two providers, 1 hint each, no common mask",
1091 hp: []HintProvider{
1092 &mockHintProvider{
1093 map[string][]TopologyHint{
1094 "resource1": {
1095 {
1096 NUMANodeAffinity: NewTestBitMask(0),
1097 Preferred: true,
1098 },
1099 },
1100 },
1101 },
1102 &mockHintProvider{
1103 map[string][]TopologyHint{
1104 "resource2": {
1105 {
1106 NUMANodeAffinity: NewTestBitMask(1),
1107 Preferred: true,
1108 },
1109 },
1110 },
1111 },
1112 },
1113 expected: TopologyHint{
1114 NUMANodeAffinity: nil,
1115 Preferred: false,
1116 },
1117 },
1118 {
1119 name: "Two providers, 1 hint each, same mask, 1 preferred, 1 not 1/2",
1120 hp: []HintProvider{
1121 &mockHintProvider{
1122 map[string][]TopologyHint{
1123 "resource1": {
1124 {
1125 NUMANodeAffinity: NewTestBitMask(0),
1126 Preferred: true,
1127 },
1128 },
1129 },
1130 },
1131 &mockHintProvider{
1132 map[string][]TopologyHint{
1133 "resource2": {
1134 {
1135 NUMANodeAffinity: NewTestBitMask(0),
1136 Preferred: false,
1137 },
1138 },
1139 },
1140 },
1141 },
1142 expected: TopologyHint{
1143 NUMANodeAffinity: nil,
1144 Preferred: false,
1145 },
1146 },
1147 {
1148 name: "Two providers, 1 hint each, same mask, 1 preferred, 1 not 2/2",
1149 hp: []HintProvider{
1150 &mockHintProvider{
1151 map[string][]TopologyHint{
1152 "resource1": {
1153 {
1154 NUMANodeAffinity: NewTestBitMask(1),
1155 Preferred: true,
1156 },
1157 },
1158 },
1159 },
1160 &mockHintProvider{
1161 map[string][]TopologyHint{
1162 "resource2": {
1163 {
1164 NUMANodeAffinity: NewTestBitMask(1),
1165 Preferred: false,
1166 },
1167 },
1168 },
1169 },
1170 },
1171 expected: TopologyHint{
1172 NUMANodeAffinity: nil,
1173 Preferred: false,
1174 },
1175 },
1176 {
1177 name: "Two providers, 1 with 2 hints, 1 with single non-preferred hint matching",
1178 hp: []HintProvider{
1179 &mockHintProvider{
1180 map[string][]TopologyHint{
1181 "resource1": {
1182 {
1183 NUMANodeAffinity: NewTestBitMask(0),
1184 Preferred: true,
1185 },
1186 {
1187 NUMANodeAffinity: NewTestBitMask(1),
1188 Preferred: true,
1189 },
1190 },
1191 },
1192 },
1193 &mockHintProvider{
1194 map[string][]TopologyHint{
1195 "resource2": {
1196 {
1197 NUMANodeAffinity: NewTestBitMask(0, 1),
1198 Preferred: false,
1199 },
1200 },
1201 },
1202 },
1203 },
1204 expected: TopologyHint{
1205 NUMANodeAffinity: nil,
1206 Preferred: false,
1207 },
1208 },
1209 {
1210 name: "Single NUMA hint generation",
1211 hp: []HintProvider{
1212 &mockHintProvider{
1213 map[string][]TopologyHint{
1214 "resource1": {
1215 {
1216 NUMANodeAffinity: NewTestBitMask(0, 1),
1217 Preferred: true,
1218 },
1219 },
1220 "resource2": {
1221 {
1222 NUMANodeAffinity: NewTestBitMask(0),
1223 Preferred: true,
1224 },
1225 {
1226 NUMANodeAffinity: NewTestBitMask(1),
1227 Preferred: true,
1228 },
1229 {
1230 NUMANodeAffinity: NewTestBitMask(0, 1),
1231 Preferred: false,
1232 },
1233 },
1234 },
1235 },
1236 },
1237 expected: TopologyHint{
1238 NUMANodeAffinity: nil,
1239 Preferred: false,
1240 },
1241 },
1242 {
1243 name: "One no-preference provider",
1244 hp: []HintProvider{
1245 &mockHintProvider{
1246 map[string][]TopologyHint{
1247 "resource1": {
1248 {
1249 NUMANodeAffinity: NewTestBitMask(0),
1250 Preferred: true,
1251 },
1252 {
1253 NUMANodeAffinity: NewTestBitMask(1),
1254 Preferred: true,
1255 },
1256 {
1257 NUMANodeAffinity: NewTestBitMask(0, 1),
1258 Preferred: false,
1259 },
1260 },
1261 },
1262 },
1263 &mockHintProvider{
1264 nil,
1265 },
1266 },
1267 expected: TopologyHint{
1268 NUMANodeAffinity: NewTestBitMask(0),
1269 Preferred: true,
1270 },
1271 },
1272 }
1273 }
1274
1275 func testPolicyMerge(policy Policy, tcases []policyMergeTestCase, t *testing.T) {
1276 for _, tc := range tcases {
1277 var providersHints []map[string][]TopologyHint
1278 for _, provider := range tc.hp {
1279 hints := provider.GetTopologyHints(&v1.Pod{}, &v1.Container{})
1280 providersHints = append(providersHints, hints)
1281 }
1282
1283 actual, _ := policy.Merge(providersHints)
1284 if !reflect.DeepEqual(actual, tc.expected) {
1285 t.Errorf("%v: Expected Topology Hint to be %v, got %v:", tc.name, tc.expected, actual)
1286 }
1287 }
1288 }
1289
1290 func TestMaxOfMinAffinityCounts(t *testing.T) {
1291 tcases := []struct {
1292 hints [][]TopologyHint
1293 expected int
1294 }{
1295 {
1296 [][]TopologyHint{},
1297 0,
1298 },
1299 {
1300 [][]TopologyHint{
1301 {
1302 TopologyHint{NewTestBitMask(), true},
1303 },
1304 },
1305 0,
1306 },
1307 {
1308 [][]TopologyHint{
1309 {
1310 TopologyHint{NewTestBitMask(0), true},
1311 },
1312 },
1313 1,
1314 },
1315 {
1316 [][]TopologyHint{
1317 {
1318 TopologyHint{NewTestBitMask(0, 1), true},
1319 },
1320 },
1321 2,
1322 },
1323 {
1324 [][]TopologyHint{
1325 {
1326 TopologyHint{NewTestBitMask(0, 1), true},
1327 TopologyHint{NewTestBitMask(0, 1, 2), true},
1328 },
1329 },
1330 2,
1331 },
1332 {
1333 [][]TopologyHint{
1334 {
1335 TopologyHint{NewTestBitMask(0, 1), true},
1336 TopologyHint{NewTestBitMask(0, 1, 2), true},
1337 },
1338 {
1339 TopologyHint{NewTestBitMask(0, 1, 2), true},
1340 },
1341 },
1342 3,
1343 },
1344 {
1345 [][]TopologyHint{
1346 {
1347 TopologyHint{NewTestBitMask(0, 1), true},
1348 TopologyHint{NewTestBitMask(0, 1, 2), true},
1349 },
1350 {
1351 TopologyHint{NewTestBitMask(0, 1, 2), true},
1352 TopologyHint{NewTestBitMask(0, 1, 2, 3), true},
1353 },
1354 },
1355 3,
1356 },
1357 }
1358
1359 for _, tc := range tcases {
1360 t.Run("", func(t *testing.T) {
1361 result := maxOfMinAffinityCounts(tc.hints)
1362 if result != tc.expected {
1363 t.Errorf("Expected result to be %v, got %v", tc.expected, result)
1364 }
1365 })
1366 }
1367 }
1368
1369 func TestCompareHintsNarrowest(t *testing.T) {
1370 tcases := []struct {
1371 description string
1372 bestNonPreferredAffinityCount int
1373 current *TopologyHint
1374 candidate *TopologyHint
1375 expected string
1376 }{
1377 {
1378 "candidate.NUMANodeAffinity.Count() == 0 (1)",
1379 -1,
1380 nil,
1381 &TopologyHint{bitmask.NewEmptyBitMask(), false},
1382 "current",
1383 },
1384 {
1385 "candidate.NUMANodeAffinity.Count() == 0 (2)",
1386 -1,
1387 &TopologyHint{NewTestBitMask(), true},
1388 &TopologyHint{NewTestBitMask(), false},
1389 "current",
1390 },
1391 {
1392 "current == nil (1)",
1393 -1,
1394 nil,
1395 &TopologyHint{NewTestBitMask(0), true},
1396 "candidate",
1397 },
1398 {
1399 "current == nil (2)",
1400 -1,
1401 nil,
1402 &TopologyHint{NewTestBitMask(0), false},
1403 "candidate",
1404 },
1405 {
1406 "!current.Preferred && candidate.Preferred",
1407 -1,
1408 &TopologyHint{NewTestBitMask(0), false},
1409 &TopologyHint{NewTestBitMask(0), true},
1410 "candidate",
1411 },
1412 {
1413 "current.Preferred && !candidate.Preferred",
1414 -1,
1415 &TopologyHint{NewTestBitMask(0), true},
1416 &TopologyHint{NewTestBitMask(0), false},
1417 "current",
1418 },
1419 {
1420 "current.Preferred && candidate.Preferred (1)",
1421 -1,
1422 &TopologyHint{NewTestBitMask(0), true},
1423 &TopologyHint{NewTestBitMask(0), true},
1424 "current",
1425 },
1426 {
1427 "current.Preferred && candidate.Preferred (2)",
1428 -1,
1429 &TopologyHint{NewTestBitMask(0, 1), true},
1430 &TopologyHint{NewTestBitMask(0), true},
1431 "candidate",
1432 },
1433 {
1434 "current.Preferred && candidate.Preferred (3)",
1435 -1,
1436 &TopologyHint{NewTestBitMask(0), true},
1437 &TopologyHint{NewTestBitMask(0, 1), true},
1438 "current",
1439 },
1440 {
1441 "!current.Preferred && !candidate.Preferred (1.1)",
1442 1,
1443 &TopologyHint{NewTestBitMask(0, 1), false},
1444 &TopologyHint{NewTestBitMask(0, 1), false},
1445 "current",
1446 },
1447 {
1448 "!current.Preferred && !candidate.Preferred (1.2)",
1449 1,
1450 &TopologyHint{NewTestBitMask(1, 2), false},
1451 &TopologyHint{NewTestBitMask(0, 1), false},
1452 "candidate",
1453 },
1454 {
1455 "!current.Preferred && !candidate.Preferred (1.3)",
1456 1,
1457 &TopologyHint{NewTestBitMask(0, 1), false},
1458 &TopologyHint{NewTestBitMask(1, 2), false},
1459 "current",
1460 },
1461 {
1462 "!current.Preferred && !candidate.Preferred (2.1)",
1463 2,
1464 &TopologyHint{NewTestBitMask(0, 1), false},
1465 &TopologyHint{NewTestBitMask(0), false},
1466 "current",
1467 },
1468 {
1469 "!current.Preferred && !candidate.Preferred (2.2)",
1470 2,
1471 &TopologyHint{NewTestBitMask(0, 1), false},
1472 &TopologyHint{NewTestBitMask(0, 1), false},
1473 "current",
1474 },
1475 {
1476 "!current.Preferred && !candidate.Preferred (2.3)",
1477 2,
1478 &TopologyHint{NewTestBitMask(1, 2), false},
1479 &TopologyHint{NewTestBitMask(0, 1), false},
1480 "candidate",
1481 },
1482 {
1483 "!current.Preferred && !candidate.Preferred (2.4)",
1484 2,
1485 &TopologyHint{NewTestBitMask(0, 1), false},
1486 &TopologyHint{NewTestBitMask(1, 2), false},
1487 "current",
1488 },
1489 {
1490 "!current.Preferred && !candidate.Preferred (3a)",
1491 2,
1492 &TopologyHint{NewTestBitMask(0), false},
1493 &TopologyHint{NewTestBitMask(0, 1, 2), false},
1494 "current",
1495 },
1496 {
1497 "!current.Preferred && !candidate.Preferred (3b)",
1498 2,
1499 &TopologyHint{NewTestBitMask(0), false},
1500 &TopologyHint{NewTestBitMask(0, 1), false},
1501 "candidate",
1502 },
1503 {
1504 "!current.Preferred && !candidate.Preferred (3ca.1)",
1505 3,
1506 &TopologyHint{NewTestBitMask(0), false},
1507 &TopologyHint{NewTestBitMask(0, 1), false},
1508 "candidate",
1509 },
1510 {
1511 "!current.Preferred && !candidate.Preferred (3ca.2)",
1512 3,
1513 &TopologyHint{NewTestBitMask(0), false},
1514 &TopologyHint{NewTestBitMask(1, 2), false},
1515 "candidate",
1516 },
1517 {
1518 "!current.Preferred && !candidate.Preferred (3ca.3)",
1519 4,
1520 &TopologyHint{NewTestBitMask(0, 1), false},
1521 &TopologyHint{NewTestBitMask(1, 2, 3), false},
1522 "candidate",
1523 },
1524 {
1525 "!current.Preferred && !candidate.Preferred (3cb)",
1526 4,
1527 &TopologyHint{NewTestBitMask(1, 2, 3), false},
1528 &TopologyHint{NewTestBitMask(0, 1), false},
1529 "current",
1530 },
1531 {
1532 "!current.Preferred && !candidate.Preferred (3cc.1)",
1533 4,
1534 &TopologyHint{NewTestBitMask(0, 1, 2), false},
1535 &TopologyHint{NewTestBitMask(0, 1, 2), false},
1536 "current",
1537 },
1538 {
1539 "!current.Preferred && !candidate.Preferred (3cc.2)",
1540 4,
1541 &TopologyHint{NewTestBitMask(0, 1, 2), false},
1542 &TopologyHint{NewTestBitMask(1, 2, 3), false},
1543 "current",
1544 },
1545 {
1546 "!current.Preferred && !candidate.Preferred (3cc.3)",
1547 4,
1548 &TopologyHint{NewTestBitMask(1, 2, 3), false},
1549 &TopologyHint{NewTestBitMask(0, 1, 2), false},
1550 "candidate",
1551 },
1552 }
1553
1554 for _, tc := range tcases {
1555 t.Run(tc.description, func(t *testing.T) {
1556 numaInfo := &NUMAInfo{}
1557 merger := NewHintMerger(numaInfo, [][]TopologyHint{}, PolicyBestEffort, PolicyOptions{})
1558 merger.BestNonPreferredAffinityCount = tc.bestNonPreferredAffinityCount
1559
1560 result := merger.compare(tc.current, tc.candidate)
1561 if result != tc.current && result != tc.candidate {
1562 t.Errorf("Expected result to be either 'current' or 'candidate' hint")
1563 }
1564 if tc.expected == "current" && result != tc.current {
1565 t.Errorf("Expected result to be %v, got %v", tc.current, result)
1566 }
1567 if tc.expected == "candidate" && result != tc.candidate {
1568 t.Errorf("Expected result to be %v, got %v", tc.candidate, result)
1569 }
1570 })
1571 }
1572 }
1573
1574 func commonNUMAInfoTwoNodes() *NUMAInfo {
1575 return &NUMAInfo{
1576 Nodes: []int{0, 1},
1577 NUMADistances: NUMADistances{
1578 0: {10, 11},
1579 1: {11, 10},
1580 },
1581 }
1582 }
1583
1584 func commonNUMAInfoFourNodes() *NUMAInfo {
1585 return &NUMAInfo{
1586 Nodes: []int{0, 1, 2, 3},
1587 NUMADistances: NUMADistances{
1588 0: {10, 11, 12, 12},
1589 1: {11, 10, 12, 12},
1590 2: {12, 12, 10, 11},
1591 3: {12, 12, 11, 10},
1592 },
1593 }
1594 }
1595
1596 func commonNUMAInfoEightNodes() *NUMAInfo {
1597 return &NUMAInfo{
1598 Nodes: []int{0, 1, 2, 3, 4, 5, 6, 7},
1599 NUMADistances: NUMADistances{
1600 0: {10, 11, 12, 12, 30, 30, 30, 30},
1601 1: {11, 10, 12, 12, 30, 30, 30, 30},
1602 2: {12, 12, 10, 11, 30, 30, 30, 30},
1603 3: {12, 12, 11, 10, 30, 30, 30, 30},
1604 4: {30, 30, 30, 30, 10, 11, 12, 12},
1605 5: {30, 30, 30, 30, 11, 10, 12, 12},
1606 6: {30, 30, 30, 30, 12, 12, 10, 11},
1607 7: {30, 30, 30, 30, 12, 12, 13, 10},
1608 },
1609 }
1610 }
1611
View as plain text