Blame SOURCES/19650-cgroup-oom.patch

9fb373
From 6c3e409c5de00ba108392be3e6502d5a49c235ce Mon Sep 17 00:00:00 2001
9fb373
From: Tom Deseyn <tom.deseyn@gmail.com>
9fb373
Date: Thu, 16 Aug 2018 20:47:20 +0200
9fb373
Subject: [PATCH] Determine memory load based on cgroup usage. (#19518)
9fb373
9fb373
cgroup usage is used to trigger oom kills. It includes rss and file cache
9fb373
of the cgroup.
9fb373
9fb373
The implementation was only using the process rss to determine memory load.
9fb373
This is less than the cgroup usage and leads to oom kills due to GC not
9fb373
being triggered soon enough.
9fb373
---
9fb373
 src/gc/unix/cgroup.cpp      | 31 +++++++++++++++++++++++++++++--
9fb373
 src/gc/unix/gcenv.unix.cpp  |  4 ++--
9fb373
 src/pal/inc/pal.h           |  2 +-
9fb373
 src/pal/src/misc/cgroup.cpp | 30 +++++++++++++++++++++++++++++-
9fb373
 src/vm/gcenv.os.cpp         |  2 +-
9fb373
 5 files changed, 62 insertions(+), 7 deletions(-)
9fb373
9fb373
diff --git a/src/gc/unix/cgroup.cpp b/src/gc/unix/cgroup.cpp
9fb373
index f892a339d8a..a3307ce8a53 100644
9fb373
--- a/src/gc/unix/cgroup.cpp
9fb373
+++ b/src/gc/unix/cgroup.cpp
9fb373
@@ -33,6 +33,7 @@ Module Name:
9fb373
 #define PROC_CGROUP_FILENAME "/proc/self/cgroup"
9fb373
 #define PROC_STATM_FILENAME "/proc/self/statm"
9fb373
 #define MEM_LIMIT_FILENAME "/memory.limit_in_bytes"
9fb373
+#define MEM_USAGE_FILENAME "/memory.usage_in_bytes"
9fb373
 #define CFS_QUOTA_FILENAME "/cpu.cfs_quota_us"
9fb373
 #define CFS_PERIOD_FILENAME "/cpu.cfs_period_us"
9fb373
 
9fb373
@@ -74,6 +75,27 @@ class CGroup
9fb373
         return result;
9fb373
     }
9fb373
 
9fb373
+    bool GetPhysicalMemoryUsage(size_t *val)
9fb373
+    {
9fb373
+        char *mem_usage_filename = nullptr;
9fb373
+        bool result = false;
9fb373
+
9fb373
+        if (m_memory_cgroup_path == nullptr)
9fb373
+            return result;
9fb373
+
9fb373
+        size_t len = strlen(m_memory_cgroup_path);
9fb373
+        len += strlen(MEM_USAGE_FILENAME);
9fb373
+        mem_usage_filename = (char*)malloc(len+1);
9fb373
+        if (mem_usage_filename == nullptr)
9fb373
+            return result;
9fb373
+
9fb373
+        strcpy(mem_usage_filename, m_memory_cgroup_path);
9fb373
+        strcat(mem_usage_filename, MEM_USAGE_FILENAME);
9fb373
+        result = ReadMemoryValueFromFile(mem_usage_filename, val);
9fb373
+        free(mem_usage_filename);
9fb373
+        return result;
9fb373
+    }
9fb373
+
9fb373
     bool GetCpuLimit(uint32_t *val)
9fb373
     {
9fb373
         long long quota;
9fb373
@@ -427,19 +449,24 @@ size_t GetRestrictedPhysicalMemoryLimit()
9fb373
     return physical_memory_limit;
9fb373
 }
9fb373
 
