8299858: [Metrics] Swap memory limit reported incorrectly when too large

Reviewed-by: stuefe
This commit is contained in:
Severin Gehwolf 2023-01-26 14:50:46 +00:00
parent 28545dcf2b
commit 64ddf9536f
3 changed files with 67 additions and 3 deletions

View file

@ -122,9 +122,11 @@ public class CgroupMetrics implements Metrics {
@Override @Override
public long getMemoryLimit() { public long getMemoryLimit() {
long subsMem = subsystem.getMemoryLimit(); long subsMem = subsystem.getMemoryLimit();
long systemTotal = getTotalMemorySize0();
assert(systemTotal > 0);
// Catch the cgroup memory limit exceeding host physical memory. // Catch the cgroup memory limit exceeding host physical memory.
// Treat this as unlimited. // Treat this as unlimited.
if (subsMem >= getTotalMemorySize0()) { if (subsMem >= systemTotal) {
return CgroupSubsystem.LONG_RETVAL_UNLIMITED; return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
} }
return subsMem; return subsMem;
@ -142,7 +144,15 @@ public class CgroupMetrics implements Metrics {
@Override @Override
public long getMemoryAndSwapLimit() { public long getMemoryAndSwapLimit() {
return subsystem.getMemoryAndSwapLimit(); long totalSystemMemSwap = getTotalMemorySize0() + getTotalSwapSize0();
assert(totalSystemMemSwap > 0);
// Catch the cgroup memory and swap limit exceeding host physical swap
// and memory. Treat this case as unlimited.
long subsSwapMem = subsystem.getMemoryAndSwapLimit();
if (subsSwapMem >= totalSystemMemSwap) {
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
}
return subsSwapMem;
} }
@Override @Override
@ -185,5 +195,6 @@ public class CgroupMetrics implements Metrics {
private static native boolean isUseContainerSupport(); private static native boolean isUseContainerSupport();
private static native long getTotalMemorySize0(); private static native long getTotalMemorySize0();
private static native long getTotalSwapSize0();
} }

View file

@ -23,6 +23,7 @@
* questions. * questions.
*/ */
#include <unistd.h> #include <unistd.h>
#include <sys/sysinfo.h>
#include "jni.h" #include "jni.h"
#include "jvm.h" #include "jvm.h"
@ -43,3 +44,15 @@ Java_jdk_internal_platform_CgroupMetrics_getTotalMemorySize0
jlong page_size = sysconf(_SC_PAGESIZE); jlong page_size = sysconf(_SC_PAGESIZE);
return pages * page_size; return pages * page_size;
} }
JNIEXPORT jlong JNICALL
Java_jdk_internal_platform_CgroupMetrics_getTotalSwapSize0
(JNIEnv *env, jclass ignored)
{
struct sysinfo si;
int retval = sysinfo(&si);
if (retval < 0) {
return 0; // syinfo failed, treat as no swap
}
return (jlong)si.totalswap;
}

View file

@ -37,6 +37,7 @@
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox
* @run main/othervm -Xbootclasspath/a:whitebox.jar -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestMemoryAwareness * @run main/othervm -Xbootclasspath/a:whitebox.jar -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestMemoryAwareness
*/ */
import java.util.function.Consumer;
import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.Common;
import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerRunOptions;
import jdk.test.lib.containers.docker.DockerTestUtils; import jdk.test.lib.containers.docker.DockerTestUtils;
@ -96,7 +97,9 @@ public class TestMemoryAwareness {
true /* additional cgroup fs mounts */ true /* additional cgroup fs mounts */
); );
testOSMXBeanIgnoresMemLimitExceedingPhysicalMemory(); testOSMXBeanIgnoresMemLimitExceedingPhysicalMemory();
testOSMXBeanIgnoresSwapLimitExceedingPhysical();
testMetricsExceedingPhysicalMemory(); testMetricsExceedingPhysicalMemory();
testMetricsSwapExceedingPhysical();
testContainerMemExceedsPhysical(); testContainerMemExceedsPhysical();
} finally { } finally {
if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) {
@ -183,6 +186,13 @@ public class TestMemoryAwareness {
private static void testOperatingSystemMXBeanAwareness(String memoryAllocation, String expectedMemory, private static void testOperatingSystemMXBeanAwareness(String memoryAllocation, String expectedMemory,
String swapAllocation, String expectedSwap, boolean addCgroupMounts) throws Exception { String swapAllocation, String expectedSwap, boolean addCgroupMounts) throws Exception {
Consumer<OutputAnalyzer> noOp = o -> {};
testOperatingSystemMXBeanAwareness(memoryAllocation, expectedMemory, swapAllocation, expectedSwap, false, noOp);
}
private static void testOperatingSystemMXBeanAwareness(String memoryAllocation, String expectedMemory,
String swapAllocation, String expectedSwap, boolean addCgroupMounts,
Consumer<OutputAnalyzer> additionalMatch) throws Exception {
Common.logNewTestCase("Check OperatingSystemMXBean"); Common.logNewTestCase("Check OperatingSystemMXBean");
@ -191,6 +201,7 @@ public class TestMemoryAwareness {
"--memory", memoryAllocation, "--memory", memoryAllocation,
"--memory-swap", swapAllocation "--memory-swap", swapAllocation
) )
.addJavaOpts("-esa")
// CheckOperatingSystemMXBean uses Metrics (jdk.internal.platform) for // CheckOperatingSystemMXBean uses Metrics (jdk.internal.platform) for
// diagnostics // diagnostics
.addJavaOpts("--add-exports") .addJavaOpts("--add-exports")
@ -228,9 +239,9 @@ public class TestMemoryAwareness {
} catch(RuntimeException ex) { } catch(RuntimeException ex) {
out.shouldMatch("OperatingSystemMXBean\\.getFreeSwapSpaceSize: 0"); out.shouldMatch("OperatingSystemMXBean\\.getFreeSwapSpaceSize: 0");
} }
additionalMatch.accept(out);
} }
// JDK-8292541: Ensure OperatingSystemMXBean ignores container memory limits above the host's physical memory. // JDK-8292541: Ensure OperatingSystemMXBean ignores container memory limits above the host's physical memory.
private static void testOSMXBeanIgnoresMemLimitExceedingPhysicalMemory() private static void testOSMXBeanIgnoresMemLimitExceedingPhysicalMemory()
throws Exception { throws Exception {
@ -239,6 +250,35 @@ public class TestMemoryAwareness {
testOperatingSystemMXBeanAwareness(badMem, hostMaxMem, badMem, hostMaxMem); testOperatingSystemMXBeanAwareness(badMem, hostMaxMem, badMem, hostMaxMem);
} }
private static void testOSMXBeanIgnoresSwapLimitExceedingPhysical()
throws Exception {
long totalSwap = wb.hostPhysicalSwap() + wb.hostPhysicalMemory();
String expectedSwap = Long.valueOf(totalSwap).toString();
String hostMaxMem = getHostMaxMemory();
String badMem = hostMaxMem + "0";
final String badSwap = expectedSwap + "0";
testOperatingSystemMXBeanAwareness(badMem, hostMaxMem, badSwap, expectedSwap, false, o -> {
o.shouldNotContain("Metrics.getMemoryAndSwapLimit() == " + badSwap);
});
}
private static void testMetricsSwapExceedingPhysical()
throws Exception {
Common.logNewTestCase("Metrics ignore container swap memory limit exceeding physical");
long totalSwap = wb.hostPhysicalSwap() + wb.hostPhysicalMemory();
String expectedSwap = Long.valueOf(totalSwap).toString();
final String badSwap = expectedSwap + "0";
String badMem = getHostMaxMemory() + "0";
DockerRunOptions opts = Common.newOpts(imageName)
.addJavaOpts("-XshowSettings:system")
.addDockerOpts("--memory", badMem)
.addDockerOpts("--memory-swap", badSwap);
OutputAnalyzer out = DockerTestUtils.dockerRunJava(opts);
out.shouldContain("Memory Limit: Unlimited");
out.shouldContain("Memory & Swap Limit: Unlimited");
}
// JDK-8292541: Ensure Metrics ignores container memory limits above the host's physical memory. // JDK-8292541: Ensure Metrics ignores container memory limits above the host's physical memory.
private static void testMetricsExceedingPhysicalMemory() private static void testMetricsExceedingPhysicalMemory()
throws Exception { throws Exception {