diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index ceb20ededdb..038593a2bc4 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -159,8 +159,10 @@ template int subsystem_file_line_contents(CgroupController* c, } PRAGMA_DIAG_POP +// log_fmt can be different than scan_fmt. For example +// cpu_period() for cgv2 uses log_fmt='%d' and scan_fmt='%*s %d' #define GET_CONTAINER_INFO(return_type, subsystem, filename, \ - logstring, scan_fmt, variable) \ + logstring, log_fmt, scan_fmt, variable) \ return_type variable; \ { \ int err; \ @@ -170,11 +172,11 @@ PRAGMA_DIAG_POP scan_fmt, \ &variable); \ if (err != 0) { \ - log_trace(os, container)(logstring, (return_type) OSCONTAINER_ERROR); \ + log_trace(os, container)(logstring "%d", OSCONTAINER_ERROR); \ return (return_type) OSCONTAINER_ERROR; \ } \ \ - log_trace(os, container)(logstring, variable); \ + log_trace(os, container)(logstring log_fmt, variable); \ } #define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \ diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 4ff77f47223..fe83650ca91 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -76,7 +76,7 @@ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { */ jlong CgroupV1MemoryController::uses_mem_hierarchy() { GET_CONTAINER_INFO(jlong, this, "/memory.use_hierarchy", - "Use Hierarchy is: " JLONG_FORMAT, JLONG_FORMAT, use_hierarchy); + "Use Hierarchy is: ", JLONG_FORMAT, JLONG_FORMAT, use_hierarchy); return use_hierarchy; } @@ -90,7 +90,7 @@ void CgroupV1MemoryController::set_subsystem_path(char *cgroup_path) { jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.limit_in_bytes", - "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit); + "Memory Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memlimit); if (memlimit >= os::Linux::physical_memory()) { log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited"); @@ -114,7 +114,7 @@ jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() { julong host_total_memsw; GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.memsw.limit_in_bytes", - "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit); + "Memory and Swap Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memswlimit); host_total_memsw = os::Linux::host_swap() + os::Linux::physical_memory(); if (memswlimit >= host_total_memsw) { log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited"); @@ -151,13 +151,13 @@ jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() { jlong CgroupV1Subsystem::read_mem_swappiness() { GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.swappiness", - "Swappiness is: " JULONG_FORMAT, JULONG_FORMAT, swappiness); + "Swappiness is: ", JULONG_FORMAT, JULONG_FORMAT, swappiness); return swappiness; } jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.soft_limit_in_bytes", - "Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit); + "Memory Soft Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memsoftlimit); if (memsoftlimit >= os::Linux::physical_memory()) { log_trace(os, container)("Memory Soft Limit is: Unlimited"); return (jlong)-1; @@ -177,7 +177,7 @@ jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { */ jlong CgroupV1Subsystem::memory_usage_in_bytes() { GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.usage_in_bytes", - "Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memusage); + "Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, memusage); return memusage; } @@ -191,20 +191,20 @@ jlong CgroupV1Subsystem::memory_usage_in_bytes() { */ jlong CgroupV1Subsystem::memory_max_usage_in_bytes() { GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.max_usage_in_bytes", - "Maximum Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memmaxusage); + "Maximum Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, memmaxusage); return memmaxusage; } jlong CgroupV1Subsystem::kernel_memory_usage_in_bytes() { GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.kmem.usage_in_bytes", - "Kernel Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, kmem_usage); + "Kernel Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, kmem_usage); return kmem_usage; } jlong CgroupV1Subsystem::kernel_memory_limit_in_bytes() { GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.kmem.limit_in_bytes", - "Kernel Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, kmem_limit); + "Kernel Memory Limit is: ", JULONG_FORMAT, JULONG_FORMAT, kmem_limit); if (kmem_limit >= os::Linux::physical_memory()) { return (jlong)-1; } @@ -213,7 +213,7 @@ jlong CgroupV1Subsystem::kernel_memory_limit_in_bytes() { jlong CgroupV1Subsystem::kernel_memory_max_usage_in_bytes() { GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.kmem.max_usage_in_bytes", - "Maximum Kernel Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, kmem_max_usage); + "Maximum Kernel Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, kmem_max_usage); return kmem_max_usage; } @@ -251,13 +251,13 @@ char * CgroupV1Subsystem::cpu_cpuset_memory_nodes() { */ int CgroupV1Subsystem::cpu_quota() { GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.cfs_quota_us", - "CPU Quota is: %d", "%d", quota); + "CPU Quota is: ", "%d", "%d", quota); return quota; } int CgroupV1Subsystem::cpu_period() { GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.cfs_period_us", - "CPU Period is: %d", "%d", period); + "CPU Period is: ", "%d", "%d", period); return period; } @@ -273,7 +273,7 @@ int CgroupV1Subsystem::cpu_period() { */ int CgroupV1Subsystem::cpu_shares() { GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.shares", - "CPU Shares is: %d", "%d", shares); + "CPU Shares is: ", "%d", "%d", shares); // Convert 1024 to no shares setup if (shares == 1024) return -1; @@ -313,6 +313,6 @@ jlong CgroupV1Subsystem::pids_max() { jlong CgroupV1Subsystem::pids_current() { if (_pids == nullptr) return OSCONTAINER_ERROR; GET_CONTAINER_INFO(jlong, _pids, "/pids.current", - "Current number of tasks is: " JLONG_FORMAT, JLONG_FORMAT, pids_current); + "Current number of tasks is: ", JLONG_FORMAT, JLONG_FORMAT, pids_current); return pids_current; } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 190b12438f6..59a95ee851f 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -36,7 +36,7 @@ */ int CgroupV2Subsystem::cpu_shares() { GET_CONTAINER_INFO(int, _unified, "/cpu.weight", - "Raw value for CPU Shares is: %d", "%d", shares); + "Raw value for CPU Shares is: ", "%d", "%d", shares); // Convert default value of 100 to no shares setup if (shares == 100) { log_debug(os, container)("CPU Shares is: %d", -1); @@ -109,7 +109,7 @@ char * CgroupV2Subsystem::cpu_cpuset_memory_nodes() { int CgroupV2Subsystem::cpu_period() { GET_CONTAINER_INFO(int, _unified, "/cpu.max", - "CPU Period is: %d", "%*s %d", period); + "CPU Period is: ", "%d", "%*s %d", period); return period; } @@ -124,7 +124,7 @@ int CgroupV2Subsystem::cpu_period() { */ jlong CgroupV2Subsystem::memory_usage_in_bytes() { GET_CONTAINER_INFO(jlong, _unified, "/memory.current", - "Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memusage); + "Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, memusage); return memusage; } @@ -158,6 +158,7 @@ jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() { assert(memory_limit >= 0, "swap limit without memory limit?"); return memory_limit + swap_limit; } + log_trace(os, container)("Memory and Swap Limit is: " JLONG_FORMAT, swap_limit); return swap_limit; } @@ -251,6 +252,6 @@ jlong CgroupV2Subsystem::pids_max() { */ jlong CgroupV2Subsystem::pids_current() { GET_CONTAINER_INFO(jlong, _unified, "/pids.current", - "Current number of tasks is: " JLONG_FORMAT, JLONG_FORMAT, pids_current); + "Current number of tasks is: ", JLONG_FORMAT, JLONG_FORMAT, pids_current); return pids_current; } diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 6b817d7255c..f6826a17ead 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -75,6 +75,7 @@ public class TestMemoryAwareness { testMemorySoftLimit("500m", "524288000"); testMemorySoftLimit("1g", "1073741824"); + testMemorySwapLimitSanity(); // Add extra 10 Mb to allocator limit, to be sure to cause OOM testOOM("256m", 256 + 10); @@ -153,6 +154,31 @@ public class TestMemoryAwareness { .shouldMatch("Memory Soft Limit.*" + expectedTraceValue); } + /* + * This test verifies that no confusingly large positive numbers get printed on + * systems with swapaccount=0 kernel option. On some systems -2 were converted + * to unsigned long and printed that way. Ensure this oddity doesn't occur. + */ + private static void testMemorySwapLimitSanity() throws Exception { + String valueToSet = "500m"; + String expectedTraceValue = "524288000"; + Common.logNewTestCase("memory swap sanity: " + valueToSet); + + DockerRunOptions opts = Common.newOpts(imageName, "PrintContainerInfo"); + Common.addWhiteBoxOpts(opts); + opts.addDockerOpts("--memory=" + valueToSet); + opts.addDockerOpts("--memory-swap=" + valueToSet); + + String neg2InUnsignedLong = "18446744073709551614"; + + Common.run(opts) + .shouldMatch("Memory Limit is:.*" + expectedTraceValue) + // Either for cgroup v1: a_1) same as memory limit, or b_1) -2 on systems with swapaccount=0 + // Either for cgroup v2: a_2) 0, or b_2) -2 on systems with swapaccount=0 + .shouldMatch("Memory and Swap Limit is:.*(" + expectedTraceValue + "|-2|0)") + .shouldNotMatch("Memory and Swap Limit is:.*" + neg2InUnsignedLong); + } + // provoke OOM inside the container, see how VM reacts private static void testOOM(String dockerMemLimit, int sizeToAllocInMb) throws Exception { diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java index aa3a902b30b..9307771d086 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java @@ -83,7 +83,7 @@ public class TestMemoryWithCgroupV1 { OutputAnalyzer out = Common.run(opts); // in case of warnings like : "Your kernel does not support swap limit // capabilities or the cgroup is not mounted. Memory limited without swap." - // we only have Memory and Swap Limit is: in the output + // we only have 'Memory and Swap Limit is: -2' in the output try { if (out.getOutput().contains("memory_and_swap_limit_in_bytes: not supported")) { System.out.println("memory_and_swap_limit_in_bytes not supported, avoiding Memory and Swap Limit check");