Skip to content

Commit e47e9ec

Browse files
committedFeb 20, 2023
8300658: memory_and_swap_limit() reporting wrong values on systems with swapaccount=0
Reviewed-by: jsjolen, iklam
1 parent 7cf7e0a commit e47e9ec

File tree

5 files changed

+68
-17
lines changed

5 files changed

+68
-17
lines changed
 

‎src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp

+34-15
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,19 @@ jlong CgroupV1Subsystem::read_memory_limit_in_bytes() {
111111
}
112112
}
113113

114-
jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() {
114+
/* read_mem_swap
115+
*
116+
* Determine the memory and swap limit metric. Returns a positive limit value strictly
117+
* lower than the physical memory and swap limit iff there is a limit. Otherwise a
118+
* negative value is returned indicating the determined status.
119+
*
120+
* returns:
121+
* * A number > 0 if the limit is available and lower than a physical upper bound.
122+
* * OSCONTAINER_ERROR if the limit cannot be retrieved (i.e. not supported) or
123+
* * -1 if there isn't any limit in place (note: includes values which exceed a physical
124+
* upper bound)
125+
*/
126+
jlong CgroupV1Subsystem::read_mem_swap() {
115127
julong host_total_memsw;
116128
GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.memsw.limit_in_bytes",
117129
"Memory and Swap Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memswlimit);
@@ -126,29 +138,36 @@ jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() {
126138
if (hier_memswlimit >= host_total_memsw) {
127139
log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited");
128140
} else {
129-
jlong swappiness = read_mem_swappiness();
130-
if (swappiness == 0) {
131-
const char* matchmemline = "hierarchical_memory_limit";
132-
GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchmemline,
133-
"Hierarchical Memory Limit is : " JULONG_FORMAT, JULONG_FORMAT, hier_memlimit)
134-
log_trace(os, container)("Memory and Swap Limit has been reset to " JULONG_FORMAT " because swappiness is 0", hier_memlimit);
135-
return (jlong)hier_memlimit;
136-
}
137141
return (jlong)hier_memswlimit;
138142
}
139143
}
140144
return (jlong)-1;
141145
} else {
142-
jlong swappiness = read_mem_swappiness();
143-
if (swappiness == 0) {
144-
jlong memlimit = read_memory_limit_in_bytes();
145-
log_trace(os, container)("Memory and Swap Limit has been reset to " JULONG_FORMAT " because swappiness is 0", memlimit);
146-
return memlimit;
147-
}
148146
return (jlong)memswlimit;
149147
}
150148
}
151149

150+
jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() {
151+
jlong memory_swap = read_mem_swap();
152+
if (memory_swap == -1) {
153+
return memory_swap;
154+
}
155+
// If there is a swap limit, but swappiness == 0, reset the limit
156+
// to the memory limit. Do the same for cases where swap isn't
157+
// supported.
158+
jlong swappiness = read_mem_swappiness();
159+
if (swappiness == 0 || memory_swap == OSCONTAINER_ERROR) {
160+
jlong memlimit = read_memory_limit_in_bytes();
161+
if (memory_swap == OSCONTAINER_ERROR) {
162+
log_trace(os, container)("Memory and Swap Limit has been reset to " JLONG_FORMAT " because swap is not supported", memlimit);
163+
} else {
164+
log_trace(os, container)("Memory and Swap Limit has been reset to " JLONG_FORMAT " because swappiness is 0", memlimit);
165+
}
166+
return memlimit;
167+
}
168+
return memory_swap;
169+
}
170+
152171
jlong CgroupV1Subsystem::read_mem_swappiness() {
153172
GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.swappiness",
154173
"Swappiness is: ", JULONG_FORMAT, JULONG_FORMAT, swappiness);

