Skip to content

Commit 0845b39

Browse files
committed
8296796: Provide clean, platform-agnostic interface to C-heap trimming
Reviewed-by: dholmes, rkennke
1 parent c50a904 commit 0845b39

File tree

10 files changed

+107
-52
lines changed

10 files changed

+107
-52
lines changed

src/hotspot/os/aix/os_aix.inline.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,8 @@ inline bool os::must_commit_stack_guard_pages() {
5252
inline void os::map_stack_shadow_pages(address sp) {
5353
}
5454

55+
// stubbed-out trim-native support
56+
inline bool os::can_trim_native_heap() { return false; }
57+
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
58+
5559
#endif // OS_AIX_OS_AIX_INLINE_HPP

src/hotspot/os/bsd/os_bsd.inline.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,8 @@ inline bool os::must_commit_stack_guard_pages() {
5555
inline void os::map_stack_shadow_pages(address sp) {
5656
}
5757

58+
// stubbed-out trim-native support
59+
inline bool os::can_trim_native_heap() { return false; }
60+
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
61+
5862
#endif // OS_BSD_OS_BSD_INLINE_HPP

src/hotspot/os/linux/os_linux.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5331,3 +5331,32 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {
53315331
st->cr();
53325332
}
53335333
}
5334+
5335+
bool os::trim_native_heap(os::size_change_t* rss_change) {
5336+
#ifdef __GLIBC__
5337+
os::Linux::meminfo_t info1;
5338+
os::Linux::meminfo_t info2;
5339+
5340+
bool have_info1 = rss_change != nullptr &&
5341+
os::Linux::query_process_memory_info(&info1);
5342+
::malloc_trim(0);
5343+
bool have_info2 = rss_change != nullptr && have_info1 &&
5344+
os::Linux::query_process_memory_info(&info2);
5345+
ssize_t delta = (ssize_t) -1;
5346+
if (rss_change != nullptr) {
5347+
if (have_info1 && have_info2 &&
5348+
info1.vmrss != -1 && info2.vmrss != -1 &&
5349+
info1.vmswap != -1 && info2.vmswap != -1) {
5350+
// Note: query_process_memory_info returns values in K
5351+
rss_change->before = (info1.vmrss + info1.vmswap) * K;
5352+
rss_change->after = (info2.vmrss + info2.vmswap) * K;
5353+
} else {
5354+
rss_change->after = rss_change->before = SIZE_MAX;
5355+
}
5356+
}
5357+
5358+
return true;
5359+
#else
5360+
return false; // musl
5361+
#endif
5362+
}

src/hotspot/os/linux/os_linux.inline.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,13 @@ inline bool os::must_commit_stack_guard_pages() {
4747
inline void os::map_stack_shadow_pages(address sp) {
4848
}
4949

50+
// Trim-native support
51+
inline bool os::can_trim_native_heap() {
52+
#ifdef __GLIBC__
53+
return true;
54+
#else
55+
return false; // musl
56+
#endif
57+
}
58+
5059
#endif // OS_LINUX_OS_LINUX_INLINE_HPP
Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021 SAP SE. All rights reserved.
2+
* Copyright (c) 2022 SAP SE. All rights reserved.
33
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -24,57 +24,29 @@
2424
*/
2525

2626
#include "precompiled.hpp"
27-
#include "logging/log.hpp"
28-
#include "os_linux.hpp"
29-
#include "runtime/os.hpp"
27+
#include "runtime/os.inline.hpp"
28+
#include "trimCHeapDCmd.hpp"
3029
#include "utilities/debug.hpp"
30+
#include "utilities/globalDefinitions.hpp"
3131
#include "utilities/ostream.hpp"
32-
#include "trimCHeapDCmd.hpp"
3332

3433
#include <malloc.h>
3534

3635
void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) {
37-
#ifdef __GLIBC__
38-
stringStream ss_report(1024); // Note: before calling trim
39-
40-
os::Linux::meminfo_t info1;
41-
os::Linux::meminfo_t info2;
42-
// Query memory before...
43-
bool have_info1 = os::Linux::query_process_memory_info(&info1);
44-
45-
_output->print_cr("Attempting trim...");
46-
::malloc_trim(0);
47-
_output->print_cr("Done.");
48-
49-
// ...and after trim.
50-
bool have_info2 = os::Linux::query_process_memory_info(&info2);
51-
52-
// Print report both to output stream as well to UL
53-
bool wrote_something = false;
54-
if (have_info1 && have_info2) {
55-
if (info1.vmsize != -1 && info2.vmsize != -1) {
56-
ss_report.print_cr("Virtual size before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)",
57-
info1.vmsize, info2.vmsize, (info2.vmsize - info1.vmsize));
58-
wrote_something = true;
59-
}
60-
if (info1.vmrss != -1 && info2.vmrss != -1) {
61-
ss_report.print_cr("RSS before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)",
62-
info1.vmrss, info2.vmrss, (info2.vmrss - info1.vmrss));
63-
wrote_something = true;
64-
}
65-
if (info1.vmswap != -1 && info2.vmswap != -1) {
66-
ss_report.print_cr("Swap before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)",
67-
info1.vmswap, info2.vmswap, (info2.vmswap - info1.vmswap));
68-
wrote_something = true;
36+
if (os::can_trim_native_heap()) {
37+
os::size_change_t sc;
38+
if (os::trim_native_heap(&sc)) {
39+
_output->print("Trim native heap: ");
40+
if (sc.after != SIZE_MAX) {
41+
const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before);
42+
const char sign = sc.after < sc.before ? '-' : '+';
43+
_output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")",
44+
PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta));
45+
} else {
46+
_output->print_cr("(no details available).");
47+
}
6948
}
49+
} else {
50+
_output->print_cr("Not available.");
7051
}
71-
if (!wrote_something) {
72-
ss_report.print_raw("No details available.");
73-
}
74-
75-
_output->print_raw(ss_report.base());
76-
log_info(os)("malloc_trim:\n%s", ss_report.base());
77-
#else
78-
_output->print_cr("Not available.");
79-
#endif
8052
}

