Change:
Setup: 3 Master nodes and 2 Worker Nodes. Version: v1.22.0-rc.0+ Memory Manager on Kubernetes Version (v1.22.0-rc.0+) and Nodes configured with Hugepages of size 2M on 2 Worker nodes. Worker node having 2 Numa Nodes (numa node0 and numa node1) of Hugepages of size 2M are 10 on each Numa node sh-4.4# cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nrhugepages 10 sh-4.4# cat /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nrhugepages 10 After configuring Memory , where Hugepages are 20M (2M * 10) on each Numa node. we create QoS pod1 pod which consumes 24Mi Hugepages (of size 2M) Pod Spec: List pods Memory Manager state file: Now create a QoS Guaranteed Pod2 requesting 16Mi . On the same worker node. Pod spec: List pods: Memory Manager state file after pod2 is deployed. Pod2 should be rejected. Steps provided above Kubernetes version (use ): v1.22.0-rc.0+ Cloud provider or hardware configuration: Openshift OS (e.g: ):Red Hat Enterprise Linux CoreOS release 4.9 Kernel (e.g. ): Linux 4.18.0-305.12.1.rt7.84.el84.x8664 SMP PREEMPTRT Thu Jul 29 14:18:12 EDT 2021 x8664 x8664 x8664 GNU/Linux Kubelet configuration
/triage accepted /priority important-longterm /sig node /area kubelet
/assign

Discussion:
maskBits := mask.GetBits() singleNUMAHint := len(maskBits) == 1 <del> // the node already in group with another node, it can not be used for the single NUMA node allocation if singleNUMAHint && len(machineState[maskBits[0]].Cells) > 1 { return } </del> totalFreeSize := map[v1.ResourceName]uint64{} totalAllocatableSize := map[v1.ResourceName]uint64{} <del> // calculate total free memory for the node mask </del> <ins> // calculate total free and allocatable memory for the node mask </ins> for _, nodeID := range maskBits { <del> // the node already used for the memory allocation if !singleNUMAHint && machineState[nodeID].NumberOfAssignments > 0 { // the node used for the single NUMA memory allocation, it can not be used for the multi NUMA node allocation if len(machineState[nodeID].Cells) == 1 { return } // the node already used with different group of nodes, it can not be use with in the current hint if !areGroupsEqual(machineState[nodeID].Cells, maskBits) { return } } </del> for resourceName := range requestedResources { if _, ok := totalFreeSize[resourceName]; !ok { totalFreeSize[resourceName] = 0

minAffinitySize = mask.Count() } <ins> // the node already in group with another node, it can not be used for the single NUMA node allocation if singleNUMAHint && len(machineState[maskBits[0]].Cells) > 1 { return } for _, nodeID := range maskBits { // the node already used for the memory allocation if !singleNUMAHint && machineState[nodeID].NumberOfAssignments > 0 { // the node used for the single NUMA memory allocation, it can not be used for the multi NUMA node allocation if len(machineState[nodeID].Cells) == 1 { return } // the node already used with different group of nodes, it can not be use with in the current hint if !areGroupsEqual(machineState[nodeID].Cells, maskBits) { return } } } </ins> // verify that for all memory types the node mask has enough free resources for resourceName, requestedSize := range requestedResources { podReusableMemory := p.getPodReusableMemory(pod, mask, resourceName)

}, expectedTopologyHints: nil, }, <ins> { description: "should not return preferred hints with multiple NUMA nodes for the pod with resources satisfied by a single NUMA node", assignments: state.ContainerMemoryAssignments{ "pod1": map[string][]state.Block{ "container1": { { NUMAAffinity: []int{0, 1}, Type:         v1.ResourceMemory, Size:         2 * gb, }, { NUMAAffinity: []int{0, 1}, Type:         hugepages2M, Size:         24 * mb, }, }, }, }, machineState: state.NUMANodeMap{ 0: &state.NUMANodeState{ MemoryMap: map[v1.ResourceName]*state.MemoryTable{ v1.ResourceMemory: { Allocatable:    1536 * mb, Free:           0, Reserved:       1536 * mb, SystemReserved: 512 * mb, TotalMemSize:   2 * gb, }, hugepages2M: { Allocatable:    20 * mb, Free:           0, Reserved:       20 * mb, SystemReserved: 0, TotalMemSize:   20 * mb, }, }, Cells:               []int{0, 1}, NumberOfAssignments: 2, }, 1: &state.NUMANodeState{ MemoryMap: map[v1.ResourceName]*state.MemoryTable{ v1.ResourceMemory: { Allocatable:    1536 * mb, Free:           gb, Reserved:       512 * mb, SystemReserved: 512 * mb, TotalMemSize:   2 * gb, }, hugepages2M: { Allocatable:    20 * mb, Free:           16 * mb, Reserved:       4 * mb, SystemReserved: 0, TotalMemSize:   20 * mb, }, }, Cells:               []int{0, 1}, NumberOfAssignments: 2, }, }, pod: getPod("pod2", "container2", &v1.ResourceRequirements{ Limits: v1.ResourceList{ v1.ResourceCPU:    resource.MustParse("1000Mi"), v1.ResourceMemory: resource.MustParse("1Gi"), hugepages2M:       resource.MustParse("16Mi"), }, Requests: v1.ResourceList{ v1.ResourceCPU:    resource.MustParse("1000Mi"), v1.ResourceMemory: resource.MustParse("1Gi"), hugepages2M:       resource.MustParse("16Mi"), }, }, ), systemReserved: systemReservedMemory{ 0: map[v1.ResourceName]uint64{ v1.ResourceMemory: 512 * mb, }, 1: map[v1.ResourceName]uint64{ v1.ResourceMemory: 512 * mb, }, }, expectedTopologyHints: map[string][]topologymanager.TopologyHint{ string(v1.ResourceMemory): { { NUMANodeAffinity: newNUMAAffinity(0, 1), Preferred:        false, }, }, hugepages2M: { { NUMANodeAffinity: newNUMAAffinity(0, 1), Preferred:        false, }, }, }, }, </ins> } for _, testCase := range testCases {