@@ -38,6 +38,10 @@ SET_DEFAULT_DEBUG_CHANNEL(MISC);
3838#define CGROUP1_MEMORY_LIMIT_FILENAME " /memory.limit_in_bytes"
3939#define CGROUP2_MEMORY_LIMIT_FILENAME " /memory.max"
4040#define CGROUP_MEMORY_STAT_FILENAME " /memory.stat"
41+ #define CGROUP1_MEMORY_USAGE_FILENAME " /memory.usage_in_bytes"
42+ #define CGROUP2_MEMORY_USAGE_FILENAME " /memory.current"
43+ #define CGROUP1_MEMORY_STAT_INACTIVE_FIELD " total_inactive_file "
44+ #define CGROUP2_MEMORY_STAT_INACTIVE_FIELD " inactive_file "
4145#define CGROUP1_CFS_QUOTA_FILENAME " /cpu.cfs_quota_us"
4246#define CGROUP1_CFS_PERIOD_FILENAME " /cpu.cfs_period_us"
4347#define CGROUP2_CPU_MAX_FILENAME " /cpu.max"
@@ -49,37 +53,12 @@ class CGroup
4953
5054 static char *s_memory_cgroup_path;
5155 static char *s_cpu_cgroup_path;
52-
53- static const char *s_mem_stat_key_names[];
54- static size_t s_mem_stat_key_lengths[];
55- static size_t s_mem_stat_n_keys;
5656public:
5757 static void Initialize ()
5858 {
5959 s_cgroup_version = FindCGroupVersion ();
6060 s_memory_cgroup_path = FindCGroupPath (s_cgroup_version == 1 ? &IsCGroup1MemorySubsystem : nullptr );
6161 s_cpu_cgroup_path = FindCGroupPath (s_cgroup_version == 1 ? &IsCGroup1CpuSubsystem : nullptr );
62-
63- if (s_cgroup_version == 1 )
64- {
65- s_mem_stat_n_keys = 4 ;
66- s_mem_stat_key_names[0 ] = " total_inactive_anon " ;
67- s_mem_stat_key_names[1 ] = " total_active_anon " ;
68- s_mem_stat_key_names[2 ] = " total_dirty " ;
69- s_mem_stat_key_names[3 ] = " total_unevictable " ;
70- }
71- else
72- {
73- s_mem_stat_n_keys = 3 ;
74- s_mem_stat_key_names[0 ] = " anon " ;
75- s_mem_stat_key_names[1 ] = " file_dirty " ;
76- s_mem_stat_key_names[2 ] = " unevictable " ;
77- }
78-
79- for (size_t i = 0 ; i < s_mem_stat_n_keys; i++)
80- {
81- s_mem_stat_key_lengths[i] = strlen (s_mem_stat_key_names[i]);
82- }
8362 }
8463
8564 static void Cleanup ()
@@ -108,9 +87,9 @@ class CGroup
10887 if (s_cgroup_version == 0 )
10988 return false ;
11089 else if (s_cgroup_version == 1 )
111- return GetCGroupMemoryUsage (val);
90+ return GetCGroupMemoryUsage (val, CGROUP1_MEMORY_USAGE_FILENAME, CGROUP1_MEMORY_STAT_INACTIVE_FIELD );
11291 else if (s_cgroup_version == 2 )
113- return GetCGroupMemoryUsage (val);
92+ return GetCGroupMemoryUsage (val, CGROUP2_MEMORY_USAGE_FILENAME, CGROUP2_MEMORY_STAT_INACTIVE_FIELD );
11493 else
11594 {
11695 _ASSERTE (!" Unknown cgroup version." );
@@ -416,8 +395,38 @@ class CGroup
416395 return result;
417396 }
418397
419- static bool GetCGroupMemoryUsage (size_t *val)
398+ static bool GetCGroupMemoryUsage (size_t *val, const char *filename, const char *inactiveFileFieldName )
420399 {
400+ // Use the same way to calculate memory load as popular container tools (Docker, Kubernetes, Containerd etc.)
401+ // For cgroup v1: value of 'memory.usage_in_bytes' minus 'total_inactive_file' value of 'memory.stat'
402+ // For cgroup v2: value of 'memory.current' minus 'inactive_file' value of 'memory.stat'
403+
404+ char * mem_usage_filename = nullptr ;
405+ if (asprintf (&mem_usage_filename, " %s%s" , s_memory_cgroup_path, filename) < 0 )
406+ return false ;
407+
408+ uint64_t temp = 0 ;
409+
410+ size_t usage = 0 ;
411+
412+ bool result = ReadMemoryValueFromFile (mem_usage_filename, &temp);
413+ if (result)
414+ {
415+ if (temp > std::numeric_limits<size_t >::max ())
416+ {
417+ usage = std::numeric_limits<size_t >::max ();
418+ }
419+ else
420+ {
421+ usage = (size_t )temp;
422+ }
423+ }
424+
425+ free (mem_usage_filename);
426+
427+ if (!result)
428+ return result;
429+
421430 if (s_memory_cgroup_path == nullptr )
422431 return false ;
423432
@@ -432,34 +441,32 @@ class CGroup
432441
433442 char *line = nullptr ;
434443 size_t lineLen = 0 ;
435- size_t readValues = 0 ;
444+ bool foundInactiveFileValue = false ;
436445 char * endptr;
437446
438- *val = 0 ;
439- while (getline (&line, &lineLen, stat_file) != -1 && readValues < s_mem_stat_n_keys)
447+ size_t inactiveFileFieldNameLength = strlen (inactiveFileFieldName);
448+
449+ while (getline (&line, &lineLen, stat_file) != -1 )
440450 {
441- for ( size_t i = 0 ; i < s_mem_stat_n_keys; i++ )
451+ if ( strncmp (line, inactiveFileFieldName, inactiveFileFieldNameLength) == 0 )
442452 {
443- if (strncmp (line, s_mem_stat_key_names[i], s_mem_stat_key_lengths[i]) == 0 )
453+ errno = 0 ;
454+ const char * startptr = line + inactiveFileFieldNameLength;
455+ size_t inactiveFileValue = strtoll (startptr, &endptr, 10 );
456+ if (endptr != startptr && errno == 0 )
444457 {
445- errno = 0 ;
446- const char * startptr = line + s_mem_stat_key_lengths[i];
447- *val += strtoll (startptr, &endptr, 10 );
448- if (endptr != startptr && errno == 0 )
449- readValues++;
450-
451- break ;
458+ foundInactiveFileValue = true ;
459+ *val = usage - inactiveFileValue;
452460 }
461+
462+ break ;
453463 }
454464 }
455465
456466 fclose (stat_file);
457467 free (line);
458468
459- if (readValues == s_mem_stat_n_keys)
460- return true ;
461-
462- return false ;
469+ return foundInactiveFileValue;
463470 }
464471
465472 static bool ReadMemoryValueFromFile (const char * filename, uint64_t * val)
@@ -624,10 +631,6 @@ int CGroup::s_cgroup_version = 0;
624631char *CGroup::s_memory_cgroup_path = nullptr ;
625632char *CGroup::s_cpu_cgroup_path = nullptr ;
626633
627- const char *CGroup::s_mem_stat_key_names[4 ] = {};
628- size_t CGroup::s_mem_stat_key_lengths[4 ] = {};
629- size_t CGroup::s_mem_stat_n_keys = 0 ;
630-
631634void InitializeCGroup ()
632635{
633636 CGroup::Initialize ();
0 commit comments