1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-29 08:21:15 +03:00

MCOL-5500 This patch adds cgroup v2 support with some sanity checks for (#2849)

values reported by cgroups v1
This commit is contained in:
Roman Nozdrin
2023-06-09 15:37:21 +01:00
committed by GitHub
parent ab9b95e368
commit 375d162376
2 changed files with 75 additions and 186 deletions

View File

@ -18,8 +18,10 @@
#include "cgroupconfigurator.h" #include "cgroupconfigurator.h"
#include "configcpp.h" #include "configcpp.h"
#include "logger.h" #include "logger.h"
#include <charconv>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <limits>
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
using namespace boost; using namespace boost;
@ -77,9 +79,8 @@ CGroupConfigurator::CGroupConfigurator()
else else
cGroupDefined = true; cGroupDefined = true;
totalMemory = 0; ifstream v2Check("/sys/fs/cgroup/cgroup.controllers");
totalSwap = 0; cGroupVersion_ = (v2Check) ? v2 : v1;
printedWarning = false;
} }
CGroupConfigurator::~CGroupConfigurator() CGroupConfigurator::~CGroupConfigurator()
@ -88,9 +89,16 @@ CGroupConfigurator::~CGroupConfigurator()
uint32_t CGroupConfigurator::getNumCoresFromCGroup() uint32_t CGroupConfigurator::getNumCoresFromCGroup()
{ {
ostringstream filename_os; ostringstream filenameOs;
filename_os << "/sys/fs/cgroup/cpuset/" << cGroupName << "/cpus"; if (cGroupVersion_ == v1)
string filename = filename_os.str(); {
filenameOs << "/sys/fs/cgroup/cpuset/" << cGroupName << "/cpuset.cpus";
}
else
{
filenameOs << "/sys/fs/cgroup/" << cGroupName << "/cpuset.cpus";
}
string filename = filenameOs.str();
ifstream in(filename.c_str()); ifstream in(filename.c_str());
string cpusString; string cpusString;
@ -141,7 +149,7 @@ uint32_t CGroupConfigurator::getNumCoresFromCGroup()
first = last + 1; first = last + 1;
} }
// cout << "found " << cpus << " CPUS in the string " << cpusString << endl; cout << "found " << cpus << " CPUS in the string " << cpusString << endl;
return cpus; return cpus;
} }
@ -155,7 +163,7 @@ uint32_t CGroupConfigurator::getNumCoresFromProc()
uint32_t CGroupConfigurator::getNumCores() uint32_t CGroupConfigurator::getNumCores()
{ {
/* /*
Detect if InfiniDB is in a C-Group Detect if MCS is in a C-Group
- get the group ID - get the group ID
If not, get the number of cores from /proc If not, get the number of cores from /proc
*/ */
@ -171,7 +179,7 @@ uint32_t CGroupConfigurator::getNumCores()
ret = getNumCoresFromProc(); ret = getNumCoresFromProc();
} }
// cout << "There are " << ret << " cores available" << endl; cout << "There are " << ret << " cores available" << endl;
return ret; return ret;
} }
@ -188,11 +196,11 @@ uint64_t CGroupConfigurator::getTotalMemory()
{ {
ret = getTotalMemoryFromCGroup(); ret = getTotalMemoryFromCGroup();
if (ret == 0) if (ret == 0 || ret == std::numeric_limits<uint64_t>::max())
ret = getTotalMemoryFromProc(); ret = getTotalMemoryFromProc();
} }
// cout << "Total mem available is " << ret << endl; cout << "Total mem available is " << ret << endl;
totalMemory = ret; totalMemory = ret;
return totalMemory; return totalMemory;
} }
@ -201,23 +209,11 @@ uint64_t CGroupConfigurator::getTotalMemoryFromProc()
{ {
size_t memTot; size_t memTot;
#if defined(__FreeBSD__)
string cmd("sysctl -a | awk '/realmem/ {print int(($2+1023)/1024);}'");
FILE* cmdPipe;
char input[80];
cmdPipe = popen(cmd.c_str(), "r");
input[0] = '\0';
fgets(input, 80, cmdPipe);
input[79] = '\0';
pclose(cmdPipe);
memTot = atoi(input);
#else
ifstream in("/proc/meminfo"); ifstream in("/proc/meminfo");
string x; string x;
in >> x; in >> x;
in >> memTot; in >> memTot;
#endif
// memTot is now in KB, convert to bytes // memTot is now in KB, convert to bytes
memTot *= 1024; memTot *= 1024;
@ -227,40 +223,61 @@ uint64_t CGroupConfigurator::getTotalMemoryFromProc()
uint64_t CGroupConfigurator::getTotalMemoryFromCGroup() uint64_t CGroupConfigurator::getTotalMemoryFromCGroup()
{ {
ifstream in; std::string memLimitStr;
uint64_t ret; uint64_t memLimit = std::numeric_limits<uint64_t>::max();
ostringstream os; ostringstream os;
string filename;
os << "/sys/fs/cgroup/memory/" << cGroupName << "/memory.limit_in_bytes"; if (cGroupVersion_ == v1)
filename = os.str(); {
os << "/sys/fs/cgroup/memory/" << cGroupName << "/memory.limit_in_bytes";
}
else
{
os << "/sys/fs/cgroup/" << cGroupName << "/memory.max";
}
string filename = os.str();
in.open(filename.c_str()); ifstream in(filename.c_str());
if (!in) if (!in)
RETURN_NO_GROUP(0); RETURN_NO_GROUP(0);
try try
{ {
in >> ret; in >> memLimitStr;
} }
catch (...) catch (...)
{ {
RETURN_READ_ERROR(0); RETURN_READ_ERROR(0);
} }
return ret; if (cGroupVersion_ == v2 && memLimitStr == "max")
{
return std::numeric_limits<uint64_t>::max();
}
auto [ch, ec] = std::from_chars(memLimitStr.c_str(), memLimitStr.c_str() + memLimitStr.size(), memLimit);
if (ec != std::errc())
{
return std::numeric_limits<uint64_t>::max();
}
if (cGroupVersion_ == v1)
{
return std::min(getTotalMemoryFromProc(), memLimit);
}
return memLimit;
} }
uint64_t CGroupConfigurator::getFreeMemory() uint64_t CGroupConfigurator::getFreeMemory()
{ {
uint64_t ret; uint64_t ret;
if (!cGroupDefined) if (!cGroupDefined)
ret = getFreeMemoryFromProc(); ret = getFreeMemoryFromProc();
else else
{ {
uint64_t usage = getMemUsageFromCGroup(); uint64_t usage = getMemUsageFromCGroup();
cout << "usage " << usage << endl;
if (usage == 0) if (usage == 0)
ret = getFreeMemoryFromProc(); ret = getFreeMemoryFromProc();
@ -268,20 +285,26 @@ uint64_t CGroupConfigurator::getFreeMemory()
ret = getTotalMemory() - usage; ret = getTotalMemory() - usage;
} }
// cout << "free memory = " << ret << endl; cout << "free memory = " << ret << endl;
return ret; return ret;
} }
uint64_t CGroupConfigurator::getMemUsageFromCGroup() uint64_t CGroupConfigurator::getMemUsageFromCGroup()
{ {
uint64_t ret = 0;
bool found = false;
char oneline[80]; char oneline[80];
if (memUsageFilename.empty()) if (memUsageFilename.empty())
{ {
ostringstream filename; ostringstream filename;
filename << "/sys/fs/cgroup/memory/" << cGroupName << "/memory.stat"; if (cGroupVersion_ == v1)
{
memStatePrefix = "rss ";
filename << "/sys/fs/cgroup/memory/" << cGroupName << "/memory.stat";
}
else
{
memStatePrefix = "anon ";
filename << "/sys/fs/cgroup/" << cGroupName << "/memory.stat";
}
memUsageFilename = filename.str(); memUsageFilename = filename.str();
} }
@ -293,14 +316,13 @@ uint64_t CGroupConfigurator::getMemUsageFromCGroup()
try try
{ {
while (in && !found) while (in)
{ {
in.getline(oneline, 80); in.getline(oneline, 80);
if (strncmp(oneline, "rss", 2) == 0) if (strncmp(oneline, memStatePrefix.c_str(), memStatePrefix.size() - 1) == 0)
{ {
ret = atoll(&oneline[3]); return atoll(&oneline[memStatePrefix.size()]);
found = true;
} }
} }
} }
@ -309,7 +331,7 @@ uint64_t CGroupConfigurator::getMemUsageFromCGroup()
RETURN_READ_ERROR(0); RETURN_READ_ERROR(0);
} }
return ret; return 0;
} }
uint64_t CGroupConfigurator::getFreeMemoryFromProc() uint64_t CGroupConfigurator::getFreeMemoryFromProc()
@ -320,10 +342,6 @@ uint64_t CGroupConfigurator::getFreeMemoryFromProc()
uint64_t memTotal = 0; uint64_t memTotal = 0;
uint64_t memAvailable = 0; uint64_t memAvailable = 0;
#if defined(__FreeBSD__)
// FreeBSD is not supported, no optimization.
memAvailable = 0;
#else
ifstream in("/proc/meminfo"); ifstream in("/proc/meminfo");
string x; string x;
@ -354,137 +372,9 @@ uint64_t CGroupConfigurator::getFreeMemoryFromProc()
memAvailable = memFree + buffers + cached; memAvailable = memFree + buffers + cached;
} }
#endif
// amount available for application // amount available for application
memAvailable *= 1024; memAvailable *= 1024;
return memAvailable; return memAvailable;
} }
uint64_t CGroupConfigurator::getTotalSwapSpace()
{
int64_t ret;
if (totalSwap != 0)
return totalSwap;
if (!cGroupDefined)
ret = getTotalSwapFromSysinfo();
else
{
ret = getTotalMemAndSwapFromCGroup();
// if no limit is set in the cgroup, the file contains maxint64. Use sysinfo in that case.
if (ret == -1 || ret == numeric_limits<int64_t>::max())
ret = getTotalSwapFromSysinfo();
else
ret -= getTotalMemory();
}
// cout << "total swap=" << ret << endl;
totalSwap = ret;
return ret;
}
uint64_t CGroupConfigurator::getTotalSwapFromSysinfo()
{
struct sysinfo si;
sysinfo(&si);
return si.totalswap;
}
int64_t CGroupConfigurator::getTotalMemAndSwapFromCGroup()
{
int64_t ret;
ifstream in;
string filename;
ostringstream os;
os << "/sys/fs/cgroup/memory/" << cGroupName << "/memory.memsw.limit_in_bytes";
filename = os.str();
in.open(filename.c_str());
if (!in)
RETURN_NO_GROUP(-1);
try
{
in >> ret;
}
catch (...)
{
RETURN_READ_ERROR(-1);
}
return ret;
}
uint64_t CGroupConfigurator::getSwapInUse()
{
int64_t ret;
if (!cGroupDefined)
ret = getSwapInUseFromSysinfo();
else
{
ret = getSwapInUseFromCGroup();
if (ret == -1)
ret = getSwapInUseFromSysinfo();
}
// cout << "current swap in use=" << ret << endl;
return ret;
}
int64_t CGroupConfigurator::getSwapInUseFromCGroup()
{
int64_t ret = -1;
ifstream in;
bool found = false;
char oneline[80];
if (usedSwapFilename.empty())
{
ostringstream os;
os << "/sys/fs/cgroup/memory/" << cGroupName << "/memory.stat";
usedSwapFilename = os.str();
}
string& filename = usedSwapFilename;
in.open(filename.c_str());
if (!in)
RETURN_NO_GROUP(-1);
try
{
while (in && !found)
{
in.getline(oneline, 80);
if (strncmp(oneline, "swap", 4) == 0)
{
ret = atoll(&oneline[5]);
found = true;
}
}
}
catch (...)
{
RETURN_READ_ERROR(-1);
}
return ret;
}
uint64_t CGroupConfigurator::getSwapInUseFromSysinfo()
{
struct sysinfo si;
sysinfo(&si);
return si.totalswap - si.freeswap;
}
} // namespace utils } // namespace utils

