8325139: JFR SwapSpace event - add free swap space information on Linux when running in a container environment
Reviewed-by: lucy, sgehwolf
This commit is contained in:
parent
c00c939f99
commit
3d106cb091
@ -264,6 +264,7 @@ class CgroupSubsystem: public CHeapObj<mtInternal> {
|
||||
virtual jlong pids_current() = 0;
|
||||
virtual jlong memory_usage_in_bytes() = 0;
|
||||
virtual jlong memory_and_swap_limit_in_bytes() = 0;
|
||||
virtual jlong memory_and_swap_usage_in_bytes() = 0;
|
||||
virtual jlong memory_soft_limit_in_bytes() = 0;
|
||||
virtual jlong memory_max_usage_in_bytes() = 0;
|
||||
virtual jlong rss_usage_in_bytes() = 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -168,6 +168,20 @@ jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() {
|
||||
return memory_swap;
|
||||
}
|
||||
|
||||
jlong CgroupV1Subsystem::memory_and_swap_usage_in_bytes() {
|
||||
jlong memory_sw_limit = memory_and_swap_limit_in_bytes();
|
||||
jlong memory_limit = CgroupSubsystem::memory_limit_in_bytes();
|
||||
if (memory_sw_limit > 0 && memory_limit > 0) {
|
||||
jlong delta_swap = memory_sw_limit - memory_limit;
|
||||
if (delta_swap > 0) {
|
||||
GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.memsw.usage_in_bytes",
|
||||
"mem swap usage is: ", JULONG_FORMAT, JULONG_FORMAT, memory_swap_usage);
|
||||
return (jlong)memory_swap_usage;
|
||||
}
|
||||
}
|
||||
return memory_usage_in_bytes();
|
||||
}
|
||||
|
||||
jlong CgroupV1Subsystem::read_mem_swappiness() {
|
||||
GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.swappiness",
|
||||
"Swappiness is: ", JULONG_FORMAT, JULONG_FORMAT, swappiness);
|
||||
|
@ -76,6 +76,7 @@ class CgroupV1Subsystem: public CgroupSubsystem {
|
||||
public:
|
||||
jlong read_memory_limit_in_bytes();
|
||||
jlong memory_and_swap_limit_in_bytes();
|
||||
jlong memory_and_swap_usage_in_bytes();
|
||||
jlong memory_soft_limit_in_bytes();
|
||||
jlong memory_usage_in_bytes();
|
||||
jlong memory_max_usage_in_bytes();
|
||||
|
@ -180,6 +180,16 @@ jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() {
|
||||
return swap_limit;
|
||||
}
|
||||
|
||||
jlong CgroupV2Subsystem::memory_and_swap_usage_in_bytes() {
|
||||
jlong memory_usage = memory_usage_in_bytes();
|
||||
if (memory_usage >= 0) {
|
||||
char* mem_swp_current_str = mem_swp_current_val();
|
||||
jlong swap_current = limit_from_str(mem_swp_current_str);
|
||||
return memory_usage + (swap_current >= 0 ? swap_current : 0);
|
||||
}
|
||||
return memory_usage; // not supported or unlimited case
|
||||
}
|
||||
|
||||
char* CgroupV2Subsystem::mem_swp_limit_val() {
|
||||
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.max",
|
||||
"Memory and Swap Limit is: %s", "%1023s", mem_swp_limit_str, 1024);
|
||||
|
@ -75,6 +75,7 @@ class CgroupV2Subsystem: public CgroupSubsystem {
|
||||
int cpu_period();
|
||||
int cpu_shares();
|
||||
jlong memory_and_swap_limit_in_bytes();
|
||||
jlong memory_and_swap_usage_in_bytes();
|
||||
jlong memory_soft_limit_in_bytes();
|
||||
jlong memory_usage_in_bytes();
|
||||
jlong memory_max_usage_in_bytes();
|
||||
|
@ -77,6 +77,11 @@ jlong OSContainer::memory_and_swap_limit_in_bytes() {
|
||||
return cgroup_subsystem->memory_and_swap_limit_in_bytes();
|
||||
}
|
||||
|
||||
jlong OSContainer::memory_and_swap_usage_in_bytes() {
|
||||
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
|
||||
return cgroup_subsystem->memory_and_swap_usage_in_bytes();
|
||||
}
|
||||
|
||||
jlong OSContainer::memory_soft_limit_in_bytes() {
|
||||
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
|
||||
return cgroup_subsystem->memory_soft_limit_in_bytes();
|
||||
|
@ -52,6 +52,7 @@ class OSContainer: AllStatic {
|
||||
|
||||
static jlong memory_limit_in_bytes();
|
||||
static jlong memory_and_swap_limit_in_bytes();
|
||||
static jlong memory_and_swap_usage_in_bytes();
|
||||
static jlong memory_soft_limit_in_bytes();
|
||||
static jlong memory_usage_in_bytes();
|
||||
static jlong memory_max_usage_in_bytes();
|
||||
|
@ -304,18 +304,41 @@ jlong os::total_swap_space() {
|
||||
return (jlong)(si.totalswap * si.mem_unit);
|
||||
}
|
||||
|
||||
jlong os::free_swap_space() {
|
||||
if (OSContainer::is_containerized()) {
|
||||
// TODO add a good implementation
|
||||
static jlong host_free_swap() {
|
||||
struct sysinfo si;
|
||||
int ret = sysinfo(&si);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
} else {
|
||||
struct sysinfo si;
|
||||
int ret = sysinfo(&si);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
return (jlong)(si.freeswap * si.mem_unit);
|
||||
}
|
||||
return (jlong)(si.freeswap * si.mem_unit);
|
||||
}
|
||||
|
||||
jlong os::free_swap_space() {
|
||||
jlong host_free_swap_val = host_free_swap();
|
||||
if (OSContainer::is_containerized()) {
|
||||
jlong mem_swap_limit = OSContainer::memory_and_swap_limit_in_bytes();
|
||||
jlong mem_limit = OSContainer::memory_limit_in_bytes();
|
||||
if (mem_swap_limit >= 0 && mem_limit >= 0) {
|
||||
jlong delta_limit = mem_swap_limit - mem_limit;
|
||||
if (delta_limit <= 0) {
|
||||
return 0;
|
||||
}
|
||||
jlong mem_swap_usage = OSContainer::memory_and_swap_usage_in_bytes();
|
||||
jlong mem_usage = OSContainer::memory_usage_in_bytes();
|
||||
if (mem_swap_usage > 0 && mem_usage > 0) {
|
||||
jlong delta_usage = mem_swap_usage - mem_usage;
|
||||
if (delta_usage >= 0) {
|
||||
jlong free_swap = delta_limit - delta_usage;
|
||||
return free_swap >= 0 ? free_swap : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// unlimited or not supported. Fall through to return host value
|
||||
log_trace(os,container)("os::free_swap_space: container_swap_limit=" JLONG_FORMAT
|
||||
" container_mem_limit=" JLONG_FORMAT " returning host value: " JLONG_FORMAT,
|
||||
mem_swap_limit, mem_limit, host_free_swap_val);
|
||||
}
|
||||
return host_free_swap_val;
|
||||
}
|
||||
|
||||
julong os::physical_memory() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -68,6 +68,10 @@ public class TestJFREvents {
|
||||
testMemory("500m", "" + 500*MB);
|
||||
testMemory("1g", "" + 1024*MB);
|
||||
|
||||
// see https://docs.docker.com/config/containers/resource_constraints/
|
||||
testSwapMemory("200m", "200m", "" + 0*MB, "" + 0*MB);
|
||||
testSwapMemory("200m", "300m", "" + 100*MB, "" + 100*MB);
|
||||
|
||||
testProcessInfo();
|
||||
|
||||
testEnvironmentVariables();
|
||||
@ -211,6 +215,37 @@ public class TestJFREvents {
|
||||
}
|
||||
|
||||
|
||||
private static void testSwapMemory(String memValueToSet, String swapValueToSet, String expectedTotalValue, String expectedFreeValue) throws Exception {
|
||||
Common.logNewTestCase("Memory: --memory = " + memValueToSet + " --memory-swap = " + swapValueToSet);
|
||||
OutputAnalyzer out = DockerTestUtils.dockerRunJava(
|
||||
commonDockerOpts()
|
||||
.addDockerOpts("--memory=" + memValueToSet)
|
||||
.addDockerOpts("--memory-swap=" + swapValueToSet)
|
||||
.addClassOptions("jdk.SwapSpace"));
|
||||
out.shouldHaveExitValue(0)
|
||||
.shouldContain("totalSize = " + expectedTotalValue)
|
||||
.shouldContain("freeSize = ");
|
||||
List<String> ls = out.asLinesWithoutVMWarnings();
|
||||
for (String cur : ls) {
|
||||
int idx = cur.indexOf("freeSize = ");
|
||||
if (idx != -1) {
|
||||
int startNbr = idx+11;
|
||||
int endNbr = cur.indexOf(' ', startNbr);
|
||||
if (endNbr == -1) endNbr = cur.length();
|
||||
String freeSizeStr = cur.substring(startNbr, endNbr);
|
||||
long freeval = Long.parseLong(freeSizeStr);
|
||||
long totalval = Long.parseLong(expectedTotalValue);
|
||||
if (0 <= freeval && freeval <= totalval) {
|
||||
System.out.println("Found freeSize value " + freeval + " is fine");
|
||||
} else {
|
||||
System.out.println("Found freeSize value " + freeval + " is bad");
|
||||
throw new Exception("Found free size value is bad");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void testProcessInfo() throws Exception {
|
||||
Common.logNewTestCase("ProcessInfo");
|
||||
DockerTestUtils.dockerRunJava(
|
||||
|
Loading…
Reference in New Issue
Block a user