From 2dd7a20bb39d31b819fab85673cd3b3ed5194e82 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Fri, 13 Mar 2026 09:30:49 +0000 Subject: [PATCH] 8369503: [Linux] Move machine-specific queries to the OSContainer layer Reviewed-by: sgehwolf, phubner --- .../os/linux/cgroupSubsystem_linux.cpp | 10 ++++-- .../os/linux/cgroupSubsystem_linux.hpp | 4 ++- src/hotspot/os/linux/cgroupUtil_linux.cpp | 33 +++++++++---------- src/hotspot/os/linux/cgroupUtil_linux.hpp | 4 +-- .../os/linux/cgroupV1Subsystem_linux.cpp | 2 -- .../os/linux/cgroupV2Subsystem_linux.cpp | 2 -- src/hotspot/os/linux/osContainer_linux.cpp | 7 +++- .../runtime/test_cgroupSubsystem_linux.cpp | 8 ++--- 8 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index e49d070890e..13a005591fb 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -28,7 +28,6 @@ #include "cgroupV2Subsystem_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" -#include "os_linux.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" @@ -605,6 +604,11 @@ void CgroupSubsystemFactory::cleanup(CgroupInfo* cg_infos) { } } +void CgroupSubsystem::adjust_controllers(physical_memory_size_type upper_mem_bound, int upper_cpu_bound) { + CgroupUtil::adjust_controller(memory_controller()->controller(), upper_mem_bound); + CgroupUtil::adjust_controller(cpu_controller()->controller(), upper_cpu_bound); +} + /* active_processor_count * * Calculate an appropriate number of active processors for the @@ -631,7 +635,7 @@ void CgroupSubsystemFactory::cleanup(CgroupInfo* cg_infos) { * return: * true if there were no errors. false otherwise. */ -bool CgroupSubsystem::active_processor_count(double& value) { +bool CgroupSubsystem::active_processor_count(int (*cpu_bound_func)(), double& value) { // We use a cache with a timeout to avoid performing expensive // computations in the event this function is called frequently. // [See 8227006]. @@ -643,7 +647,7 @@ bool CgroupSubsystem::active_processor_count(double& value) { return true; } - int cpu_count = os::Linux::active_processor_count(); + int cpu_count = cpu_bound_func(); double result = -1; if (!CgroupUtil::processor_count(contrl->controller(), cpu_count, result)) { return false; diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index d083a9985c2..adde37e1c77 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -278,7 +278,7 @@ class CgroupMemoryController: public CHeapObj { class CgroupSubsystem: public CHeapObj { public: bool memory_limit_in_bytes(physical_memory_size_type upper_bound, physical_memory_size_type& value); - bool active_processor_count(double& value); + bool active_processor_count(int (*cpu_bound_func)(), double& value); virtual bool pids_max(uint64_t& value) = 0; virtual bool pids_current(uint64_t& value) = 0; @@ -291,6 +291,8 @@ class CgroupSubsystem: public CHeapObj { virtual CachingCgroupController* cpu_controller() = 0; virtual CgroupCpuacctController* cpuacct_controller() = 0; + void adjust_controllers(physical_memory_size_type upper_mem_bound, int upper_cpu_bound); + bool cpu_quota(int& value); bool cpu_period(int& value); bool cpu_shares(int& value); diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index 570b335940b..f166f6cd5e4 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -24,7 +24,6 @@ */ #include "cgroupUtil_linux.hpp" -#include "os_linux.hpp" bool CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int upper_bound, double& value) { assert(upper_bound > 0, "upper bound of cpus must be positive"); @@ -82,7 +81,7 @@ double CgroupUtil::get_updated_cpu_limit(CgroupCpuController* cpu, return lowest; } -void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { +void CgroupUtil::adjust_controller(CgroupMemoryController* mem, physical_memory_size_type upper_bound) { assert(mem->cgroup_path() != nullptr, "invariant"); if (strstr(mem->cgroup_path(), "../") != nullptr) { log_warning(os, container)("Cgroup memory controller path at '%s' seems to have moved " @@ -100,17 +99,16 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { char* cg_path = os::strdup(orig); char* last_slash; assert(cg_path[0] == '/', "cgroup path must start with '/'"); - physical_memory_size_type phys_mem = os::Linux::physical_memory(); char* limit_cg_path = nullptr; physical_memory_size_type limit = value_unlimited; - physical_memory_size_type lowest_limit = phys_mem; - lowest_limit = get_updated_mem_limit(mem, lowest_limit, phys_mem); - physical_memory_size_type orig_limit = lowest_limit != phys_mem ? lowest_limit : phys_mem; + physical_memory_size_type lowest_limit = upper_bound; + lowest_limit = get_updated_mem_limit(mem, lowest_limit, upper_bound); + physical_memory_size_type orig_limit = lowest_limit != upper_bound ? lowest_limit : upper_bound; while ((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 = get_updated_mem_limit(mem, lowest_limit, phys_mem); + limit = get_updated_mem_limit(mem, lowest_limit, upper_bound); if (limit < lowest_limit) { lowest_limit = limit; os::free(limit_cg_path); // handles nullptr @@ -119,13 +117,13 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { } // need to check limit at mount point mem->set_subsystem_path("/"); - limit = get_updated_mem_limit(mem, lowest_limit, phys_mem); + limit = get_updated_mem_limit(mem, lowest_limit, upper_bound); if (limit < lowest_limit) { lowest_limit = limit; os::free(limit_cg_path); // handles nullptr limit_cg_path = os::strdup("/"); } - assert(lowest_limit <= phys_mem, "limit must not exceed host memory"); + assert(lowest_limit <= upper_bound, "limit must not exceed upper bound"); if (lowest_limit != orig_limit) { // we've found a lower limit anywhere in the hierarchy, // set the path to the limit path @@ -147,7 +145,7 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { os::free(limit_cg_path); } -void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { +void CgroupUtil::adjust_controller(CgroupCpuController* cpu, int upper_bound) { assert(cpu->cgroup_path() != nullptr, "invariant"); if (strstr(cpu->cgroup_path(), "../") != nullptr) { log_warning(os, container)("Cgroup cpu controller path at '%s' seems to have moved " @@ -165,17 +163,16 @@ void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { char* cg_path = os::strdup(orig); char* last_slash; assert(cg_path[0] == '/', "cgroup path must start with '/'"); - int host_cpus = os::Linux::active_processor_count(); - int lowest_limit = host_cpus; - double cpus = get_updated_cpu_limit(cpu, lowest_limit, host_cpus); - int orig_limit = lowest_limit != host_cpus ? lowest_limit : host_cpus; + int lowest_limit = upper_bound; + double cpus = get_updated_cpu_limit(cpu, lowest_limit, upper_bound); + int orig_limit = lowest_limit != upper_bound ? lowest_limit : upper_bound; char* limit_cg_path = nullptr; while ((last_slash = strrchr(cg_path, '/')) != cg_path) { *last_slash = '\0'; // strip path // update to shortened path and try again cpu->set_subsystem_path(cg_path); - cpus = get_updated_cpu_limit(cpu, lowest_limit, host_cpus); - if (cpus != host_cpus && cpus < lowest_limit) { + cpus = get_updated_cpu_limit(cpu, lowest_limit, upper_bound); + if (cpus != upper_bound && cpus < lowest_limit) { lowest_limit = cpus; os::free(limit_cg_path); // handles nullptr limit_cg_path = os::strdup(cg_path); @@ -183,8 +180,8 @@ void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { } // need to check limit at mount point cpu->set_subsystem_path("/"); - cpus = get_updated_cpu_limit(cpu, lowest_limit, host_cpus); - if (cpus != host_cpus && cpus < lowest_limit) { + cpus = get_updated_cpu_limit(cpu, lowest_limit, upper_bound); + if (cpus != upper_bound && cpus < lowest_limit) { lowest_limit = cpus; os::free(limit_cg_path); // handles nullptr limit_cg_path = os::strdup(cg_path); diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp index 1fd2a7d872b..68585c22c2d 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.hpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp @@ -35,10 +35,10 @@ class CgroupUtil: AllStatic { static bool processor_count(CgroupCpuController* cpu, int upper_bound, double& value); // Given a memory controller, adjust its path to a point in the hierarchy // that represents the closest memory limit. - static void adjust_controller(CgroupMemoryController* m); + static void adjust_controller(CgroupMemoryController* m, physical_memory_size_type upper_bound); // Given a cpu controller, adjust its path to a point in the hierarchy // that represents the closest cpu limit. - static void adjust_controller(CgroupCpuController* c); + static void adjust_controller(CgroupCpuController* c, int upper_bound); private: static physical_memory_size_type get_updated_mem_limit(CgroupMemoryController* m, physical_memory_size_type lowest, diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index c8f5a290c99..e42b7a13391 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -326,8 +326,6 @@ CgroupV1Subsystem::CgroupV1Subsystem(CgroupV1Controller* cpuset, _cpuset(cpuset), _cpuacct(cpuacct), _pids(pids) { - CgroupUtil::adjust_controller(memory); - CgroupUtil::adjust_controller(cpu); _memory = new CachingCgroupController(memory); _cpu = new CachingCgroupController(cpu); } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 30e1affc646..edd80bb7427 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -154,8 +154,6 @@ CgroupV2Subsystem::CgroupV2Subsystem(CgroupV2MemoryController * memory, CgroupV2CpuacctController* cpuacct, CgroupV2Controller unified) : _unified(unified) { - CgroupUtil::adjust_controller(memory); - CgroupUtil::adjust_controller(cpu); _memory = new CachingCgroupController(memory); _cpu = new CachingCgroupController(cpu); _cpuacct = cpuacct; diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index b46263efd99..da2cbf381e6 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -59,6 +59,11 @@ void OSContainer::init() { if (cgroup_subsystem == nullptr) { return; // Required subsystem files not found or other error } + // Adjust controller paths once subsystem is initialized + physical_memory_size_type phys_mem = os::Linux::physical_memory(); + int host_cpus = os::Linux::active_processor_count(); + cgroup_subsystem->adjust_controllers(phys_mem, host_cpus); + /* * In order to avoid a false positive on is_containerized() on * Linux systems outside a container *and* to ensure compatibility @@ -252,7 +257,7 @@ char * OSContainer::cpu_cpuset_memory_nodes() { bool OSContainer::active_processor_count(double& value) { assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); - return cgroup_subsystem->active_processor_count(value); + return cgroup_subsystem->active_processor_count(&os::Linux::active_processor_count, value); } bool OSContainer::cpu_quota(int& value) { diff --git a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp index 7a4f7bcb99e..69d04ae8883 100644 --- a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp +++ b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp @@ -479,7 +479,7 @@ TEST(cgroupTest, set_cgroupv1_subsystem_path_adjusted) { ccc->set_subsystem_path((char*)cpu.cgroup_path); EXPECT_TRUE(ccc->needs_hierarchy_adjustment()); - CgroupUtil::adjust_controller(ccc); + CgroupUtil::adjust_controller(ccc, 1); ASSERT_STREQ(cpu.expected_path, ccc->subsystem_path()); EXPECT_FALSE(ccc->needs_hierarchy_adjustment()); @@ -489,7 +489,7 @@ TEST(cgroupTest, set_cgroupv1_subsystem_path_adjusted) { cmc->set_subsystem_path((char*)memory.cgroup_path); EXPECT_TRUE(cmc->needs_hierarchy_adjustment()); - CgroupUtil::adjust_controller(cmc); + CgroupUtil::adjust_controller(cmc, (physical_memory_size_type)1024); ASSERT_STREQ(memory.expected_path, cmc->subsystem_path()); EXPECT_FALSE(cmc->needs_hierarchy_adjustment()); } @@ -512,7 +512,7 @@ TEST(cgroupTest, set_cgroupv2_subsystem_path_adjusted) { true /* read-only mount */)); EXPECT_TRUE(ccc->needs_hierarchy_adjustment()); - CgroupUtil::adjust_controller(ccc); + CgroupUtil::adjust_controller(ccc, 1); ASSERT_STREQ(cpu.expected_path, ccc->subsystem_path()); EXPECT_FALSE(ccc->needs_hierarchy_adjustment()); @@ -521,7 +521,7 @@ TEST(cgroupTest, set_cgroupv2_subsystem_path_adjusted) { true /* read-only mount */)); EXPECT_TRUE(cmc->needs_hierarchy_adjustment()); - CgroupUtil::adjust_controller(cmc); + CgroupUtil::adjust_controller(cmc, (physical_memory_size_type)1024); ASSERT_STREQ(memory.expected_path, cmc->subsystem_path()); EXPECT_FALSE(cmc->needs_hierarchy_adjustment()); }