mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
memory manager: provide an additional validation for reserved memory
Calculate the total amount of reserved memory only for NUMA nodes that are existing under the machine. Signed-off-by: Artyom Lukianov <alukiano@redhat.com>
This commit is contained in:
parent
27c5efe8ec
commit
aa63e5aed2
@ -267,6 +267,7 @@ func (m *manager) GetTopologyHints(pod *v1.Pod, container *v1.Container) map[str
|
|||||||
return m.policy.GetTopologyHints(m.state, pod, container)
|
return m.policy.GetTopologyHints(m.state, pod, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move the method to the upper level, to re-use it under the CPU and memory managers
|
||||||
func (m *manager) removeStaleState() {
|
func (m *manager) removeStaleState() {
|
||||||
// Only once all sources are ready do we attempt to remove any stale state.
|
// Only once all sources are ready do we attempt to remove any stale state.
|
||||||
// This ensures that the call to `m.activePods()` below will succeed with
|
// This ensures that the call to `m.activePods()` below will succeed with
|
||||||
@ -319,10 +320,20 @@ func (m *manager) policyRemoveContainerByRef(podUID string, containerName string
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTotalMemoryTypeReserved(preReservedMemory map[int]map[v1.ResourceName]resource.Quantity) map[v1.ResourceName]resource.Quantity {
|
func getTotalMemoryTypeReserved(machineInfo *cadvisorapi.MachineInfo, reservedMemory map[int]map[v1.ResourceName]resource.Quantity) map[v1.ResourceName]resource.Quantity {
|
||||||
totalMemoryType := map[v1.ResourceName]resource.Quantity{}
|
totalMemoryType := map[v1.ResourceName]resource.Quantity{}
|
||||||
|
|
||||||
for _, node := range preReservedMemory {
|
numaNodes := map[int]bool{}
|
||||||
|
for _, numaNode := range machineInfo.Topology {
|
||||||
|
numaNodes[numaNode.Id] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for nodeID, node := range reservedMemory {
|
||||||
|
if !numaNodes[nodeID] {
|
||||||
|
klog.Warningf("The NUMA node %d specified under --reserved- memory does not exist on the machine", nodeID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for memType, memVal := range node {
|
for memType, memVal := range node {
|
||||||
if totalMem, exists := totalMemoryType[memType]; exists {
|
if totalMem, exists := totalMemoryType[memType]; exists {
|
||||||
memVal.Add(totalMem)
|
memVal.Add(totalMem)
|
||||||
@ -334,8 +345,8 @@ func getTotalMemoryTypeReserved(preReservedMemory map[int]map[v1.ResourceName]re
|
|||||||
return totalMemoryType
|
return totalMemoryType
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateReservedMemory(nodeAllocatableReservation v1.ResourceList, reservedMemory map[int]map[v1.ResourceName]resource.Quantity) error {
|
func validateReservedMemory(machineInfo *cadvisorapi.MachineInfo, nodeAllocatableReservation v1.ResourceList, reservedMemory map[int]map[v1.ResourceName]resource.Quantity) error {
|
||||||
totalMemoryType := getTotalMemoryTypeReserved(reservedMemory)
|
totalMemoryType := getTotalMemoryTypeReserved(machineInfo, reservedMemory)
|
||||||
|
|
||||||
commonMemoryTypeSet := make(map[v1.ResourceName]bool)
|
commonMemoryTypeSet := make(map[v1.ResourceName]bool)
|
||||||
for resourceType := range totalMemoryType {
|
for resourceType := range totalMemoryType {
|
||||||
@ -391,7 +402,7 @@ func convertReserved(machineInfo *cadvisorapi.MachineInfo, reservedMemory map[in
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getSystemReservedMemory(machineInfo *cadvisorapi.MachineInfo, nodeAllocatableReservation v1.ResourceList, preReservedMemory map[int]map[v1.ResourceName]resource.Quantity) (systemReservedMemory, error) {
|
func getSystemReservedMemory(machineInfo *cadvisorapi.MachineInfo, nodeAllocatableReservation v1.ResourceList, preReservedMemory map[int]map[v1.ResourceName]resource.Quantity) (systemReservedMemory, error) {
|
||||||
if err := validateReservedMemory(nodeAllocatableReservation, preReservedMemory); err != nil {
|
if err := validateReservedMemory(machineInfo, nodeAllocatableReservation, preReservedMemory); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,54 +146,77 @@ func getPod(podUID string, containerName string, requirements *v1.ResourceRequir
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateReservedMemory(t *testing.T) {
|
func TestValidateReservedMemory(t *testing.T) {
|
||||||
|
machineInfo := &cadvisorapi.MachineInfo{
|
||||||
|
Topology: []cadvisorapi.Node{
|
||||||
|
{Id: 0},
|
||||||
|
{Id: 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
const msgNotEqual = "the total amount of memory of type \"%s\" is not equal to the value determined by Node Allocatable feature"
|
const msgNotEqual = "the total amount of memory of type \"%s\" is not equal to the value determined by Node Allocatable feature"
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
nodeAllocatableReservation v1.ResourceList
|
nodeAllocatableReservation v1.ResourceList
|
||||||
|
machineInfo *cadvisorapi.MachineInfo
|
||||||
systemReservedMemory map[int]map[v1.ResourceName]resource.Quantity
|
systemReservedMemory map[int]map[v1.ResourceName]resource.Quantity
|
||||||
expectedError string
|
expectedError string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"Node Allocatable not set, pre-reserved not set",
|
"Node Allocatable not set, reserved not set",
|
||||||
v1.ResourceList{},
|
v1.ResourceList{},
|
||||||
|
machineInfo,
|
||||||
map[int]map[v1.ResourceName]resource.Quantity{},
|
map[int]map[v1.ResourceName]resource.Quantity{},
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Node Allocatable set to zero, pre-reserved set to zero",
|
"Node Allocatable set to zero, reserved set to zero",
|
||||||
v1.ResourceList{v1.ResourceMemory: *resource.NewQuantity(0, resource.DecimalSI)},
|
v1.ResourceList{v1.ResourceMemory: *resource.NewQuantity(0, resource.DecimalSI)},
|
||||||
|
machineInfo,
|
||||||
map[int]map[v1.ResourceName]resource.Quantity{
|
map[int]map[v1.ResourceName]resource.Quantity{
|
||||||
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(0, resource.DecimalSI)},
|
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(0, resource.DecimalSI)},
|
||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Node Allocatable not set (equal zero), pre-reserved set",
|
"Node Allocatable not set (equal zero), reserved set",
|
||||||
v1.ResourceList{},
|
v1.ResourceList{},
|
||||||
|
machineInfo,
|
||||||
map[int]map[v1.ResourceName]resource.Quantity{
|
map[int]map[v1.ResourceName]resource.Quantity{
|
||||||
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI)},
|
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI)},
|
||||||
},
|
},
|
||||||
fmt.Sprintf(msgNotEqual, v1.ResourceMemory),
|
fmt.Sprintf(msgNotEqual, v1.ResourceMemory),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Node Allocatable set, pre-reserved not set",
|
"Node Allocatable set, reserved not set",
|
||||||
v1.ResourceList{hugepages2M: *resource.NewQuantity(5, resource.DecimalSI)},
|
v1.ResourceList{hugepages2M: *resource.NewQuantity(5, resource.DecimalSI)},
|
||||||
|
machineInfo,
|
||||||
map[int]map[v1.ResourceName]resource.Quantity{},
|
map[int]map[v1.ResourceName]resource.Quantity{},
|
||||||
fmt.Sprintf(msgNotEqual, hugepages2M),
|
fmt.Sprintf(msgNotEqual, hugepages2M),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Pre-reserved not equal to Node Allocatable",
|
"Reserved not equal to Node Allocatable",
|
||||||
v1.ResourceList{v1.ResourceMemory: *resource.NewQuantity(5, resource.DecimalSI)},
|
v1.ResourceList{v1.ResourceMemory: *resource.NewQuantity(5, resource.DecimalSI)},
|
||||||
|
machineInfo,
|
||||||
map[int]map[v1.ResourceName]resource.Quantity{
|
map[int]map[v1.ResourceName]resource.Quantity{
|
||||||
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI)},
|
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI)},
|
||||||
},
|
},
|
||||||
fmt.Sprintf(msgNotEqual, v1.ResourceMemory),
|
fmt.Sprintf(msgNotEqual, v1.ResourceMemory),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Pre-reserved total equal to Node Allocatable",
|
"Reserved contains the NUMA node that does not exist under the machine",
|
||||||
|
v1.ResourceList{v1.ResourceMemory: *resource.NewQuantity(17, resource.DecimalSI)},
|
||||||
|
machineInfo,
|
||||||
|
map[int]map[v1.ResourceName]resource.Quantity{
|
||||||
|
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI)},
|
||||||
|
2: nodeResources{v1.ResourceMemory: *resource.NewQuantity(5, resource.DecimalSI)},
|
||||||
|
},
|
||||||
|
fmt.Sprintf(msgNotEqual, v1.ResourceMemory),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Reserved total equal to Node Allocatable",
|
||||||
v1.ResourceList{v1.ResourceMemory: *resource.NewQuantity(17, resource.DecimalSI),
|
v1.ResourceList{v1.ResourceMemory: *resource.NewQuantity(17, resource.DecimalSI),
|
||||||
hugepages2M: *resource.NewQuantity(77, resource.DecimalSI),
|
hugepages2M: *resource.NewQuantity(77, resource.DecimalSI),
|
||||||
hugepages1G: *resource.NewQuantity(13, resource.DecimalSI)},
|
hugepages1G: *resource.NewQuantity(13, resource.DecimalSI)},
|
||||||
|
machineInfo,
|
||||||
map[int]map[v1.ResourceName]resource.Quantity{
|
map[int]map[v1.ResourceName]resource.Quantity{
|
||||||
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI),
|
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI),
|
||||||
hugepages2M: *resource.NewQuantity(70, resource.DecimalSI),
|
hugepages2M: *resource.NewQuantity(70, resource.DecimalSI),
|
||||||
@ -204,10 +227,11 @@ func TestValidateReservedMemory(t *testing.T) {
|
|||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Pre-reserved total hugapages-2M not equal to Node Allocatable",
|
"Reserved total hugapages-2M not equal to Node Allocatable",
|
||||||
v1.ResourceList{v1.ResourceMemory: *resource.NewQuantity(17, resource.DecimalSI),
|
v1.ResourceList{v1.ResourceMemory: *resource.NewQuantity(17, resource.DecimalSI),
|
||||||
hugepages2M: *resource.NewQuantity(14, resource.DecimalSI),
|
hugepages2M: *resource.NewQuantity(14, resource.DecimalSI),
|
||||||
hugepages1G: *resource.NewQuantity(13, resource.DecimalSI)},
|
hugepages1G: *resource.NewQuantity(13, resource.DecimalSI)},
|
||||||
|
machineInfo,
|
||||||
map[int]map[v1.ResourceName]resource.Quantity{
|
map[int]map[v1.ResourceName]resource.Quantity{
|
||||||
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI),
|
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI),
|
||||||
hugepages2M: *resource.NewQuantity(70, resource.DecimalSI),
|
hugepages2M: *resource.NewQuantity(70, resource.DecimalSI),
|
||||||
@ -215,13 +239,14 @@ func TestValidateReservedMemory(t *testing.T) {
|
|||||||
1: nodeResources{v1.ResourceMemory: *resource.NewQuantity(5, resource.DecimalSI),
|
1: nodeResources{v1.ResourceMemory: *resource.NewQuantity(5, resource.DecimalSI),
|
||||||
hugepages2M: *resource.NewQuantity(7, resource.DecimalSI)},
|
hugepages2M: *resource.NewQuantity(7, resource.DecimalSI)},
|
||||||
},
|
},
|
||||||
|
|
||||||
fmt.Sprintf(msgNotEqual, hugepages2M),
|
fmt.Sprintf(msgNotEqual, hugepages2M),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
err := validateReservedMemory(tc.nodeAllocatableReservation, tc.systemReservedMemory)
|
err := validateReservedMemory(tc.machineInfo, tc.nodeAllocatableReservation, tc.systemReservedMemory)
|
||||||
if strings.TrimSpace(tc.expectedError) != "" {
|
if strings.TrimSpace(tc.expectedError) != "" {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, err.Error(), tc.expectedError)
|
assert.Equal(t, err.Error(), tc.expectedError)
|
||||||
@ -254,7 +279,7 @@ func TestConvertPreReserved(t *testing.T) {
|
|||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Single NUMA node is pre-reserved",
|
"Single NUMA node is reserved",
|
||||||
map[int]map[v1.ResourceName]resource.Quantity{
|
map[int]map[v1.ResourceName]resource.Quantity{
|
||||||
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI),
|
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI),
|
||||||
hugepages2M: *resource.NewQuantity(70, resource.DecimalSI),
|
hugepages2M: *resource.NewQuantity(70, resource.DecimalSI),
|
||||||
@ -271,7 +296,7 @@ func TestConvertPreReserved(t *testing.T) {
|
|||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Both NUMA nodes are pre-reserved",
|
"Both NUMA nodes are reserved",
|
||||||
map[int]map[v1.ResourceName]resource.Quantity{
|
map[int]map[v1.ResourceName]resource.Quantity{
|
||||||
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI),
|
0: nodeResources{v1.ResourceMemory: *resource.NewQuantity(12, resource.DecimalSI),
|
||||||
hugepages2M: *resource.NewQuantity(70, resource.DecimalSI),
|
hugepages2M: *resource.NewQuantity(70, resource.DecimalSI),
|
||||||
|
Loading…
Reference in New Issue
Block a user