‎src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ class CgroupV1Subsystem: public CgroupSubsystem {
114114
char * pids_max_val();
115115

116116
jlong read_mem_swappiness();
117+
jlong read_mem_swap();
117118

118119
public:
119120
CgroupV1Subsystem(CgroupV1Controller* cpuset,

‎src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ char* CgroupV2Subsystem::mem_soft_limit_val() {
152152
// without also setting a memory limit is not allowed.
153153
jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() {
154154
char* mem_swp_limit_str = mem_swp_limit_val();
155+
if (mem_swp_limit_str == nullptr) {
156+
// Some container tests rely on this trace logging to happen.
157+
log_trace(os, container)("Memory and Swap Limit is: %d", OSCONTAINER_ERROR);
158+
// swap disabled at kernel level, treat it as no swap
159+
return read_memory_limit_in_bytes();
160+
}
155161
jlong swap_limit = limit_from_str(mem_swp_limit_str);
156162
if (swap_limit >= 0) {
157163
jlong memory_limit = read_memory_limit_in_bytes();

‎test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java

+25
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ public static void main(String[] args) throws Exception {
7777
testMemorySoftLimit("1g", "1073741824");
7878
testMemorySwapLimitSanity();
7979

80+
testMemorySwapNotSupported("500m", "520m", "512000 k", "532480 k");
81+
8082
// Add extra 10 Mb to allocator limit, to be sure to cause OOM
8183
testOOM("256m", 256 + 10);
8284

@@ -154,6 +156,29 @@ private static void testMemorySoftLimit(String valueToSet, String expectedTraceV
154156
.shouldMatch("Memory Soft Limit.*" + expectedTraceValue);
155157
}
156158

159+
/*
160+
* Verifies that PrintContainerInfo prints the memory
161+
* limit - without swap - iff swap is disabled (e.g. via swapaccount=0). It must
162+
* not print 'not supported' for that value in that case. It'll always pass
163+
* on systems with swap accounting enabled.
164+
*/
165+
private static void testMemorySwapNotSupported(String valueToSet, String swapToSet, String expectedMem, String expectedSwap)
166+
throws Exception {
167+
Common.logNewTestCase("memory swap not supported: " + valueToSet);
168+
169+
DockerRunOptions opts = Common.newOpts(imageName, "PrintContainerInfo");
170+
Common.addWhiteBoxOpts(opts);
171+
opts.addDockerOpts("--memory=" + valueToSet);
172+
opts.addDockerOpts("--memory-swap=" + swapToSet);
173+
174+
Common.run(opts)
175+
.shouldMatch("memory_limit_in_bytes:.*" + expectedMem)
176+
.shouldNotMatch("memory_and_swap_limit_in_bytes:.*not supported")
177+
// On systems with swapaccount=0 this returns the memory limit.
178+
// On systems with swapaccount=1 this returns the set memory+swap value.
179+
.shouldMatch("memory_and_swap_limit_in_bytes:.*(" + expectedMem + "|" + expectedSwap + ")");
180+
}
181+
157182
/*
158183
* This test verifies that no confusingly large positive numbers get printed on
159184
* systems with swapaccount=0 kernel option. On some systems -2 were converted

‎test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ private static void testMemoryLimitWithSwappiness(String dockerMemLimit, String
8585
// capabilities or the cgroup is not mounted. Memory limited without swap."
8686
// we only have 'Memory and Swap Limit is: -2' in the output
8787
try {
88-
if (out.getOutput().contains("memory_and_swap_limit_in_bytes: not supported")) {
89-
System.out.println("memory_and_swap_limit_in_bytes not supported, avoiding Memory and Swap Limit check");
88+
if (out.getOutput().contains("Memory and Swap Limit is: -2")) {
89+
System.out.println("System doesn't seem to allow swap, avoiding Memory and Swap Limit check");
9090
} else {
9191
out.shouldContain("Memory and Swap Limit is: " + expectedReadLimit)
9292
.shouldContain(

0 commit comments

Comments
 (0)
Please sign in to comment.