8296671: [JFR] jdk.ContainerConfiguration event should include host total memory

Reviewed-by: egahlin
This commit is contained in:
Severin Gehwolf 2022-11-24 10:05:18 +00:00
parent 8b7397064b
commit 3c4d5204ff
7 changed files with 48 additions and 5 deletions

View File

@ -63,6 +63,7 @@
#ifdef LINUX
#include "osContainer_linux.hpp"
#include "os_linux.hpp"
#endif
#define NO_TRANSITION(result_type, header) extern "C" { result_type JNICALL header {
@ -391,3 +392,13 @@ JVM_ENTRY_NO_ENV(jboolean, jfr_is_containerized(JNIEnv* env, jobject jvm))
return false;
#endif
JVM_END
JVM_ENTRY_NO_ENV(jlong, jfr_host_total_memory(JNIEnv* env, jobject jvm))
#ifdef LINUX
// We want the host memory, not the container limit.
// os::physical_memory() would return the container limit.
return os::Linux::physical_memory();
#else
return os::physical_memory();
#endif
JVM_END

View File

@ -160,6 +160,8 @@ jboolean JNICALL jfr_is_class_instrumented(JNIEnv* env, jobject jvm, jclass claz
jboolean JNICALL jfr_is_containerized(JNIEnv* env, jobject jvm);
jlong JNICALL jfr_host_total_memory(JNIEnv* env, jobject jvm);
#ifdef __cplusplus
}
#endif

View File

@ -94,7 +94,8 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
(char*)"getTypeId", (char*)"(Ljava/lang/String;)J", (void*)jfr_get_type_id_from_string,
(char*)"isExcluded", (char*)"(Ljava/lang/Class;)Z", (void*)jfr_is_class_excluded,
(char*)"isInstrumented", (char*)"(Ljava/lang/Class;)Z", (void*) jfr_is_class_instrumented,
(char*)"isContainerized", (char*)"()Z", (void*) jfr_is_containerized
(char*)"isContainerized", (char*)"()Z", (void*) jfr_is_containerized,
(char*)"hostTotalMemory", (char*)"()J", (void*) jfr_host_total_memory
};
const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod);

View File

@ -75,4 +75,9 @@ public final class ContainerConfigurationEvent extends AbstractJDKEvent {
@Description("Maximum amount of physical memory and swap space, in bytes, that can be allocated in the container")
@DataAmount
public long swapMemoryLimit;
@Label("Container Host Total Memory")
@Description("Total memory of the host running the container")
@DataAmount
public long hostTotalMemory;
}

View File

@ -635,4 +635,10 @@ public final class JVM {
* can't be emitted anyway.
*/
public native boolean isContainerized();
/**
* Returns the total amount of memory of the host system whether or not this
* JVM runs in a container.
*/
public native long hostTotalMemory();
}

View File

@ -221,6 +221,7 @@ public final class JDKEvents {
t.memorySoftLimit = containerMetrics.getMemorySoftLimit();
t.memoryLimit = containerMetrics.getMemoryLimit();
t.swapMemoryLimit = containerMetrics.getMemoryAndSwapLimit();
t.hostTotalMemory = JVM.getJVM().hostTotalMemory();
t.commit();
}
}

View File

@ -51,6 +51,7 @@ public class TestJFREvents {
private static final String TEST_ENV_VARIABLE = "UNIQUE_VARIABLE_ABC592903XYZ";
private static final String TEST_ENV_VALUE = "unique_value_abc592903xyz";
private static final int availableCPUs = Runtime.getRuntime().availableProcessors();
private static final int UNKNOWN = -100;
public static void main(String[] args) throws Exception {
System.out.println("Test Environment: detected availableCPUs = " + availableCPUs);
@ -82,18 +83,32 @@ public class TestJFREvents {
}
private static void containerInfoTestCase() throws Exception {
long hostTotalMemory = getHostTotalMemory();
System.out.println("Debug: Host total memory is " + hostTotalMemory);
// Leave one CPU for system and tools, otherwise this test may be unstable.
// Try the memory sizes that were verified by testMemory tests before.
int maxNrOfAvailableCpus = availableCPUs - 1;
for (int cpus = 1; cpus < maxNrOfAvailableCpus; cpus *= 2) {
for (int mem : new int[]{ 200, 500, 1024 }) {
testContainerInfo(cpus, mem);
testContainerInfo(cpus, mem, hostTotalMemory);
}
}
}
private static void testContainerInfo(int expectedCPUs, int expectedMemoryMB) throws Exception {
Common.logNewTestCase("ContainerInfo: --cpus = " + expectedCPUs + " --memory=" + expectedMemoryMB + "m");
private static long getHostTotalMemory() throws Exception {
DockerRunOptions opts = Common.newOpts(imageName);
String hostMem = Common.run(opts).firstMatch("total physical memory: (\\d+)", 1);
try {
return Long.parseLong(hostMem);
} catch (NumberFormatException e) {
System.out.println("Could not parse total physical memory '" + hostMem + "' returning " + UNKNOWN);
return UNKNOWN;
}
}
private static void testContainerInfo(int expectedCPUs, int expectedMemoryMB, long hostTotalMemory) throws Exception {
Common.logNewTestCase("ContainerInfo: --cpus=" + expectedCPUs + " --memory=" + expectedMemoryMB + "m");
String eventName = "jdk.ContainerConfiguration";
long expectedSlicePeriod = 100000; // default slice period
long expectedMemoryLimit = expectedMemoryMB * 1024 * 1024;
@ -102,6 +117,7 @@ public class TestJFREvents {
String cpuQuotaFld = "cpuQuota";
String cpuSlicePeriodFld = "cpuSlicePeriod";
String memoryLimitFld = "memoryLimit";
String totalMem = "hostTotalMemory";
DockerTestUtils.dockerRunJava(
commonDockerOpts()
@ -112,7 +128,8 @@ public class TestJFREvents {
.shouldContain(cpuCountFld + " = " + expectedCPUs)
.shouldContain(cpuSlicePeriodFld + " = " + expectedSlicePeriod)
.shouldContain(cpuQuotaFld + " = " + expectedCPUs * expectedSlicePeriod)
.shouldContain(memoryLimitFld + " = " + expectedMemoryLimit);
.shouldContain(memoryLimitFld + " = " + expectedMemoryLimit)
.shouldContain(totalMem + " = " + hostTotalMemory);
}
private static void testCpuUsage() throws Exception {