9fb373
-bool GetWorkingSetSize(size_t* val)
9fb373
+bool GetPhysicalMemoryUsed(size_t* val)
9fb373
 {
9fb373
     bool result = false;
9fb373
     size_t linelen;
9fb373
     char* line = nullptr;
9fb373
+    CGroup cgroup;
9fb373
 
9fb373
     if (val == nullptr)
9fb373
         return false;
9fb373
 
9fb373
+    // Linux uses cgroup usage to trigger oom kills.
9fb373
+    if (cgroup.GetPhysicalMemoryUsage(val))
9fb373
+        return true;
9fb373
+
9fb373
+    // process resident set size.
9fb373
     FILE* file = fopen(PROC_STATM_FILENAME, "r");
9fb373
     if (file != nullptr && getline(&line, &linelen, file) != -1)
9fb373
     {
9fb373
-
9fb373
         char* context = nullptr;
9fb373
         char* strTok = strtok_r(line, " ", &context); 
9fb373
         strTok = strtok_r(nullptr, " ", &context); 
9fb373
diff --git a/src/gc/unix/gcenv.unix.cpp b/src/gc/unix/gcenv.unix.cpp
9fb373
index f34dd8993b2..a1e12961ada 100644
9fb373
--- a/src/gc/unix/gcenv.unix.cpp
9fb373
+++ b/src/gc/unix/gcenv.unix.cpp
9fb373
@@ -56,7 +56,7 @@ static uint8_t* g_helperPage = 0;
9fb373
 static pthread_mutex_t g_flushProcessWriteBuffersMutex;
9fb373
 
9fb373
 size_t GetRestrictedPhysicalMemoryLimit();
9fb373
-bool GetWorkingSetSize(size_t* val);
9fb373
+bool GetPhysicalMemoryUsed(size_t* val);
9fb373
 bool GetCpuLimit(uint32_t* val);
9fb373
 
9fb373
 static size_t g_RestrictedPhysicalMemoryLimit = 0;
9fb373
@@ -623,7 +623,7 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available
9fb373
 
9fb373
         // Get the physical memory in use - from it, we can get the physical memory available.
9fb373
         // We do this only when we have the total physical memory available.
9fb373
-        if (total > 0 && GetWorkingSetSize(&used))
9fb373
+        if (total > 0 && GetPhysicalMemoryUsed(&used))
9fb373
         {
9fb373
             available = total > used ? total-used : 0; 
9fb373
             load = (uint32_t)(((float)used * 100) / (float)total);
9fb373
diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h
9fb373
index 60f4a81c66e..5106c014211 100644
9fb373
--- a/src/pal/inc/pal.h
9fb373
+++ b/src/pal/inc/pal.h
9fb373
@@ -2364,7 +2364,7 @@ PAL_GetRestrictedPhysicalMemoryLimit(VOID);
9fb373
 PALIMPORT
9fb373
 BOOL
9fb373
 PALAPI
9fb373
-PAL_GetWorkingSetSize(size_t* val);
9fb373
+PAL_GetPhysicalMemoryUsed(size_t* val);
9fb373
 
9fb373
 PALIMPORT
9fb373
 BOOL
9fb373
diff --git a/src/pal/src/misc/cgroup.cpp b/src/pal/src/misc/cgroup.cpp
9fb373
index 7a3a9261a11..145586a0b98 100644
9fb373
--- a/src/pal/src/misc/cgroup.cpp
9fb373
+++ b/src/pal/src/misc/cgroup.cpp
9fb373
@@ -23,6 +23,7 @@ SET_DEFAULT_DEBUG_CHANNEL(MISC);
9fb373
 #define PROC_CGROUP_FILENAME "/proc/self/cgroup"
9fb373
 #define PROC_STATM_FILENAME "/proc/self/statm"
9fb373
 #define MEM_LIMIT_FILENAME "/memory.limit_in_bytes"
9fb373
+#define MEM_USAGE_FILENAME "/memory.usage_in_bytes"
9fb373
 #define CFS_QUOTA_FILENAME "/cpu.cfs_quota_us"
9fb373
 #define CFS_PERIOD_FILENAME "/cpu.cfs_period_us"
9fb373
 class CGroup
9fb373
@@ -63,6 +64,27 @@ class CGroup
9fb373
         return result;
9fb373
     }
9fb373
 
9fb373
+    bool GetPhysicalMemoryUsage(size_t *val)
9fb373
+    {
9fb373
+        char *mem_usage_filename = nullptr;
9fb373
+        bool result = false;
9fb373
+
9fb373
+        if (m_memory_cgroup_path == nullptr)
9fb373
+            return result;
9fb373
+
9fb373
+        size_t len = strlen(m_memory_cgroup_path);
9fb373
+        len += strlen(MEM_USAGE_FILENAME);
9fb373
+        mem_usage_filename = (char*)malloc(len+1);
9fb373
+        if (mem_usage_filename == nullptr)
9fb373
+            return result;
9fb373
+
9fb373
+        strcpy(mem_usage_filename, m_memory_cgroup_path);
9fb373
+        strcat(mem_usage_filename, MEM_USAGE_FILENAME);
9fb373
+        result = ReadMemoryValueFromFile(mem_usage_filename, val);
9fb373
+        free(mem_usage_filename);
9fb373
+        return result;
9fb373
+    }
9fb373
+
9fb373
     bool GetCpuLimit(UINT *val)
9fb373
     {
9fb373
         long long quota;
9fb373
@@ -384,15 +406,21 @@ PAL_GetRestrictedPhysicalMemoryLimit()
9fb373
 
9fb373
 BOOL
9fb373
 PALAPI
9fb373
-PAL_GetWorkingSetSize(size_t* val)
9fb373
+PAL_GetPhysicalMemoryUsed(size_t* val)
9fb373
 {
9fb373
     BOOL result = false;
9fb373
     size_t linelen;
9fb373
     char* line = nullptr;
9fb373
+    CGroup cgroup;
9fb373
 
9fb373
     if (val == nullptr)
9fb373
         return FALSE;
9fb373
 
9fb373
+    // Linux uses cgroup usage to trigger oom kills.
9fb373
+    if (cgroup.GetPhysicalMemoryUsage(val))
9fb373
+        return TRUE;
9fb373
+
9fb373
+    // process resident set size.
9fb373
     FILE* file = fopen(PROC_STATM_FILENAME, "r");
9fb373
     if (file != nullptr && getline(&line, &linelen, file) != -1)
9fb373
     {
9fb373
diff --git a/src/vm/gcenv.os.cpp b/src/vm/gcenv.os.cpp
9fb373
index 70dc2619dd9..99e9ff6c727 100644
9fb373
--- a/src/vm/gcenv.os.cpp
9fb373
+++ b/src/vm/gcenv.os.cpp
9fb373
@@ -605,7 +605,7 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available
9fb373
             workingSetSize = pmc.WorkingSetSize;
9fb373
         }
9fb373
 #else
9fb373
-        status = PAL_GetWorkingSetSize(&workingSetSize);
9fb373
+        status = PAL_GetPhysicalMemoryUsed(&workingSetSize);
9fb373
 #endif
9fb373
         if(status)
9fb373
         {