Skip to content

Commit a25682c

Browse files
tmdsdanmoseley
authored andcommitted
Determine memory load based on cgroup usage. (dotnet#19518) (dotnet#19650)
cgroup usage is used to trigger oom kills. It includes rss and file cache of the cgroup. The implementation was only using the process rss to determine memory load. This is less than the cgroup usage and leads to oom kills due to GC not being triggered soon enough.
1 parent 387cfc2 commit a25682c

File tree

5 files changed

+62
-7
lines changed

5 files changed

+62
-7
lines changed

src/gc/unix/cgroup.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Module Name:
3333
#define PROC_CGROUP_FILENAME "/proc/self/cgroup"
3434
#define PROC_STATM_FILENAME "/proc/self/statm"
3535
#define MEM_LIMIT_FILENAME "/memory.limit_in_bytes"
36+
#define MEM_USAGE_FILENAME "/memory.usage_in_bytes"
3637
#define CFS_QUOTA_FILENAME "/cpu.cfs_quota_us"
3738
#define CFS_PERIOD_FILENAME "/cpu.cfs_period_us"
3839

@@ -74,6 +75,27 @@ class CGroup
7475
return result;
7576
}
7677

78+
bool GetPhysicalMemoryUsage(size_t *val)
79+
{
80+
char *mem_usage_filename = nullptr;
81+
bool result = false;
82+
83+
if (m_memory_cgroup_path == nullptr)
84+
return result;
85+
86+
size_t len = strlen(m_memory_cgroup_path);
87+
len += strlen(MEM_USAGE_FILENAME);
88+
mem_usage_filename = (char*)malloc(len+1);
89+
if (mem_usage_filename == nullptr)
90+
return result;
91+
92+
strcpy(mem_usage_filename, m_memory_cgroup_path);
93+
strcat(mem_usage_filename, MEM_USAGE_FILENAME);
94+
result = ReadMemoryValueFromFile(mem_usage_filename, val);
95+
free(mem_usage_filename);
96+
return result;
97+
}
98+
7799
bool GetCpuLimit(uint32_t *val)
78100
{
79101
long long quota;
@@ -427,19 +449,24 @@ size_t GetRestrictedPhysicalMemoryLimit()
427449
return physical_memory_limit;
428450
}
429451

430-
bool GetWorkingSetSize(size_t* val)
452+
bool GetPhysicalMemoryUsed(size_t* val)
431453
{
432454
bool result = false;
433455
size_t linelen;
434456
char* line = nullptr;
457+
CGroup cgroup;
435458

436459
if (val == nullptr)
437460
return false;
438461

462+
// Linux uses cgroup usage to trigger oom kills.
463+
if (cgroup.GetPhysicalMemoryUsage(val))
464+
return true;
465+
466+
// process resident set size.
439467
FILE* file = fopen(PROC_STATM_FILENAME, "r");
440468
if (file != nullptr && getline(&line, &linelen, file) != -1)
441469
{
442-
443470
char* context = nullptr;
444471
char* strTok = strtok_r(line, " ", &context);
445472
strTok = strtok_r(nullptr, " ", &context);

src/gc/unix/gcenv.unix.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static uint8_t* g_helperPage = 0;
5656
static pthread_mutex_t g_flushProcessWriteBuffersMutex;
5757

5858
size_t GetRestrictedPhysicalMemoryLimit();
59-
bool GetWorkingSetSize(size_t* val);
59+
bool GetPhysicalMemoryUsed(size_t* val);
6060
bool GetCpuLimit(uint32_t* val);
6161

6262
static size_t g_RestrictedPhysicalMemoryLimit = 0;
@@ -623,7 +623,7 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available
623623

624624
// Get the physical memory in use - from it, we can get the physical memory available.
625625
// We do this only when we have the total physical memory available.
626-
if (total > 0 && GetWorkingSetSize(&used))
626+
if (total > 0 && GetPhysicalMemoryUsed(&used))
627627
{
628628
available = total > used ? total-used : 0;
629629
load = (uint32_t)(((float)used * 100) / (float)total);

src/pal/inc/pal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2364,7 +2364,7 @@ PAL_GetRestrictedPhysicalMemoryLimit(VOID);
23642364
PALIMPORT
23652365
BOOL
23662366
PALAPI
2367-
PAL_GetWorkingSetSize(size_t* val);
2367+
PAL_GetPhysicalMemoryUsed(size_t* val);
23682368

23692369
PALIMPORT
23702370
BOOL

src/pal/src/misc/cgroup.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ SET_DEFAULT_DEBUG_CHANNEL(MISC);
2323
#define PROC_CGROUP_FILENAME "/proc/self/cgroup"
2424
#define PROC_STATM_FILENAME "/proc/self/statm"
2525
#define MEM_LIMIT_FILENAME "/memory.limit_in_bytes"
26+
#define MEM_USAGE_FILENAME "/memory.usage_in_bytes"
2627
#define CFS_QUOTA_FILENAME "/cpu.cfs_quota_us"
2728
#define CFS_PERIOD_FILENAME "/cpu.cfs_period_us"
2829
class CGroup
@@ -63,6 +64,27 @@ class CGroup
6364
return result;
6465
}
6566

67+
bool GetPhysicalMemoryUsage(size_t *val)
68+
{
69+
char *mem_usage_filename = nullptr;
70+
bool result = false;
71+
72+
if (m_memory_cgroup_path == nullptr)
73+
return result;
74+
75+
size_t len = strlen(m_memory_cgroup_path);
76+
len += strlen(MEM_USAGE_FILENAME);
77+
mem_usage_filename = (char*)malloc(len+1);
78+
if (mem_usage_filename == nullptr)
79+
return result;
80+
81+
strcpy(mem_usage_filename, m_memory_cgroup_path);
82+
strcat(mem_usage_filename, MEM_USAGE_FILENAME);
83+
result = ReadMemoryValueFromFile(mem_usage_filename, val);
84+
free(mem_usage_filename);
85+
return result;
86+
}
87+
6688
bool GetCpuLimit(UINT *val)
6789
{
6890
long long quota;
@@ -384,15 +406,21 @@ PAL_GetRestrictedPhysicalMemoryLimit()
384406

385407
BOOL
386408
PALAPI
387-
PAL_GetWorkingSetSize(size_t* val)
409+
PAL_GetPhysicalMemoryUsed(size_t* val)
388410
{
389411
BOOL result = false;
390412
size_t linelen;
391413
char* line = nullptr;
414+
CGroup cgroup;
392415

393416
if (val == nullptr)
394417
return FALSE;
395418

419+
// Linux uses cgroup usage to trigger oom kills.
420+
if (cgroup.GetPhysicalMemoryUsage(val))
421+
return TRUE;
422+
423+
// process resident set size.
396424
FILE* file = fopen(PROC_STATM_FILENAME, "r");
397425
if (file != nullptr && getline(&line, &linelen, file) != -1)
398426
{

src/vm/gcenv.os.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available
605605
workingSetSize = pmc.WorkingSetSize;
606606
}
607607
#else
608-
status = PAL_GetWorkingSetSize(&workingSetSize);
608+
status = PAL_GetPhysicalMemoryUsed(&workingSetSize);
609609
#endif
610610
if(status)
611611
{

0 commit comments

Comments
 (0)