8250984: Memory Docker tests fail on some Linux kernels w/o cgroupv1 …

Reviewed-by: bobv, sgehwolf
This commit is contained in:
Harold Seigel 2020-09-25 17:16:38 +00:00
parent a75edc29c6
commit 0187567704
8 changed files with 103 additions and 58 deletions

View File

@ -28,6 +28,7 @@ package jdk.internal.platform.cgroupv1;
public class CgroupV1MemorySubSystemController extends CgroupV1SubsystemController {
private boolean hierarchical;
private boolean swapenabled;
public CgroupV1MemorySubSystemController(String root, String mountPoint) {
super(root, mountPoint);
@ -41,4 +42,11 @@ public class CgroupV1MemorySubSystemController extends CgroupV1SubsystemControll
this.hierarchical = hierarchical;
}
}
boolean isSwapEnabled() {
return swapenabled;
}
void setSwapEnabled(boolean swapenabled) {
this.swapenabled = swapenabled;
}
}

View File

@ -199,6 +199,8 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
CgroupV1MemorySubSystemController memorySubSystem = (CgroupV1MemorySubSystemController)controller;
boolean isHierarchial = getHierarchical(memorySubSystem);
memorySubSystem.setHierarchical(isHierarchial);
boolean isSwapEnabled = getSwapEnabled(memorySubSystem);
memorySubSystem.setSwapEnabled(isSwapEnabled);
}
subsystem.setActiveSubSystems();
}
@ -208,6 +210,12 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
}
private static boolean getSwapEnabled(CgroupV1MemorySubSystemController controller) {
long retval = getLongValue(controller, "memory.memsw.limit_in_bytes");
return retval > 0;
}
private static boolean getHierarchical(CgroupV1MemorySubSystemController controller) {
long hierarchical = getLongValue(controller, "memory.use_hierarchy");
return hierarchical > 0;
@ -438,10 +446,16 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
}
public long getMemoryAndSwapFailCount() {
if (!memory.isSwapEnabled()) {
return getMemoryFailCount();
}
return getLongValue(memory, "memory.memsw.failcnt");
}
public long getMemoryAndSwapLimit() {
if (!memory.isSwapEnabled()) {
return getMemoryLimit();
}
long retval = getLongValue(memory, "memory.memsw.limit_in_bytes");
if (retval > CgroupV1SubsystemController.UNLIMITED_MIN) {
if (memory.isHierarchical()) {
@ -457,10 +471,16 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
}
public long getMemoryAndSwapMaxUsage() {
if (!memory.isSwapEnabled()) {
return getMemoryMaxUsage();
}
return getLongValue(memory, "memory.memsw.max_usage_in_bytes");
}
public long getMemoryAndSwapUsage() {
if (!memory.isSwapEnabled()) {
return getMemoryUsage();
}
return getLongValue(memory, "memory.memsw.usage_in_bytes");
}

View File

@ -86,7 +86,6 @@ runtime/cds/DeterministicDump.java 8253495 generic-all
runtime/cds/serviceability/ReplaceCriticalClassesForSubgraphs.java 8253081 generic-all
runtime/jni/terminatedThread/TestTerminatedThread.java 8219652 aix-ppc64
runtime/ReservedStack/ReservedStackTest.java 8231031 generic-all
containers/docker/TestMemoryAwareness.java 8250984 linux-5.4.0-1019-oracle
#############################################################################

View File

@ -45,7 +45,7 @@ public class PlainRead {
oa.shouldNotMatch("^.*" + what + " *" + value + ".*$");
}
static final String good_value = "(\\d+|-1|Unlimited)";
static final String good_value = "(\\d+|-1|-2|Unlimited)";
static final String bad_value = "(failed)";
static final String[] variables = {"Memory Limit is:", "CPU Shares is:", "CPU Quota is:", "CPU Period is:", "active_processor_count:"};

View File

@ -153,18 +153,24 @@ public class TestMemoryAwareness {
out.shouldHaveExitValue(0)
.shouldContain("Checking OperatingSystemMXBean")
.shouldContain("OperatingSystemMXBean.getTotalPhysicalMemorySize: " + expectedMemory)
.shouldMatch("OperatingSystemMXBean\\.getFreePhysicalMemorySize: [1-9][0-9]+")
.shouldContain("OperatingSystemMXBean.getTotalMemorySize: " + expectedMemory)
.shouldMatch("OperatingSystemMXBean\\.getFreeMemorySize: [1-9][0-9]+")
.shouldMatch("OperatingSystemMXBean\\.getFreeSwapSpaceSize: [1-9][0-9]+");
// in case of warnings like : "Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap."
// the getTotalSwapSpaceSize returns the system values as the container setup isn't supported in that case.
.shouldMatch("OperatingSystemMXBean\\.getFreePhysicalMemorySize: [1-9][0-9]+");
// in case of warnings like : "Your kernel does not support swap limit capabilities
// or the cgroup is not mounted. Memory limited without swap."
// the getTotalSwapSpaceSize and getFreeSwapSpaceSize return the system
// values as the container setup isn't supported in that case.
try {
out.shouldContain("OperatingSystemMXBean.getTotalSwapSpaceSize: " + expectedSwap);
} catch(RuntimeException ex) {
out.shouldMatch("OperatingSystemMXBean.getTotalSwapSpaceSize: [1-9][0-9]+");
out.shouldContain("Metrics.getMemoryLimit() == " + expectedMemory);
out.shouldContain("Metrics.getMemoryAndSwapLimit() == -1");
out.shouldMatch("OperatingSystemMXBean.getTotalSwapSpaceSize: [0-9]+");
}
try {
out.shouldMatch("OperatingSystemMXBean\\.getFreeSwapSpaceSize: [1-9][0-9]+");
} catch(RuntimeException ex) {
out.shouldMatch("OperatingSystemMXBean\\.getFreeSwapSpaceSize: 0");
}
}

View File

@ -905,8 +905,6 @@ jdk/jfr/event/os/TestThreadContextSwitches.java 8247776 windows-
# jdk_internal
jdk/internal/platform/docker/TestDockerMemoryMetrics.java 8250984 linux-5.4.0-1019-oracle
############################################################################
# jdk_jpackage

View File

@ -66,34 +66,42 @@ public class MetricsMemoryTester {
}
private static void testMemoryFailCount() {
long count = Metrics.systemMetrics().getMemoryFailCount();
long memAndSwapLimit = Metrics.systemMetrics().getMemoryAndSwapLimit();
long memLimit = Metrics.systemMetrics().getMemoryLimit();
// Allocate 512M of data
byte[][] bytes = new byte[64][];
boolean atLeastOneAllocationWorked = false;
for (int i = 0; i < 64; i++) {
try {
bytes[i] = new byte[8 * 1024 * 1024];
atLeastOneAllocationWorked = true;
// Break out as soon as we see an increase in failcount
// to avoid getting killed by the OOM killer.
if (Metrics.systemMetrics().getMemoryFailCount() > count) {
// We need swap to execute this test or will SEGV
if (memAndSwapLimit <= memLimit) {
System.out.println("No swap memory limits, test case skipped");
} else {
long count = Metrics.systemMetrics().getMemoryFailCount();
// Allocate 512M of data
byte[][] bytes = new byte[64][];
boolean atLeastOneAllocationWorked = false;
for (int i = 0; i < 64; i++) {
try {
bytes[i] = new byte[8 * 1024 * 1024];
atLeastOneAllocationWorked = true;
// Break out as soon as we see an increase in failcount
// to avoid getting killed by the OOM killer.
if (Metrics.systemMetrics().getMemoryFailCount() > count) {
break;
}
} catch (Error e) { // OOM error
break;
}
} catch (Error e) { // OOM error
break;
}
}
if (!atLeastOneAllocationWorked) {
System.out.println("Allocation failed immediately. Ignoring test!");
return;
}
// Be sure bytes allocations don't get optimized out
System.out.println("DEBUG: Bytes allocation length 1: " + bytes[0].length);
if (Metrics.systemMetrics().getMemoryFailCount() <= count) {
throw new RuntimeException("Memory fail count : new : ["
+ Metrics.systemMetrics().getMemoryFailCount() + "]"
+ ", old : [" + count + "]");
if (!atLeastOneAllocationWorked) {
System.out.println("Allocation failed immediately. Ignoring test!");
return;
}
// Be sure bytes allocations don't get optimized out
System.out.println("DEBUG: Bytes allocation length 1: " + bytes[0].length);
if (Metrics.systemMetrics().getMemoryFailCount() <= count) {
throw new RuntimeException("Memory fail count : new : ["
+ Metrics.systemMetrics().getMemoryFailCount() + "]"
+ ", old : [" + count + "]");
}
}
System.out.println("TEST PASSED!!!");
}
@ -131,10 +139,12 @@ public class MetricsMemoryTester {
private static void testMemoryAndSwapLimit(String memory, String memAndSwap) {
long expectedMem = getMemoryValue(memory);
long expectedMemAndSwap = getMemoryValue(memAndSwap);
long actualMemAndSwap = Metrics.systemMetrics().getMemoryAndSwapLimit();
if (expectedMem != Metrics.systemMetrics().getMemoryLimit()
|| expectedMemAndSwap != Metrics.systemMetrics().getMemoryAndSwapLimit()) {
System.err.println("Memory and swap limit not equal, expected : ["
|| (expectedMemAndSwap != actualMemAndSwap
&& expectedMem != actualMemAndSwap)) {
throw new RuntimeException("Memory and swap limit not equal, expected : ["
+ expectedMem + ", " + expectedMemAndSwap + "]"
+ ", got : [" + Metrics.systemMetrics().getMemoryLimit()
+ ", " + Metrics.systemMetrics().getMemoryAndSwapLimit() + "]");

View File

@ -293,29 +293,33 @@ public class MetricsTesterCgroupV1 implements CgroupMetricsTester {
}
// Memory and Swap
oldVal = metrics.getMemoryAndSwapFailCount();
newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.failcnt");
if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
fail(Controller.MEMORY, "memory.memsw.failcnt", oldVal, newVal);
}
oldVal = metrics.getMemoryAndSwapLimit();
newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.limit_in_bytes");
newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
fail(Controller.MEMORY, "memory.memsw.limit_in_bytes", oldVal, newVal);
}
// Skip swap tests if no swap is configured.
if (metrics.getMemoryAndSwapLimit() > metrics.getMemoryLimit()) {
oldVal = metrics.getMemoryAndSwapFailCount();
newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.failcnt");
if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
fail(Controller.MEMORY, "memory.memsw.failcnt", oldVal, newVal);
}
oldVal = metrics.getMemoryAndSwapMaxUsage();
newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.max_usage_in_bytes");
if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
fail(Controller.MEMORY, "memory.memsw.max_usage_in_bytes", oldVal, newVal);
}
oldVal = metrics.getMemoryAndSwapLimit();
newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.limit_in_bytes");
newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
fail(Controller.MEMORY, "memory.memsw.limit_in_bytes", oldVal, newVal);
}
oldVal = metrics.getMemoryAndSwapUsage();
newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.usage_in_bytes");
if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
fail(Controller.MEMORY, "memory.memsw.usage_in_bytes", oldVal, newVal);
oldVal = metrics.getMemoryAndSwapMaxUsage();
newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.max_usage_in_bytes");
if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
fail(Controller.MEMORY, "memory.memsw.max_usage_in_bytes", oldVal, newVal);
}
oldVal = metrics.getMemoryAndSwapUsage();
newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.usage_in_bytes");
if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
fail(Controller.MEMORY, "memory.memsw.usage_in_bytes", oldVal, newVal);
}
}
oldVal = metrics.getMemorySoftLimit();