From 52670962bd675667b0e9932b9ef06ba2fcda5bb6 Mon Sep 17 00:00:00 2001 From: Nikolay Martyanov Date: Fri, 27 Sep 2024 11:11:00 +0200 Subject: [PATCH] pillar: Allow EVE memory limits above 4GB. Previously, EVE's memory limit was stored in bytes using a uint32 value in the global configuration, limiting the maximum memory to approximately 4GB. This restriction prevented setting higher memory limits necessary for applications like kubevirt. This commit introduces support for specifying the EVE memory limit in mebibytes (MiB) while maintaining backward compatibility with the byte-based configuration. If the byte-based limit is set and valid, it is used; otherwise, the MiB-based limit is applied. This enhancement allows EVE to support memory limits beyond 4GB and ensures accurate memory management, preventing issues in scenarios that require higher memory allocations. Signed-off-by: Nikolay Martyanov (cherry picked from commit 2f2f9055423b6ecf9607b2b9242a235fe2c304a8) --- pkg/pillar/cmd/zedmanager/memorysizemgmt.go | 29 ++++++++++++++++++++- pkg/pillar/types/global.go | 11 +++++++- pkg/pillar/types/global_test.go | 1 + 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/pkg/pillar/cmd/zedmanager/memorysizemgmt.go b/pkg/pillar/cmd/zedmanager/memorysizemgmt.go index 6915355103..6ce4f30993 100644 --- a/pkg/pillar/cmd/zedmanager/memorysizemgmt.go +++ b/pkg/pillar/cmd/zedmanager/memorysizemgmt.go @@ -11,6 +11,30 @@ import ( "github.com/lf-edge/eve/pkg/pillar/vault" ) +// getMemoryReservedForEveInBytes returns the amount of memory reserved for eve +// in bytes. There are two sources for this value: +// 1. Global config value `EveMemoryLimitInBytes` +// 2. Global config value `EveMemoryLimitInMiB` +// The first onve is the legacy config, as it does not support values more than 4GB. +// But we still support it for backward compatibility. If it's set to valid value, +// we use it. If it's set to 0 (which means the value set might be too high), +// we fallback to the second one. +func getMemoryReservedForEveInBytes(ctxPtr *zedmanagerContext) (uint64, error) { + // First, check the legacy config + memoryReservedForEveInBytes := ctxPtr.globalConfig.GlobalValueInt(types.EveMemoryLimitInBytes) + if memoryReservedForEveInBytes != 0 { + return uint64(memoryReservedForEveInBytes), nil + } + // If the legacy config is not set, or contains 0 (which means the value set might be too high), + // fallback to the new config + memoryReservedForEveInMiB := ctxPtr.globalConfig.GlobalValueInt(types.EveMemoryLimitInMiB) + if memoryReservedForEveInMiB != 0 { + return uint64(memoryReservedForEveInMiB) << 20, nil + } + return 0, fmt.Errorf("memoryReservedForEveInMiB is not set") + +} + // getRemainingMemory returns how many bytes remain for app instance usage // which is based on the running and about to run app instances. // It also returns a count for the app instances which are not in those @@ -41,7 +65,10 @@ func getRemainingMemory(ctxPtr *zedmanagerContext) (uint64, uint64, uint64, erro latentMemorySize += mem } } - memoryReservedForEve := uint64(ctxPtr.globalConfig.GlobalValueInt(types.EveMemoryLimitInBytes)) + memoryReservedForEve, err := getMemoryReservedForEveInBytes(ctxPtr) + if err != nil { + return 0, 0, 0, fmt.Errorf("getMemoryReservedForEveInBytes failed: %v", err) + } if vault.ReadPersistType() == types.PersistZFS { zfsArcMaxLimit, err := types.GetZFSArcMaxSizeInBytes() if err != nil { diff --git a/pkg/pillar/types/global.go b/pkg/pillar/types/global.go index f9d02d9ca3..40ff3c12f4 100644 --- a/pkg/pillar/types/global.go +++ b/pkg/pillar/types/global.go @@ -225,7 +225,12 @@ const ( VgaAccess GlobalSettingKey = "debug.enable.vga" // AllowAppVnc global setting key AllowAppVnc GlobalSettingKey = "app.allow.vnc" - // EveMemoryLimitInBytes global setting key + // EveMemoryLimitInMiB global setting key, memory limit for EVE in MiB + EveMemoryLimitInMiB GlobalSettingKey = "memory.eve.limit.MiB" + // EveMemoryLimitInBytes global setting key, memory limit for EVE in bytes + // Deprecated: Use EveMemoryLimitInMiB. This config is limited to 4GB + // as it is stored as uint32. Nevertheles, for backward compatibility, + // this config is still supported and has higher priority than EveMemoryLimitInMiB. EveMemoryLimitInBytes GlobalSettingKey = "memory.eve.limit.bytes" // How much memory overhead is allowed for VMM needs VmmMemoryLimitInMiB GlobalSettingKey = "memory.vmm.limit.MiB" @@ -805,6 +810,8 @@ func NewConfigItemSpecMap() ConfigItemSpecMap { if err != nil { logrus.Errorf("getEveMemoryLimitInBytes failed: %v", err) } + // Round up to the nearest MiB + eveMemoryLimitInMiB := uint32((eveMemoryLimitInBytes + 1024*1024 - 1) / (1024 * 1024)) var configItemSpecMap ConfigItemSpecMap configItemSpecMap.GlobalSettings = make(map[GlobalSettingKey]ConfigItemSpec) configItemSpecMap.AgentSettings = make(map[AgentSettingKey]ConfigItemSpec) @@ -869,6 +876,8 @@ func NewConfigItemSpecMap() ConfigItemSpecMap { // configItemSpecMap.AddIntItem(EveMemoryLimitInBytes, uint32(eveMemoryLimitInBytes), uint32(eveMemoryLimitInBytes), 0xFFFFFFFF) + configItemSpecMap.AddIntItem(EveMemoryLimitInMiB, eveMemoryLimitInMiB, + eveMemoryLimitInMiB, 0xFFFFFFFF) // Limit manual vmm overhead override to 1 PiB configItemSpecMap.AddIntItem(VmmMemoryLimitInMiB, 0, 0, uint32(1024*1024*1024)) // LogRemainToSendMBytes - Default is 2 Gbytes, minimum is 10 Mbytes diff --git a/pkg/pillar/types/global_test.go b/pkg/pillar/types/global_test.go index 6ff3353675..e7c4d6d5c9 100644 --- a/pkg/pillar/types/global_test.go +++ b/pkg/pillar/types/global_test.go @@ -187,6 +187,7 @@ func TestNewConfigItemSpecMap(t *testing.T) { GOGCForcedGrowthMemInMiB, GOGCForcedGrowthMemPerc, EveMemoryLimitInBytes, + EveMemoryLimitInMiB, VmmMemoryLimitInMiB, IgnoreMemoryCheckForApps, IgnoreDiskCheckForApps,