summaryrefslogtreecommitdiff
path: root/src/gc/unix/cgroup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gc/unix/cgroup.cpp')
-rw-r--r--src/gc/unix/cgroup.cpp203
1 files changed, 164 insertions, 39 deletions
diff --git a/src/gc/unix/cgroup.cpp b/src/gc/unix/cgroup.cpp
index 1775ef7ff0..992678b634 100644
--- a/src/gc/unix/cgroup.cpp
+++ b/src/gc/unix/cgroup.cpp
@@ -9,7 +9,7 @@ Module Name:
cgroup.cpp
Abstract:
- Read memory limits for the current process
+ Read memory and cpu limits for the current process
--*/
#include <cstdint>
#include <cstddef>
@@ -26,42 +26,24 @@ Abstract:
#define PROC_CGROUP_FILENAME "/proc/self/cgroup"
#define PROC_STATM_FILENAME "/proc/self/statm"
#define MEM_LIMIT_FILENAME "/memory.limit_in_bytes"
+#define CFS_QUOTA_FILENAME "/cpu.cfs_quota_us"
+#define CFS_PERIOD_FILENAME "/cpu.cfs_period_us"
class CGroup
{
char* m_memory_cgroup_path;
+ char* m_cpu_cgroup_path;
public:
CGroup()
{
- m_memory_cgroup_path = nullptr;
- char* memoryHierarchyMount = nullptr;
- char *cgroup_path_relative_to_mount = nullptr;
- size_t len;
- memoryHierarchyMount = FindMemoryHierarchyMount();
- if (memoryHierarchyMount == nullptr)
- goto done;
-
- cgroup_path_relative_to_mount = FindCGroupPathForMemorySubsystem();
- if (cgroup_path_relative_to_mount == nullptr)
- goto done;
-
- len = strlen(memoryHierarchyMount);
- len += strlen(cgroup_path_relative_to_mount);
- m_memory_cgroup_path = (char*)malloc(len+1);
- if (m_memory_cgroup_path == nullptr)
- goto done;
-
- strcpy(m_memory_cgroup_path, memoryHierarchyMount);
- strcat(m_memory_cgroup_path, cgroup_path_relative_to_mount);
-
- done:
- free(memoryHierarchyMount);
- free(cgroup_path_relative_to_mount);
+ m_memory_cgroup_path = FindCgroupPath(&IsMemorySubsystem);
+ m_cpu_cgroup_path = FindCgroupPath(&IsCpuSubsystem);
}
~CGroup()
{
free(m_memory_cgroup_path);
+ free(m_cpu_cgroup_path);
}
bool GetPhysicalMemoryLimit(size_t *val)
@@ -84,15 +66,89 @@ public:
free(mem_limit_filename);
return result;
}
+
+ bool GetCpuLimit(uint32_t *val)
+ {
+ long long quota;
+ long long period;
+ long long cpu_count;
+
+ quota = ReadCpuCGroupValue(CFS_QUOTA_FILENAME);
+ if (quota <= 0)
+ return false;
+
+ period = ReadCpuCGroupValue(CFS_PERIOD_FILENAME);
+ if (period <= 0)
+ return false;
+
+ // Cannot have less than 1 CPU
+ if (quota <= period)
+ {
+ *val = 1;
+ return true;
+ }
+
+ cpu_count = quota / period;
+ if (cpu_count < UINT32_MAX)
+ {
+ *val = cpu_count;
+ }
+ else
+ {
+ *val = UINT32_MAX;
+ }
+
+ return true;
+ }
private:
- char* FindMemoryHierarchyMount()
+ static bool IsMemorySubsystem(const char *strTok){
+ return strcmp("memory", strTok) == 0;
+ }
+
+ static bool IsCpuSubsystem(const char *strTok){
+ return strcmp("cpu", strTok) == 0;
+ }
+
+ static char* FindCgroupPath(bool (*is_subsystem)(const char *)){
+ char *cgroup_path = nullptr;
+ char *hierarchy_mount = nullptr;
+ char *hierarchy_root = nullptr;
+ char *cgroup_path_relative_to_mount = nullptr;
+
+ FindHierarchyMount(is_subsystem, &hierarchy_mount, &hierarchy_root);
+ if (hierarchy_mount == nullptr || hierarchy_root == nullptr)
+ goto done;
+
+ cgroup_path_relative_to_mount = FindCGroupPathForSubsystem(is_subsystem);
+ if (cgroup_path_relative_to_mount == nullptr)
+ goto done;
+
+ cgroup_path = (char*)malloc(strlen(hierarchy_mount) + strlen(cgroup_path_relative_to_mount) + 1);
+ if (cgroup_path == nullptr)
+ goto done;
+
+ strcpy(cgroup_path, hierarchy_mount);
+ // For a host cgroup, we need to append the relative path.
+ // In a docker container, the root and relative path are the same and we don't need to append.
+ if (strcmp(hierarchy_root, cgroup_path_relative_to_mount) != 0)
+ strcat(cgroup_path, cgroup_path_relative_to_mount);
+
+ done:
+ free(hierarchy_mount);
+ free(hierarchy_root);
+ free(cgroup_path_relative_to_mount);
+ return cgroup_path;
+ }
+
+ static void FindHierarchyMount(bool (*is_subsystem)(const char *), char** pmountpath, char** pmountroot)
{
char *line = nullptr;
size_t lineLen = 0, maxLineLen = 0;
char *filesystemType = nullptr;
char *options = nullptr;
- char* mountpath = nullptr;
+ char *mountpath = nullptr;
+ char *mountroot = nullptr;
FILE *mountinfofile = fopen(PROC_MOUNTINFO_FILENAME, "r");
if (mountinfofile == nullptr)
@@ -113,11 +169,11 @@ private:
maxLineLen = lineLen;
}
- char* separatorChar = strchr(line, '-');
+ char* separatorChar = strstr(line, " - ");
// See man page of proc to get format for /proc/self/mountinfo file
int sscanfRet = sscanf(separatorChar,
- "- %s %*s %s",
+ " - %s %*s %s",
filesystemType,
options);
if (sscanfRet != 2)
@@ -132,21 +188,26 @@ private:
char* strTok = strtok_r(options, ",", &context);
while (strTok != nullptr)
{
- if (strncmp("memory", strTok, 6) == 0)
+ if (is_subsystem(strTok))
{
mountpath = (char*)malloc(lineLen+1);
if (mountpath == nullptr)
goto done;
+ mountroot = (char*)malloc(lineLen+1);
+ if (mountroot == nullptr)
+ goto done;
sscanfRet = sscanf(line,
- "%*s %*s %*s %*s %s ",
+ "%*s %*s %*s %s %s ",
+ mountroot,
mountpath);
- if (sscanfRet != 1)
- {
- free(mountpath);
- mountpath = nullptr;
+ if (sscanfRet != 2)
assert(!"Failed to parse mount info file contents with sscanf.");
- }
+
+ // assign the output arguments and clear the locals so we don't free them.
+ *pmountpath = mountpath;
+ *pmountroot = mountroot;
+ mountpath = mountroot = nullptr;
goto done;
}
strTok = strtok_r(nullptr, ",", &context);
@@ -154,15 +215,16 @@ private:
}
}
done:
+ free(mountpath);
+ free(mountroot);
free(filesystemType);
free(options);
free(line);
if (mountinfofile)
fclose(mountinfofile);
- return mountpath;
}
- char* FindCGroupPathForMemorySubsystem()
+ static char* FindCGroupPathForSubsystem(bool (*is_subsystem)(const char *))
{
char *line = nullptr;
size_t lineLen = 0;
@@ -205,7 +267,7 @@ private:
char* strTok = strtok_r(subsystem_list, ",", &context);
while (strTok != nullptr)
{
- if (strncmp("memory", strTok, 6) == 0)
+ if (is_subsystem(strTok))
{
result = true;
break;
@@ -271,6 +333,59 @@ private:
free(line);
return result;
}
+
+ long long ReadCpuCGroupValue(const char* subsystemFilename){
+ char *filename = nullptr;
+ bool result = false;
+ long long val;
+
+ if (m_cpu_cgroup_path == nullptr)
+ return -1;
+
+ filename = (char*)malloc(strlen(m_cpu_cgroup_path) + strlen(subsystemFilename) + 1);
+ if (filename == nullptr)
+ return -1;
+
+ strcpy(filename, m_cpu_cgroup_path);
+ strcat(filename, subsystemFilename);
+ result = ReadLongLongValueFromFile(filename, &val);
+ free(filename);
+ if (!result)
+ return -1;
+
+ return val;
+ }
+
+ bool ReadLongLongValueFromFile(const char* filename, long long* val)
+ {
+ bool result = false;
+ char *line = nullptr;
+ size_t lineLen = 0;
+
+ FILE* file = nullptr;
+
+ if (val == nullptr)
+ goto done;
+
+ file = fopen(filename, "r");
+ if (file == nullptr)
+ goto done;
+
+ if (getline(&line, &lineLen, file) == -1)
+ goto done;
+
+ errno = 0;
+ *val = atoll(line);
+ if (errno != 0)
+ goto done;
+
+ result = true;
+ done:
+ if (file)
+ fclose(file);
+ free(line);
+ return result;
+ }
};
size_t GetRestrictedPhysicalMemoryLimit()
@@ -340,3 +455,13 @@ bool GetWorkingSetSize(size_t* val)
free(line);
return result;
}
+
+bool GetCpuLimit(uint32_t* val)
+{
+ CGroup cgroup;
+
+ if (val == nullptr)
+ return false;
+
+ return cgroup.GetCpuLimit(val);
+}