Skip to content

Commit

Permalink
Add tests for cgroup subsystem availability
Browse files Browse the repository at this point in the history
Add tests for omrsysinfo_cgroup_is_system_available, get_available_subsystems,
are_subsystems_available, get_enabled_subsystems, enable_subsystems, and
are_subsystems_enabled.

Issue: #1281
Signed-off-by: Eric Yang <eric.yang@ibm.com>
  • Loading branch information
EricYangIBM committed May 24, 2022
1 parent 26a2042 commit 191eba3
Showing 1 changed file with 183 additions and 0 deletions.
183 changes: 183 additions & 0 deletions fvtest/porttest/si.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if defined(LINUX)
#include <linux/magic.h>
#include <sys/vfs.h>
#include <fstream>
#include <regex>
#endif /* defined(LINUX) */
#if defined(OMR_OS_WINDOWS)
#include <direct.h>
#endif /* defined(OMR_OS_WINDOWS) */
Expand Down Expand Up @@ -2362,6 +2368,183 @@ TEST(PortSysinfoTest, sysinfo_test_os_kernel_info)
return;
}

class CgroupTest : public ::testing::Test {
protected:
#if defined(LINUX)
static bool isV1Available;
static bool isV2Available;
static std::string memCgroup;
static std::string cpuCgroup;
const static std::map<std::string, uint64_t> supportedSubsystems;
constexpr static char CGROUP_MOUNT_POINT[] = "/sys/fs/cgroup";
static uint64_t available;
#endif /* defined(LINUX) */

/* Initialize static vars. */
static void
SetUpTestCase()
{
#if defined(LINUX)
isV1Available = isCgroupV1Available();
isV2Available = isCgroupV2Available();
ASSERT_TRUE(isV1Available != isV2Available);

std::ifstream cgroupFile(std::string("/proc/") + std::to_string(getpid()) + std::string("/cgroup"));
std::string line;
if (isV1Available) {
while (std::getline(cgroupFile, line)) {
std::regex v1Regex(R"(^[0-9]+:([^:]*):(.+)$)");
std::smatch sm;

ASSERT_TRUE(std::regex_match(line, sm, v1Regex));
if (0 != sm[1].length()) {
std::stringstream ss(sm[1].str());
std::vector<std::string> subsystems;

while (ss.good()) {
std::string subsystem;
std::getline(ss, subsystem, ',');
subsystems.push_back(subsystem);
}
for (auto s : subsystems) {
auto it = supportedSubsystems.find(s);
if (supportedSubsystems.end() != it) {
available |= it->second;
switch(it->second) {
case OMR_CGROUP_SUBSYSTEM_CPU:
cpuCgroup = sm[2].str();
break;
case OMR_CGROUP_SUBSYSTEM_MEMORY:
memCgroup = sm[2].str();
break;
}
}
}
}
}
} else {
ASSERT_TRUE(std::getline(cgroupFile, line));
std::regex v2Regex(R"(^0::(.+)$)");
std::smatch sm;

ASSERT_TRUE(std::regex_match(line, sm, v2Regex));
ASSERT_GT(sm[1].length(), 0);

cpuCgroup = sm[1].str();
memCgroup = sm[1].str();
std::ifstream controllerFile(CGROUP_MOUNT_POINT + cpuCgroup + "/cgroup.controllers");
std::string s;
while (controllerFile >> s) {
auto it = supportedSubsystems.find(s);
if (supportedSubsystems.end() != it) {
available |= it->second;
}
}
}
#endif /* defined(LINUX) */
}

#if defined(LINUX)
static bool
isCgroupV1Available(void)
{
struct statfs buf = {0};
int32_t rc = 0;
bool result = true;

/* If tmpfs is mounted on /sys/fs/cgroup, then it indicates cgroup v1 system is available */
rc = statfs("/sys/fs/cgroup", &buf);
if (0 != rc) {
result = false;
} else if (TMPFS_MAGIC != buf.f_type) {
result = false;
}

return result;
}

static bool
isCgroupV2Available(void)
{
bool result = false;

/* If the cgroup.controllers file exists at the root cgroup, then v2 is available. */
if (0 == access("/sys/fs/cgroup/cgroup.controllers", F_OK)) {
result = true;
}

return result;
}
#endif /* defined(LINUX) */

};

#if defined(LINUX)
bool CgroupTest::isV1Available = false;
bool CgroupTest::isV2Available = false;
std::string CgroupTest::memCgroup;
std::string CgroupTest::cpuCgroup;
const std::map<std::string, uint64_t> CgroupTest::supportedSubsystems = {
{"cpu", OMR_CGROUP_SUBSYSTEM_CPU},
{"memory", OMR_CGROUP_SUBSYSTEM_MEMORY},
{"cpuset", OMR_CGROUP_SUBSYSTEM_CPUSET}
};
constexpr char CgroupTest::CGROUP_MOUNT_POINT[];
uint64_t CgroupTest::available = 0;
#endif /* defined(LINUX) */

/**
* Test omrsysinfo_cgroup_is_system_available.
*/
TEST(PortSysinfoTest, sysinfo_cgroup_is_system_available)
{
OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary());
const char *testName = "omrsysinfo_cgroup_is_system_available";
BOOLEAN result = FALSE;

reportTestEntry(OMRPORTLIB, testName);

result = omrsysinfo_cgroup_is_system_available();

#if defined(LINUX)
if (FALSE == result) {
outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_is_system_available returned FALSE on linux\n");
}
#else /* defined(LINUX) */
if (TRUE == result) {
outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_is_system_available returned TRUE on nonlinux\n");
}
#endif /* defined(LINUX) */

reportTestExit(OMRPORTLIB, testName);
return;
}

/**
* Test omrsysinfo_cgroup_get_available_subsystems.
*/
TEST_F(CgroupTest, sysinfo_cgroup_get_available_subsystems)
{
OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary());
const char *testName = "omrsysinfo_cgroup_get_available_subsystems";
uint64_t available = 0;

reportTestEntry(OMRPORTLIB, testName);

available = omrsysinfo_cgroup_get_available_subsystems();

#if defined(LINUX)
ASSERT_EQ(available, CgroupTest::available);
#else /* defined(LINUX) */
if (0 != available) {
outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_get_available_subsystems returned nonzero on nonlinux\n");
}
#endif /* defined(LINUX) */

reportTestExit(OMRPORTLIB, testName);
return;
}

/**
* Test omrsysinfo_cgroup_get_memlimit.
*/
Expand Down

0 comments on commit 191eba3

Please sign in to comment.