View File

@ -31,14 +31,17 @@ namespace utils
class CGroupConfigurator class CGroupConfigurator
{ {
public: public:
enum CGroupVersions
{
v1,
v2,
};
CGroupConfigurator(); CGroupConfigurator();
virtual ~CGroupConfigurator(); virtual ~CGroupConfigurator();
uint32_t getNumCores(); uint32_t getNumCores();
uint64_t getTotalMemory(); uint64_t getTotalMemory();
uint64_t getFreeMemory(); uint64_t getFreeMemory();
uint64_t getTotalSwapSpace();
uint64_t getSwapInUse();
bool usingCGroup() bool usingCGroup()
{ {
@ -52,20 +55,16 @@ class CGroupConfigurator
uint64_t getTotalMemoryFromCGroup(); uint64_t getTotalMemoryFromCGroup();
uint64_t getFreeMemoryFromProc(); uint64_t getFreeMemoryFromProc();
uint64_t getMemUsageFromCGroup(); uint64_t getMemUsageFromCGroup();
uint64_t getTotalSwapFromSysinfo();
int64_t getTotalMemAndSwapFromCGroup();
uint64_t getSwapInUseFromSysinfo();
int64_t getSwapInUseFromCGroup();
std::string memUsageFilename;
std::string usedSwapFilename;
std::string cGroupName; std::string cGroupName;
std::string memUsageFilename;
std::string memStatePrefix;
bool cGroupDefined; bool cGroupDefined;
config::Config* config; config::Config* config;
uint64_t totalMemory; uint64_t totalMemory = 0;
uint64_t totalSwap; uint64_t totalSwap = 0;
bool printedWarning; bool printedWarning = false;
enum CGroupVersions cGroupVersion_;
}; };
} // namespace utils } // namespace utils