Skip to content

Commit

Permalink
MB-49632: Add functionality to get limits from linux cgroup
Browse files Browse the repository at this point in the history
Use /proc/mounts to look up the various mount points for
the cgroup v1 and v2 and use that information in order
to search for the pid in the various cgroup.procs files
stored on the system.

Control groups V1 use a group per controller type (cpu,
memory etc), whereas V2 use a single group.

V1:
   /sys/fs/cgroup/cpu/groupname/cgroup.procs
                               /cpu.cfs_period_us
                               /cpu.cfs_quota_us
   /sys/fs/cgroup/memory/groupname/cgroup.procs
                                  /memory.usage_in_bytes
                                  /memory.limit_in_bytes
   etc

V2:
   /sys/fs/cgroup/groupname/cgroup.procs
                           /cpu.max
                           /memory.current
                           /memory.max

Change-Id: I7ca7403092e3df2315c7538d66ce0191691ea175
Reviewed-on: https://review.couchbase.org/c/platform/+/165727
Tested-by: Build Bot <build@couchbase.com>
Reviewed-by: Dave Rigby <daver@couchbase.com>
  • Loading branch information
trondn committed Nov 25, 2021
1 parent ee6c2ac commit 6f57551
Show file tree
Hide file tree
Showing 10 changed files with 979 additions and 2 deletions.
8 changes: 8 additions & 0 deletions CMakeLists.txt
Expand Up @@ -286,6 +286,10 @@ foreach(platform_cbassert_variant ${platform_cbassert_VARIANTS})
target_link_libraries(${platform_cbassert_variant} PRIVATE Folly::headers)
endforeach()

if (UNIX AND NOT APPLE)
add_subdirectory(cgroup)
endif()

if (MEMORY_ALLOCATOR STREQUAL "jemalloc")
LIST(APPEND PLATFORM_FILES src/je_arena_corelocal_tracker.cc)
LIST(APPEND PLATFORM_FILES src/je_arena_malloc.cc)
Expand Down Expand Up @@ -361,6 +365,10 @@ TARGET_LINK_LIBRARIES(platform PUBLIC
${COUCHBASE_NETWORK_LIBS}
platform_cbassert nlohmann_json::nlohmann_json)

if (UNIX AND NOT APPLE)
target_link_libraries(platform PRIVATE cgroup)
endif()

SET_TARGET_PROPERTIES(platform PROPERTIES POSITION_INDEPENDENT_CODE true)
platform_enable_pch(platform)
cb_enable_unity_build(platform)
Expand Down
17 changes: 17 additions & 0 deletions cgroup/CMakeLists.txt
@@ -0,0 +1,17 @@
add_library(cgroup STATIC
cgroup_private.cc
cgroup.cc
${Platform_SOURCE_DIR}/include/cgroup/cgroup.h
cgroup_private.h)
target_include_directories(cgroup SYSTEM PRIVATE ${BOOST_INCLUDE_DIR})
target_include_directories(cgroup SYSTEM PUBLIC ${Platform_SOURCE_DIR}/include)
target_link_libraries(cgroup PRIVATE ${Boost_FILESYSTEM_LIBRARY})
set_property(TARGET cgroup PROPERTY POSITION_INDEPENDENT_CODE 1)
cb_enable_unity_build(cgroup)
cb_add_test_executable(cgroup_test cgroup_tests.cc)
target_link_libraries(cgroup_test cgroup
platform
Folly::folly
GTest::gtest
GTest::gtest_main)
add_test(cgroup_test cgroup_test)
82 changes: 82 additions & 0 deletions cgroup/cgroup.cc
@@ -0,0 +1,82 @@
/*
* Copyright 2021-Present Couchbase, Inc.
*
* Use of this software is governed by the Business Source License included
* in the file licenses/BSL-Couchbase.txt. As of the Change Date specified
* in that file, in accordance with the Business Source License, use of this
* software will be governed by the Apache License, Version 2.0, included in
* the file licenses/APL2.txt.
*/

#include "cgroup_private.h"

#include <cgroup/cgroup.h>
#include <sched.h>
#include <unistd.h>
#include <cstring>
#include <stdexcept>
#include <system_error>

namespace cb::cgroup {

size_t ControlGroup::get_available_cpu_count() {
int num = get_available_cpu_count_from_environment();
if (num != 0) {
return num;
}

num = get_available_cpu_count_from_quota();
if (num != 0) {
return num;
}

// No quota set, check for cpu sets
cpu_set_t set;
if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) {
return CPU_COUNT(&set);
}

auto ret = sysconf(_SC_NPROCESSORS_ONLN);
if (ret == -1) {
throw std::system_error(
std::error_code(errno, std::system_category()),
"cb::cgroup::get_available_cpu_count(): sysconf failed");
}

return size_t(ret);
}

size_t ControlGroup::get_available_cpu_count_from_environment() {
char* env = getenv("COUCHBASE_CPU_COUNT");
if (env == nullptr) {
return 0;
}
std::size_t pos;

// std::stoi allows for leading whitespace, so we should allow for
// trailing whitespace as well
auto count = std::stoi(env, &pos);
if (count > 0 && pos == strlen(env)) {
return count;
}

// there might be characters after the number...
const char* c = env + pos;
do {
if (!std::isspace(*c)) {
throw std::logic_error(
"cb::cgroup::get_available_cpu_count: Invalid format. "
"COUCHBASE_CPU_COUNT should be a number");
}
c++;
} while (*c);

// the string had trailing spaces.. accept it anyway
return count;
}

ControlGroup& ControlGroup::instance() {
static auto instance = priv::make_control_group();
return *instance;
}
} // namespace cb::cgroup

0 comments on commit 6f57551

Please sign in to comment.