src/hotspot/os/windows/os_windows.inline.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,8 @@ inline void PlatformMonitor::notify_all() {
9898
WakeAllConditionVariable(&_cond);
9999
}
100100

101+
// stubbed-out trim-native support
102+
inline bool os::can_trim_native_heap() { return false; }
103+
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
104+
101105
#endif // OS_WINDOWS_OS_WINDOWS_INLINE_HPP

src/hotspot/share/runtime/os.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,15 @@ class os: AllStatic {
440440
static bool uncommit_memory(char* addr, size_t bytes, bool executable = false);
441441
static bool release_memory(char* addr, size_t bytes);
442442

443+
// Does the platform support trimming the native heap?
444+
static bool can_trim_native_heap();
445+
446+
// Trim the C-heap. Optionally returns working set size change (RSS+Swap) in *rss_change.
447+
// Note: If trimming succeeded but no size change information could be obtained,
448+
// rss_change.after will contain SIZE_MAX upon return.
449+
struct size_change_t { size_t before; size_t after; };
450+
static bool trim_native_heap(size_change_t* rss_change = nullptr);
451+
443452
// A diagnostic function to print memory mappings in the given range.
444453
static void print_memory_mappings(char* addr, size_t bytes, outputStream* st);
445454
// Prints all mappings

src/hotspot/share/utilities/globalDefinitions.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,9 @@ inline T byte_size_in_proper_unit(T s) {
372372
}
373373
}
374374

375+
#define PROPERFMT SIZE_FORMAT "%s"
376+
#define PROPERFMTARGS(s) byte_size_in_proper_unit(s), proper_unit_for_byte_size(s)
377+
375378
inline const char* exact_unit_for_byte_size(size_t s) {
376379
#ifdef _LP64
377380
if (s >= G && (s % G) == 0) {

test/hotspot/gtest/runtime/test_os.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include "precompiled.hpp"
2525
#include "memory/allocation.hpp"
2626
#include "memory/resourceArea.hpp"
27-
#include "runtime/os.hpp"
27+
#include "runtime/os.inline.hpp"
2828
#include "runtime/thread.hpp"
2929
#include "services/memTracker.hpp"
3030
#include "utilities/globalDefinitions.hpp"
@@ -890,3 +890,27 @@ TEST_VM(os, is_first_C_frame) {
890890
EXPECT_FALSE(os::is_first_C_frame(&cur_frame));
891891
#endif // _WIN32
892892
}
893+
894+
#ifdef __GLIBC__
895+
TEST_VM(os, trim_native_heap) {
896+
EXPECT_TRUE(os::can_trim_native_heap());
897+
os::size_change_t sc;
898+
sc.before = sc.after = (size_t)-1;
899+
EXPECT_TRUE(os::trim_native_heap(&sc));
900+
tty->print_cr(SIZE_FORMAT "->" SIZE_FORMAT, sc.before, sc.after);
901+
// Regardless of whether we freed memory, both before and after
902+
// should be somewhat believable numbers (RSS).
903+
const size_t min = 5 * M;
904+
const size_t max = LP64_ONLY(20 * G) NOT_LP64(3 * G);
905+
ASSERT_LE(min, sc.before);
906+
ASSERT_GT(max, sc.before);
907+
ASSERT_LE(min, sc.after);
908+
ASSERT_GT(max, sc.after);
909+
// Should also work
910+
EXPECT_TRUE(os::trim_native_heap());
911+
}
912+
#else
913+
TEST_VM(os, trim_native_heap) {
914+
EXPECT_FALSE(os::can_trim_native_heap());
915+
}
916+
#endif // __GLIBC__

test/hotspot/jtreg/serviceability/dcmd/vm/TrimLibcHeapTest.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
* @test
3232
* @summary Test of diagnostic command VM.trim_libc_heap
3333
* @library /test/lib
34-
* @requires os.family == "linux"
34+
* @requires (os.family=="linux") & !vm.musl
3535
* @modules java.base/jdk.internal.misc
3636
* java.compiler
3737
* java.management
@@ -42,10 +42,7 @@ public class TrimLibcHeapTest {
4242
public void run(CommandExecutor executor) {
4343
OutputAnalyzer output = executor.execute("System.trim_native_heap");
4444
output.reportDiagnosticSummary();
45-
output.shouldMatch("(Done|Not available)"); // Not available could happen on Linux + non-glibc (eg. muslc)
46-
if (output.firstMatch("Done") != null) {
47-
output.shouldMatch("(Virtual size before|RSS before|Swap before|No details available)");
48-
}
45+
output.shouldMatch(".*Trim native heap: RSS\\+Swap: \\d+[BKM]->\\d+[BKM].*");
4946
}
5047

5148
@Test

0 commit comments

Comments
 (0)