diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 34a40a7dce186..a2d4369249a73 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -105,10 +105,12 @@ class CgroupController: public CHeapObj { protected: char* _cgroup_path; + char* _mount_point; public: virtual char* subsystem_path() = 0; virtual bool is_read_only() = 0; char* cgroup_path() { return _cgroup_path; } + char* mount_point() { return _mount_point; } virtual bool needs_hierarchy_adjustment() { return false; } /* Read a numerical value as unsigned long @@ -207,8 +209,11 @@ class CgroupCpuController: public CHeapObj { virtual int cpu_period() = 0; virtual int cpu_shares() = 0; virtual bool needs_hierarchy_adjustment() = 0; - virtual CgroupCpuController* adjust_controller(int host_cpus) = 0; virtual bool is_read_only() = 0; + virtual char* subsystem_path() = 0; + virtual void set_subsystem_path(char* cgroup_path) = 0; + virtual char* mount_point() = 0; + virtual char* cgroup_path() = 0; }; // Pure virtual class representing version agnostic memory controllers @@ -223,9 +228,12 @@ class CgroupMemoryController: public CHeapObj { virtual jlong rss_usage_in_bytes() = 0; virtual jlong cache_usage_in_bytes() = 0; virtual void print_version_specific_info(outputStream* st, julong host_mem) = 0; - virtual CgroupMemoryController* adjust_controller(julong phys_mem) = 0; virtual bool needs_hierarchy_adjustment() = 0; virtual bool is_read_only() = 0; + virtual char* subsystem_path() = 0; + virtual void set_subsystem_path(char* cgroup_path) = 0; + virtual char* mount_point() = 0; + virtual char* cgroup_path() = 0; }; class CgroupSubsystem: public CHeapObj { diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index 774da1e5ec3fc..5ed2b6886040d 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -49,17 +49,97 @@ int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) { } CgroupMemoryController* CgroupUtil::adjust_controller(CgroupMemoryController* mem) { - if (mem->needs_hierarchy_adjustment()) { - julong phys_mem = os::Linux::physical_memory(); - return mem->adjust_controller(phys_mem); + if (!mem->needs_hierarchy_adjustment()) { + // nothing to do + return mem; } + log_trace(os, container)("Adjusting controller path for memory: %s", mem->subsystem_path()); + assert(mem->cgroup_path() != nullptr, "invariant"); + char* orig = os::strdup(mem->cgroup_path()); + char* cg_path = os::strdup(orig); + char* last_slash; + julong phys_mem = os::Linux::physical_memory(); + jlong limit = mem->read_memory_limit_in_bytes(phys_mem); + bool path_iterated = false; + while (limit < 0 && (last_slash = strrchr(cg_path, '/')) != cg_path) { + *last_slash = '\0'; // strip path + // update to shortened path and try again + mem->set_subsystem_path(cg_path); + limit = mem->read_memory_limit_in_bytes(phys_mem); + path_iterated = true; + if (limit > 0) { + log_trace(os, container)("Adjusted controller path for memory to: %s", mem->subsystem_path()); + os::free(cg_path); + os::free(orig); + return mem; + } + } + // no lower limit found or limit at leaf + os::free(cg_path); + if (path_iterated) { + mem->set_subsystem_path((char*)"/"); + limit = mem->read_memory_limit_in_bytes(phys_mem); + if (limit > 0) { + // handle limit set at mount point + log_trace(os, container)("Adjusted controller path for memory to: %s", mem->subsystem_path()); + os::free(orig); + return mem; + } + log_trace(os, container)("No lower limit found in hierarchy %s, adjusting to original path %s", + mem->mount_point(), orig); + mem->set_subsystem_path(orig); + } else { + log_trace(os, container)("Lowest limit for memory at leaf: %s", + mem->subsystem_path()); + } + os::free(orig); return mem; } CgroupCpuController* CgroupUtil::adjust_controller(CgroupCpuController* cpu) { - if (cpu->needs_hierarchy_adjustment()) { - int cpu_total = os::Linux::active_processor_count(); - return cpu->adjust_controller(cpu_total); + if (!cpu->needs_hierarchy_adjustment()) { + // nothing to do + return cpu; + } + log_trace(os, container)("Adjusting controller path for cpu: %s", cpu->subsystem_path()); + assert(cpu->cgroup_path() != nullptr, "invariant"); + char* orig = os::strdup(cpu->cgroup_path()); + char* cg_path = os::strdup(orig); + char* last_slash; + int host_cpus = os::Linux::active_processor_count(); + int cpus = CgroupUtil::processor_count(cpu, host_cpus); + bool path_iterated = false; + while (cpus == host_cpus && (last_slash = strrchr(cg_path, '/')) != cg_path) { + *last_slash = '\0'; // strip path + // update to shortened path and try again + cpu->set_subsystem_path((char*)cg_path); + cpus = CgroupUtil::processor_count(cpu, host_cpus); + path_iterated = true; + if (cpus != host_cpus) { + log_trace(os, container)("Adjusted controller path for cpu to: %s", cpu->subsystem_path()); + os::free(cg_path); + os::free(orig); + return cpu; + } + } + // no lower limit found or limit at leaf + os::free(cg_path); + if (path_iterated) { + cpu->set_subsystem_path((char*)"/"); + cpus = CgroupUtil::processor_count(cpu, host_cpus); + if (cpus != host_cpus) { + // handle limit set at mount point + log_trace(os, container)("Adjusted controller path for cpu to: %s", cpu->subsystem_path()); + os::free(orig); + return cpu; + } + log_trace(os, container)("No lower limit found in hierarchy %s, adjusting to original path %s", + cpu->mount_point(), orig); + cpu->set_subsystem_path(orig); + } else { + log_trace(os, container)("Lowest limit for cpu at leaf: %s", + cpu->subsystem_path()); } + os::free(orig); return cpu; } diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 6667642793af7..a16fd22d22394 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -73,101 +73,6 @@ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { } } -bool CgroupV1MemoryController::needs_hierarchy_adjustment() { - return reader()->needs_hierarchy_adjustment(); -} - -bool CgroupV1CpuController::needs_hierarchy_adjustment() { - return reader()->needs_hierarchy_adjustment(); -} - -CgroupV1MemoryController* CgroupV1MemoryController::adjust_controller(julong phys_mem) { - log_trace(os, container)("Adjusting v1 controller path for memory: %s", reader()->subsystem_path()); - assert(reader()->cgroup_path() != nullptr, "invariant"); - char* orig = os::strdup(reader()->cgroup_path()); - char* cg_path = os::strdup(orig); - char* last_slash; - jlong limit = read_memory_limit_in_bytes(phys_mem); - bool path_iterated = false; - while (limit < 0 && (last_slash = strrchr(cg_path, '/')) != cg_path) { - *last_slash = '\0'; // strip path - // update to shortened path and try again - reader()->set_subsystem_path(cg_path); - limit = read_memory_limit_in_bytes(phys_mem); - path_iterated = true; - if (limit > 0) { - log_trace(os, container)("Adjusted v1 controller path for memory to: %s", reader()->subsystem_path()); - os::free(cg_path); - os::free(orig); - return this; - } - } - // no lower limit found or limit at leaf - os::free(cg_path); - if (path_iterated) { - reader()->set_subsystem_path((char*)"/"); - limit = read_memory_limit_in_bytes(phys_mem); - if (limit > 0) { - // handle limit set at mount point - log_trace(os, container)("Adjusted v1 controller path for memory to: %s", reader()->subsystem_path()); - os::free(orig); - return this; - } - log_trace(os, container)("No lower limit found in hierarchy %s, adjusting to original path %s", - reader()->mount_point(), orig); - reader()->set_subsystem_path(orig); - } else { - log_trace(os, container)("Lowest limit for memory at leaf: %s", - reader()->subsystem_path()); - } - os::free(orig); - return this; -} - -CgroupV1CpuController* CgroupV1CpuController::adjust_controller(int host_cpus) { - log_trace(os, container)("Adjusting v1 controller path for cpu: %s", reader()->subsystem_path()); - assert(reader()->cgroup_path() != nullptr, "invariant"); - assert(host_cpus > 0, "Negative host cpus?"); - char* orig = os::strdup(reader()->cgroup_path()); - char* cg_path = os::strdup(orig); - char* last_slash; - int cpus = CgroupUtil::processor_count(this, host_cpus); - bool path_iterated = false; - while (cpus == host_cpus && (last_slash = strrchr(cg_path, '/')) != cg_path) { - *last_slash = '\0'; // strip path - // update to shortened path and try again - reader()->set_subsystem_path((char*)cg_path); - cpus = CgroupUtil::processor_count(this, host_cpus); - path_iterated = true; - if (cpus != host_cpus) { - log_trace(os, container)("Adjusted v1 controller path for cpu to: %s", reader()->subsystem_path()); - os::free(cg_path); - os::free(orig); - return this; - } - } - // no lower limit found or limit at leaf - os::free(cg_path); - if (path_iterated) { - reader()->set_subsystem_path((char*)"/"); - cpus = CgroupUtil::processor_count(this, host_cpus); - if (cpus != host_cpus) { - // handle limit set at mount point - log_trace(os, container)("Adjusted v1 controller path for cpu to: %s", reader()->subsystem_path()); - os::free(orig); - return this; - } - log_trace(os, container)("No lower limit found in hierarchy %s, adjusting to original path %s", - reader()->mount_point(), orig); - reader()->set_subsystem_path(orig); - } else { - log_trace(os, container)("Lowest limit for cpu at leaf: %s", - reader()->subsystem_path()); - } - os::free(orig); - return this; -} - bool CgroupV1Controller::needs_hierarchy_adjustment() { assert(_cgroup_path != nullptr, "sanity"); return strcmp(_root, _cgroup_path) != 0; diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index af117c070e715..d43b9ec063095 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -36,7 +36,6 @@ class CgroupV1Controller: public CgroupController { private: /* mountinfo contents */ char* _root; - char* _mount_point; bool _read_only; /* Constructed subsystem directory */ @@ -46,17 +45,17 @@ class CgroupV1Controller: public CgroupController { CgroupV1Controller(char *root, char *mountpoint, bool ro) : _root(os::strdup(root)), - _mount_point(os::strdup(mountpoint)), _read_only(ro), _path(nullptr) { _cgroup_path = nullptr; + _mount_point = os::strdup(mountpoint); } // Shallow copy constructor CgroupV1Controller(const CgroupV1Controller& o) : _root(o._root), - _mount_point(o._mount_point), _read_only(o._read_only), _path(o._path) { _cgroup_path = o._cgroup_path; + _mount_point = o._mount_point; } ~CgroupV1Controller() { // At least one subsystem controller exists with paths to malloc'd path @@ -67,7 +66,6 @@ class CgroupV1Controller: public CgroupController { char* subsystem_path() override { return _path; } bool is_read_only() override { return _read_only; } bool needs_hierarchy_adjustment() override; - char* mount_point() { return _mount_point; } }; class CgroupV1MemoryController final : public CgroupMemoryController { @@ -76,7 +74,7 @@ class CgroupV1MemoryController final : public CgroupMemoryController { CgroupV1Controller _reader; CgroupV1Controller* reader() { return &_reader; } public: - void set_subsystem_path(char *cgroup_path) { + void set_subsystem_path(char *cgroup_path) override { reader()->set_subsystem_path(cgroup_path); } jlong read_memory_limit_in_bytes(julong upper_bound) override; @@ -91,11 +89,15 @@ class CgroupV1MemoryController final : public CgroupMemoryController { jlong kernel_memory_limit_in_bytes(julong host_mem); jlong kernel_memory_max_usage_in_bytes(); void print_version_specific_info(outputStream* st, julong host_mem) override; - bool needs_hierarchy_adjustment() override; - CgroupV1MemoryController* adjust_controller(julong phys_mem) override; + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } bool is_read_only() override { return reader()->is_read_only(); } + char* subsystem_path() override { return reader()->subsystem_path(); } + char* mount_point() override { return reader()->mount_point(); } + char* cgroup_path() override { return reader()->cgroup_path(); } private: jlong read_mem_swappiness(); jlong read_mem_swap(julong host_total_memsw); @@ -116,18 +118,26 @@ class CgroupV1CpuController final : public CgroupCpuController { int cpu_quota() override; int cpu_period() override; int cpu_shares() override; - void set_subsystem_path(char *cgroup_path) { + void set_subsystem_path(char *cgroup_path) override { reader()->set_subsystem_path(cgroup_path); } bool is_read_only() override { return reader()->is_read_only(); } + char* subsystem_path() override { + return reader()->subsystem_path(); + } + char* mount_point() override { + return reader()->mount_point(); + } + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + char* cgroup_path() override { return reader()->cgroup_path(); } public: CgroupV1CpuController(const CgroupV1Controller& reader) : _reader(reader) { } - bool needs_hierarchy_adjustment() override; - CgroupV1CpuController* adjust_controller(int host_cpus) override; }; class CgroupV1Subsystem: public CgroupSubsystem { diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 580f893bdd2ef..a2f4b05b6581d 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -268,101 +268,7 @@ void CgroupV2Controller::set_subsystem_path(char* cgroup_path) { if (_path != nullptr) { os::free(_path); } - _path = construct_path(_mount_path, cgroup_path); -} - -bool CgroupV2MemoryController::needs_hierarchy_adjustment() { - return reader()->needs_hierarchy_adjustment(); -} - -bool CgroupV2CpuController::needs_hierarchy_adjustment() { - return reader()->needs_hierarchy_adjustment(); -} - -CgroupCpuController* CgroupV2CpuController::adjust_controller(int host_cpus) { - log_trace(os, container)("Adjusting v2 controller path for cpu: %s", reader()->subsystem_path()); - assert(reader()->cgroup_path() != nullptr, "invariant"); - assert(host_cpus > 0, "Negative host cpus?"); - char* orig = os::strdup(reader()->cgroup_path()); - char* cg_path = os::strdup(orig); - char* last_slash; - int cpus = CgroupUtil::processor_count(this, host_cpus); - bool path_iterated = false; - while (cpus == host_cpus && (last_slash = strrchr(cg_path, '/')) != cg_path) { - *last_slash = '\0'; // strip path - // update to shortened path and try again - reader()->set_subsystem_path(cg_path); - cpus = CgroupUtil::processor_count(this, host_cpus); - path_iterated = true; - if (cpus != host_cpus) { - log_trace(os, container)("Adjusted v2 controller path for cpu to: %s", reader()->subsystem_path()); - os::free(cg_path); - os::free(orig); - return this; - } - } - os::free(cg_path); - if (path_iterated) { - reader()->set_subsystem_path((char*)"/"); - cpus = CgroupUtil::processor_count(this, host_cpus); - if (cpus != host_cpus) { - // handle limit set at mount point - log_trace(os, container)("Adjusted v2 controller path for cpu to: %s", reader()->subsystem_path()); - os::free(orig); - return this; - } - log_trace(os, container)("No lower limit found in hierarchy %s, adjusting to original path %s", - reader()->mount_point(), orig); - reader()->set_subsystem_path(orig); - } else { - log_trace(os, container)("Lowest limit for cpu at leaf: %s", - reader()->subsystem_path()); - } - os::free(orig); - return this; -} - -CgroupMemoryController* CgroupV2MemoryController::adjust_controller(julong phys_mem) { - log_trace(os, container)("Adjusting v2 controller path for memory: %s", reader()->subsystem_path()); - assert(reader()->cgroup_path() != nullptr, "invariant"); - char* orig = os::strdup(reader()->cgroup_path()); - char* cg_path = os::strdup(orig); - char* last_slash; - jlong limit = read_memory_limit_in_bytes(phys_mem); - bool path_iterated = false; - while (limit < 0 && (last_slash = strrchr(cg_path, '/')) != cg_path) { - *last_slash = '\0'; // strip path - // update to shortened path and try again - reader()->set_subsystem_path(cg_path); - limit = read_memory_limit_in_bytes(phys_mem); - path_iterated = true; - if (limit > 0) { - log_trace(os, container)("Adjusted v2 controller path for memory to: %s", reader()->subsystem_path()); - os::free(cg_path); - os::free(orig); - return this; - } - } - // no lower limit found or limit at leaf - os::free(cg_path); - if (path_iterated) { - reader()->set_subsystem_path((char*)"/"); - limit = read_memory_limit_in_bytes(phys_mem); - if (limit > 0) { - // handle limit set at mount point - log_trace(os, container)("Adjusted v2 controller path for memory to: %s", reader()->subsystem_path()); - os::free(orig); - return this; - } - log_trace(os, container)("No lower limit found in hierarchy %s, adjusting to original path %s", - reader()->mount_point(), orig); - reader()->set_subsystem_path(orig); - } else { - log_trace(os, container)("Lowest limit for memory at leaf: %s", - reader()->subsystem_path()); - } - os::free(orig); - return this; + _path = construct_path(_mount_point, cgroup_path); } // For cgv2 we only need hierarchy walk if the cgroup path isn't '/' (root) diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index a273881847637..257c6a552fc8f 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -30,8 +30,6 @@ class CgroupV2Controller: public CgroupController { private: - /* the mount path of the cgroup v2 hierarchy */ - char *_mount_path; bool _read_only; /* Constructed full path to the subsystem directory */ @@ -41,28 +39,27 @@ class CgroupV2Controller: public CgroupController { public: CgroupV2Controller(char* mount_path, char *cgroup_path, - bool ro) : _mount_path(os::strdup(mount_path)), - _read_only(ro), + bool ro) : _read_only(ro), _path(construct_path(mount_path, cgroup_path)) { _cgroup_path = os::strdup(cgroup_path); + _mount_point = os::strdup(mount_path); } // Shallow copy constructor CgroupV2Controller(const CgroupV2Controller& o) : - _mount_path(o._mount_path), _read_only(o._read_only), _path(o._path) { _cgroup_path = o._cgroup_path; + _mount_point = o._mount_point; } ~CgroupV2Controller() { // At least one controller exists with references to the paths } - char *subsystem_path() override { return _path; } + char* subsystem_path() override { return _path; } bool needs_hierarchy_adjustment() override; // Allow for optional updates of the subsystem path void set_subsystem_path(char* cgroup_path); bool is_read_only() override { return _read_only; } - char * mount_point() { return _mount_path; }; }; class CgroupV2CpuController: public CgroupCpuController { @@ -78,8 +75,17 @@ class CgroupV2CpuController: public CgroupCpuController { bool is_read_only() override { return reader()->is_read_only(); } - bool needs_hierarchy_adjustment() override; - CgroupCpuController* adjust_controller(int host_cpus) override; + char* subsystem_path() { + return reader()->subsystem_path(); + } + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + void set_subsystem_path(char* cgroup_path) { + reader()->set_subsystem_path(cgroup_path); + } + char* mount_point() { return reader()->mount_point(); } + char* cgroup_path() override { return reader()->cgroup_path(); } }; class CgroupV2MemoryController final: public CgroupMemoryController { @@ -99,11 +105,20 @@ class CgroupV2MemoryController final: public CgroupMemoryController { jlong rss_usage_in_bytes() override; jlong cache_usage_in_bytes() override; void print_version_specific_info(outputStream* st, julong host_mem) override; - bool needs_hierarchy_adjustment() override; - CgroupMemoryController* adjust_controller(julong phys_mem) override; bool is_read_only() override { return reader()->is_read_only(); } + char* subsystem_path() { + return reader()->subsystem_path(); + } + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + void set_subsystem_path(char* cgroup_path) { + reader()->set_subsystem_path(cgroup_path); + } + char* mount_point() { return reader()->mount_point(); } + char* cgroup_path() override { return reader()->cgroup_path(); } }; class CgroupV2Subsystem: public CgroupSubsystem {