This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
rahul
committed
Mar 10, 2017
1 parent
515af5e
commit 5fc16f8
Showing
13 changed files
with
716 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
/*++ | ||
Module Name: | ||
cgroup.cpp | ||
Abstract: | ||
Read memory limits for the current process | ||
--*/ | ||
#include <cstdint> | ||
#include <cstddef> | ||
#include <cassert> | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <sys/resource.h> | ||
#include <errno.h> | ||
#include "cgroup.h" | ||
|
||
#define SIZE_T_MAX (~(size_t)0) | ||
#define PROC_MOUNTINFO_FILENAME "/proc/self/mountinfo" | ||
#define PROC_CGROUP_FILENAME "/proc/self/cgroup" | ||
#define PROC_STATM_FILENAME "/proc/self/statm" | ||
#define MEM_LIMIT_FILENAME "/memory.limit_in_bytes" | ||
#define MEM_SWAP_LIMIT_FILENAME "/memory.memsw.limit_in_bytes" | ||
|
||
CGroup::CGroup() | ||
{ | ||
if (!FindMemoryHierarchyMount(m_memory_cgroup_path)) | ||
{ | ||
m_memory_cgroup_path[0] = '\0'; | ||
return; | ||
} | ||
char cgroup_path_relative_to_mount[MAX_PATH]; | ||
if (!FindCGroupPathForMemorySubsystem(cgroup_path_relative_to_mount)) | ||
{ | ||
m_memory_cgroup_path[0] = '\0'; | ||
return; | ||
} | ||
strcat(m_memory_cgroup_path, cgroup_path_relative_to_mount); | ||
} | ||
|
||
bool CGroup::GetPhysicalMemoryLimit(size_t *val) | ||
{ | ||
char mem_limit_filename[MAX_PATH]; | ||
|
||
if (m_memory_cgroup_path[0] == 0) | ||
return false; | ||
|
||
strcpy(mem_limit_filename, m_memory_cgroup_path); | ||
strcat(mem_limit_filename, MEM_LIMIT_FILENAME); | ||
return ReadMemoryValueFromFile(mem_limit_filename, val); | ||
} | ||
|
||
bool CGroup::GetSwapMemoryLimit(size_t *val) | ||
{ | ||
char memsw_limit_filename[MAX_PATH]; | ||
|
||
if (m_memory_cgroup_path[0] == 0) | ||
return false; | ||
|
||
strcpy(memsw_limit_filename, m_memory_cgroup_path); | ||
strcat(memsw_limit_filename, MEM_SWAP_LIMIT_FILENAME); | ||
return ReadMemoryValueFromFile(memsw_limit_filename, val); | ||
} | ||
|
||
bool CGroup::FindMemoryHierarchyMount(char* mountpath) | ||
{ | ||
bool retval = false; | ||
char *line = nullptr; | ||
size_t lineLen = 0; | ||
FILE *mountinfofile = fopen(PROC_MOUNTINFO_FILENAME, "r"); | ||
if (mountinfofile == NULL) | ||
goto done; | ||
|
||
while (!retval && getline(&line, &lineLen, mountinfofile) != -1) | ||
{ | ||
char filesystemType[100]; | ||
char options[MAX_PATH]; | ||
|
||
char* separatorChar = strchr(line, '-'); | ||
|
||
// See man page of proc to get format for /proc/self/mountinfo file | ||
int sscanfRet = sscanf(separatorChar, | ||
"- %s %*s %s", | ||
filesystemType, | ||
options); | ||
if (sscanfRet != 2) | ||
{ | ||
assert(!"Failed to parse mount info file contents with sscanf."); | ||
goto done; | ||
} | ||
|
||
if (strncmp(filesystemType, "cgroup", 6) == 0) | ||
{ | ||
char* context = NULL; | ||
char* strTok = strtok_r(options, ",", &context); | ||
while (strTok != NULL) | ||
{ | ||
if (strncmp("memory", strTok, 6) == 0) | ||
{ | ||
sscanfRet = sscanf(line, | ||
"%*d %*d %*s %*s %s ", | ||
mountpath); | ||
if (sscanfRet != 1) | ||
{ | ||
assert(!"Failed to parse mount info file contents with sscanf."); | ||
goto done; | ||
} | ||
retval = true; | ||
break; | ||
} | ||
strTok = strtok_r(NULL, ",", &context); | ||
} | ||
} | ||
} | ||
done: | ||
if (line) | ||
free(line); | ||
if (mountinfofile) | ||
fclose(mountinfofile); | ||
return retval; | ||
} | ||
|
||
bool CGroup::FindCGroupPathForMemorySubsystem(char* cgrouppath) | ||
{ | ||
bool retval = false; | ||
char *line = nullptr; | ||
size_t lineLen = 0; | ||
FILE *cgroupfile = fopen(PROC_CGROUP_FILENAME, "r"); | ||
if (cgroupfile == NULL) | ||
goto done; | ||
|
||
while (!retval && getline(&line, &lineLen, cgroupfile) != -1) | ||
{ | ||
char subsystem_list[100]; | ||
char cgroup_path[MAX_PATH]; | ||
|
||
// See man page of proc to get format for /proc/self/cgroup file | ||
int sscanfRet = sscanf(line, | ||
"%*[^:]:%[^:]:%s", | ||
subsystem_list, | ||
cgroup_path); | ||
if (sscanfRet != 2) | ||
{ | ||
assert(!"Failed to parse cgroup info file contents with sscanf."); | ||
goto done; | ||
} | ||
|
||
char* context = NULL; | ||
char* strTok = strtok_r(subsystem_list, ",", &context); | ||
while (strTok != NULL) | ||
{ | ||
if (strncmp("memory", strTok, 6) == 0) | ||
{ | ||
strcpy(cgrouppath, cgroup_path); | ||
retval = true; | ||
break; | ||
} | ||
strTok = strtok_r(NULL, ",", &context); | ||
} | ||
} | ||
done: | ||
if (line) | ||
free(line); | ||
if (cgroupfile) | ||
fclose(cgroupfile); | ||
return retval; | ||
} | ||
|
||
bool CGroup::ReadMemoryValueFromFile(const char* filename, size_t* val) | ||
{ | ||
bool result = false; | ||
char *line = nullptr; | ||
size_t lineLen = 0; | ||
char* endptr = NULL; | ||
size_t num = 0, l, multiplier; | ||
FILE* file = NULL; | ||
|
||
if (val == NULL) | ||
goto done; | ||
|
||
file = fopen(filename, "r"); | ||
if (file == NULL) | ||
goto done; | ||
|
||
if (getline(&line, &lineLen, file) == -1) | ||
goto done; | ||
|
||
errno = 0; | ||
num = strtoull(line, &endptr, 0); | ||
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; | ||
} | ||
|
||
*val = num * multiplier; | ||
result = true; | ||
if (*val/multiplier != num) | ||
result = false; | ||
done: | ||
if (file) | ||
fclose(file); | ||
if (line) | ||
free(line); | ||
return result; | ||
} | ||
|
||
size_t GetRestrictedPhysicalMemoryLimit() | ||
{ | ||
CGroup cgroup; | ||
size_t result; | ||
size_t physical_memory_limit; | ||
size_t swap_memory_limit; | ||
|
||
if (!cgroup.GetPhysicalMemoryLimit(&physical_memory_limit)) | ||
physical_memory_limit = SIZE_T_MAX; | ||
if (cgroup.GetSwapMemoryLimit(&swap_memory_limit)) | ||
{ | ||
assert(swap_memory_limit >= physical_memory_limit); | ||
result = swap_memory_limit; | ||
} | ||
else | ||
result = physical_memory_limit; | ||
struct rlimit curr_rlimit; | ||
size_t rlimit_soft_limit = RLIM_INFINITY; | ||
if (getrlimit(RLIMIT_AS, &curr_rlimit) == 0) | ||
{ | ||
rlimit_soft_limit = curr_rlimit.rlim_cur; | ||
} | ||
result = (result < rlimit_soft_limit) ? result : rlimit_soft_limit; | ||
return result; | ||
} | ||
|
||
bool GetWorkingSetSize(size_t* val) | ||
{ | ||
bool result = false; | ||
size_t linelen; | ||
char* line = NULL; | ||
|
||
FILE* file = fopen(PROC_STATM_FILENAME, "r"); | ||
if (file != NULL && getline(&line, &linelen, file) != -1) | ||
{ | ||
if (sscanf(line, "%*s %zu %*s %*s %*s %*s %*s", val) == 1) | ||
result = true; | ||
} | ||
|
||
if (file) | ||
fclose(file); | ||
if (line) | ||
free(line); | ||
return result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
/*++ | ||
Module Name: | ||
cgroup.h | ||
Abstract: | ||
Read memory limits for the current process | ||
--*/ | ||
|
||
#define MAX_PATH 1024 | ||
|
||
class CGroup | ||
{ | ||
char m_memory_cgroup_path[MAX_PATH]; | ||
public: | ||
CGroup(); | ||
bool GetPhysicalMemoryLimit(size_t* val); | ||
bool GetSwapMemoryLimit(size_t* val); | ||
private: | ||
bool FindMemoryHierarchyMount(char* mountpath); | ||
bool FindCGroupPathForMemorySubsystem(char* cgrouppath); | ||
bool ReadMemoryValueFromFile(const char* filename, size_t* val); | ||
}; | ||
|
||
size_t GetRestrictedPhysicalMemoryLimit(); | ||
bool GetWorkingSetSize(size_t* val); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.