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 11d92a7
Showing
12 changed files
with
690 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,271 @@ | ||
// 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> | ||
|
||
#define MAX_PATH 1024 | ||
#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" | ||
|
||
class CGroup | ||
{ | ||
char _memory_cgroup_path[MAX_PATH]; | ||
public: | ||
CGroup() | ||
{ | ||
if (!FindMemoryHierarchyMount(_memory_cgroup_path)) | ||
{ | ||
_memory_cgroup_path[0] = '\0'; | ||
return; | ||
} | ||
char cgroup_path_relative_to_mount[MAX_PATH]; | ||
if (!FindCGroupPathForMemorySubsystem(cgroup_path_relative_to_mount)) | ||
{ | ||
_memory_cgroup_path[0] = '\0'; | ||
return; | ||
} | ||
strcat(_memory_cgroup_path, cgroup_path_relative_to_mount); | ||
} | ||
|
||
bool GetPhysicalMemoryLimit(size_t *val) | ||
{ | ||
char mem_limit_filename[MAX_PATH]; | ||
|
||
if (_memory_cgroup_path[0] == 0) | ||
return false; | ||
|
||
strcpy(mem_limit_filename, _memory_cgroup_path); | ||
strcat(mem_limit_filename, MEM_LIMIT_FILENAME); | ||
return ReadMemoryValueFromFile(mem_limit_filename, val); | ||
} | ||
|
||
bool GetSwapMemoryLimit(size_t *val) | ||
{ | ||
char memsw_limit_filename[MAX_PATH]; | ||
|
||
if (_memory_cgroup_path[0] == 0) | ||
return false; | ||
|
||
strcpy(memsw_limit_filename, _memory_cgroup_path); | ||
strcat(memsw_limit_filename, MEM_SWAP_LIMIT_FILENAME); | ||
return ReadMemoryValueFromFile(memsw_limit_filename, val); | ||
} | ||
private: | ||
bool 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 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 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
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.