summaryrefslogtreecommitdiff
path: root/src/pal/src/misc/sysinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/misc/sysinfo.cpp')
-rw-r--r--src/pal/src/misc/sysinfo.cpp83
1 files changed, 71 insertions, 12 deletions
diff --git a/src/pal/src/misc/sysinfo.cpp b/src/pal/src/misc/sysinfo.cpp
index e3d001b544..52e8ec065d 100644
--- a/src/pal/src/misc/sysinfo.cpp
+++ b/src/pal/src/misc/sysinfo.cpp
@@ -25,6 +25,8 @@ Revision History:
#include <sched.h>
#include <errno.h>
#include <unistd.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
#include <sys/types.h>
#if HAVE_SYSCTL
#include <sys/sysctl.h>
@@ -239,6 +241,58 @@ GetSystemInfo(
PERF_EXIT(GetSystemInfo);
}
+// Get memory size multiplier based on the passed in units (k = kilo, m = mega, g = giga)
+static uint64_t GetMemorySizeMultiplier(char units)
+{
+ switch(units)
+ {
+ case 'g':
+ case 'G': return 1024 * 1024 * 1024;
+ case 'm':
+ case 'M': return 1024 * 1024;
+ case 'k':
+ case 'K': return 1024;
+ }
+
+ // No units multiplier
+ return 1;
+}
+
+#ifndef __APPLE__
+// Try to read the MemAvailable entry from /proc/meminfo.
+// Return true if the /proc/meminfo existed, the entry was present and we were able to parse it.
+static bool ReadMemAvailable(uint64_t* memAvailable)
+{
+ bool foundMemAvailable = false;
+ FILE* memInfoFile = fopen("/proc/meminfo", "r");
+ if (memInfoFile != NULL)
+ {
+ char *line = nullptr;
+ size_t lineLen = 0;
+
+ while (getline(&line, &lineLen, memInfoFile) != -1)
+ {
+ char units = '\0';
+ uint64_t available;
+ int fieldsParsed = sscanf(line, "MemAvailable: %" SCNu64 " %cB", &available, &units);
+
+ if (fieldsParsed >= 1)
+ {
+ uint64_t multiplier = GetMemorySizeMultiplier(units);
+ *memAvailable = available * multiplier;
+ foundMemAvailable = true;
+ break;
+ }
+ }
+
+ free(line);
+ fclose(memInfoFile);
+ }
+
+ return foundMemAvailable;
+}
+#endif // __APPLE__
+
/*++
Function:
GlobalMemoryStatusEx
@@ -365,7 +419,22 @@ GlobalMemoryStatusEx(
if (lpBuffer->ullTotalPhys > 0)
{
#ifndef __APPLE__
- lpBuffer->ullAvailPhys = sysconf(SYSCONF_PAGES) * sysconf(_SC_PAGE_SIZE);
+ static volatile bool tryReadMemInfo = true;
+
+ if (tryReadMemInfo)
+ {
+ // Ensure that we don't try to read the /proc/meminfo in successive calls to the GlobalMemoryStatusEx
+ // if we have failed to access the file or the file didn't contain the MemAvailable value.
+ tryReadMemInfo = ReadMemAvailable(&lpBuffer->ullAvailPhys);
+ }
+
+ if (!tryReadMemInfo)
+ {
+ // The /proc/meminfo doesn't exist or it doesn't contain the MemAvailable row or the format of the row is invalid
+ // Fall back to getting the available pages using sysconf.
+ lpBuffer->ullAvailPhys = sysconf(SYSCONF_PAGES) * sysconf(_SC_PAGE_SIZE);
+ }
+
INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys;
lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
#else
@@ -445,17 +514,7 @@ ReadMemoryValueFromFile(const char* filename, size_t* val)
if (errno != 0)
goto done;
- multiplier = 1;
- switch(*endptr)
- {
- case 'g':
- case 'G': multiplier = 1024;
- case 'm':
- case 'M': multiplier = multiplier*1024;
- case 'k':
- case 'K': multiplier = multiplier*1024;
- }
-
+ multiplier = GetMemorySizeMultiplier(*endptr);
*val = num * multiplier;
result = true;
if (*val/multiplier != num)