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 pids_current() = 0;
|
||||||
virtual jlong memory_usage_in_bytes() = 0;
|
virtual jlong memory_usage_in_bytes() = 0;
|
||||||
virtual jlong memory_and_swap_limit_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_soft_limit_in_bytes() = 0;
|
||||||
virtual jlong memory_max_usage_in_bytes() = 0;
|
virtual jlong memory_max_usage_in_bytes() = 0;
|
||||||
virtual jlong rss_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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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;
|
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() {
|
jlong CgroupV1Subsystem::read_mem_swappiness() {
|
||||||
GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.swappiness",
|
GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.swappiness",
|
||||||
"Swappiness is: ", JULONG_FORMAT, JULONG_FORMAT, swappiness);
|
"Swappiness is: ", JULONG_FORMAT, JULONG_FORMAT, swappiness);
|
||||||
|
@ -76,6 +76,7 @@ class CgroupV1Subsystem: public CgroupSubsystem {
|
|||||||
public:
|
public:
|
||||||
jlong read_memory_limit_in_bytes();
|
jlong read_memory_limit_in_bytes();
|
||||||
jlong memory_and_swap_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_soft_limit_in_bytes();
|
||||||
jlong memory_usage_in_bytes();
|
jlong memory_usage_in_bytes();
|
||||||
jlong memory_max_usage_in_bytes();
|
jlong memory_max_usage_in_bytes();
|
||||||
|
@ -180,6 +180,16 @@ jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() {
|
|||||||
return swap_limit;
|
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() {
|
char* CgroupV2Subsystem::mem_swp_limit_val() {
|
||||||
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.max",
|
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.max",
|
||||||
"Memory and Swap Limit is: %s", "%1023s", mem_swp_limit_str, 1024);
|
"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_period();
|
||||||
int cpu_shares();
|
int cpu_shares();
|
||||||
jlong memory_and_swap_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_soft_limit_in_bytes();
|
||||||
jlong memory_usage_in_bytes();
|
jlong memory_usage_in_bytes();
|
||||||
jlong memory_max_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();
|
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() {
|
jlong OSContainer::memory_soft_limit_in_bytes() {
|
||||||
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
|
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
|
||||||
return cgroup_subsystem->memory_soft_limit_in_bytes();
|
return cgroup_subsystem->memory_soft_limit_in_bytes();
|
||||||
|
@ -52,6 +52,7 @@ class OSContainer: AllStatic {
|
|||||||
|
|
||||||
static jlong memory_limit_in_bytes();
|
static jlong memory_limit_in_bytes();
|
||||||
static jlong memory_and_swap_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_soft_limit_in_bytes();
|
||||||
static jlong memory_usage_in_bytes();
|
static jlong memory_usage_in_bytes();
|
||||||
static jlong memory_max_usage_in_bytes();
|
static jlong memory_max_usage_in_bytes();
|
||||||
|
@ -304,11 +304,7 @@ jlong os::total_swap_space() {
|
|||||||
return (jlong)(si.totalswap * si.mem_unit);
|
return (jlong)(si.totalswap * si.mem_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
jlong os::free_swap_space() {
|
static jlong host_free_swap() {
|
||||||
if (OSContainer::is_containerized()) {
|
|
||||||
// TODO add a good implementation
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
struct sysinfo si;
|
struct sysinfo si;
|
||||||
int ret = sysinfo(&si);
|
int ret = sysinfo(&si);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@ -316,6 +312,33 @@ jlong os::free_swap_space() {
|
|||||||
}
|
}
|
||||||
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() {
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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("500m", "" + 500*MB);
|
||||||
testMemory("1g", "" + 1024*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();
|
testProcessInfo();
|
||||||
|
|
||||||
testEnvironmentVariables();
|
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 {
|
private static void testProcessInfo() throws Exception {
|
||||||
Common.logNewTestCase("ProcessInfo");
|
Common.logNewTestCase("ProcessInfo");
|
||||||
DockerTestUtils.dockerRunJava(
|
DockerTestUtils.dockerRunJava(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user